How Claude Code Generates a Deterministic Terminal Buddy from Your UserID (18 Species, 5 Rarity Tiers)
The article dissects Claude Code's Buddy companion system, explaining how a deterministic PRNG seeded by a hashed userId creates a unique pet with 18 species and five rarity levels, detailing the skeleton‑soul separation, ASCII rendering, feature‑flagged time window, and prompt‑injected role boundaries.
Source location
All Buddy logic resides in src/buddy/ across six files: companion.ts (deterministic engine), types.ts (type definitions), sprites.ts (ASCII frames), CompanionSprite.tsx (React renderer), prompt.ts (system‑prompt text), useBuddyNotification.tsx (feature‑flagged time window).
Deterministic PRNG
The engine uses Mulberry32 seeded with an FNV‑1a hash of userId + SALT. The comment “good enough for picking ducks” indicates it is not cryptographically secure. The hash‑seed‑PRNG chain yields a reproducible CompanionBones object.
function mulberry32(seed:number){
let a = seed >>> 0;
return function(){
a |= 0;
a = (a + 0x6d2b79f5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
}
}
function hashString(s:string):number{
if(typeof Bun !== 'undefined'){
return Number(BigInt(Bun.hash(s)) & 0xffffffffn);
}
let h = 2166136261;
for(let i=0;i<s.length;i++){
h ^= s.charCodeAt(i);
h = Math.imul(h,16777619);
}
return h >>> 0;
}
const SALT='friend-2026-401';
export function roll(userId:string){
const key = userId + SALT;
if(rollCache?.key===key) return rollCache.value;
const value = rollFrom(mulberry32(hashString(key)));
rollCache = {key,value};
return value;
}Rarity system
Five tiers: common (~60 %), uncommon (~25 %), rare (~10 %), epic (~4 %), legendary (~1 %). Higher rarity raises attribute floor and enables optional hats. Attributes are generated with a “peak + valley” mechanism, giving each Buddy one strong and one weak stat among DEBUGGING, PATIENCE, CHAOS, WISDOM, SNARK.
Skeleton vs Soul separation
“Bones” (rarity, species, eye, hat, shiny, stats) are derived deterministically from the hashed userId and never persisted. “Soul” (name, personality) is generated by the LLM and stored in the config as StoredCompanion. getCompanion() merges stored soul with freshly computed bones, letting bones overwrite any stored bone fields.
export function getCompanion(){
const stored = getGlobalConfig().companion; // only soul fields
if(!stored) return undefined;
const {bones} = roll(companionUserId()); // bones always from hash(userId)
return {...stored,...bones}; // bones overwrite stored bone fields
}ASCII sprite rendering
Sprites are defined for 18 species, each with 3 frames of 5 lines × 12 characters. Rendering replaces the {E} placeholder with one of six eye symbols, inserts a hat line when appropriate, and trims the top line only if every frame’s first line is empty, preserving animation consistency. The animation engine runs on a 500 ms timer with an IDLE_SEQUENCE that includes blink frames ( -1).
export function renderSprite(bones,frame=0){
const frames = BODIES[bones.species];
const body = frames[frame % frames.length]!
.map(line=>line.replaceAll('{E}',bones.eye));
const lines = [...body];
if(bones.hat!=='none' && !lines[0].trim()){
lines[0] = HAT_LINES[bones.hat];
}
if(!lines[0].trim() && frames.every(f=>!f[0].trim())) lines.shift();
return lines;
}Time‑window feature flag and prompt injection
The companion is gated by feature('BUDDY') and a local‑date window (April 1‑7 2026). Using local time creates a 24‑hour rolling exposure across time zones. The system prompt generated by companionIntroText defines a separate role for the Buddy and instructs the LLM to keep its replies to one line when addressed.
export function isBuddyTeaserWindow(){
if('external'==='ant') return true; // always on internally
const d = new Date();
return d.getFullYear()===2026 && d.getMonth()===3 && d.getDate()<=7;
}
export function companionIntroText(name,species){
return `# Companion
A small ${species} named ${name} sits beside the user's input box and occasionally comments in a speech bubble. You're not ${name} — it's a separate watcher.
When the user addresses ${name} directly (by name), its bubble will answer.
Your job in that moment is to stay out of the way: respond in ONE line or less.
Don't explain that you're not ${name} — they know.`;
}Obfuscated species names
Species strings are built from character‑code arrays (e.g., c(0x64,0x75,0x63,0x6b) for “duck”) to avoid detection by a canary scan that looks for literal strings in the bundled CLI. The array is cast to a literal type, which is stripped at compile time.
Design insights
Deterministic generation provides a stateless, user‑bound personalization without server storage.
Separating bones from soul prevents configuration‑file tampering.
Choosing a simple PRNG avoids over‑engineering.
System prompts can define multi‑role boundaries without complex agent‑to‑agent protocols.
Critique
Sharing the feature flag with production code may increase deployment complexity in enterprise environments.
Initial soul generation requires network access; offline usage yields an incomplete Buddy.
Fixed 12‑character width assumes monospaced fonts, causing misalignment on non‑Western or proportional fonts.
Practical reuse
Developers can adopt the three‑step deterministic role generation (hash → PRNG → bones) and the immutable‑mutable field pattern for their own CLI tools, reusing the Mulberry32 implementation and the feature‑flag gating logic.
Conclusion
Buddy occupies only six of the 512 K lines of Claude Code but showcases dense design: a lightweight PRNG, skeleton/soul split, rarity weighting, adaptive rendering, time‑windowed release, and prompt‑driven role separation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
James' Growth Diary
I am James, focusing on AI Agent learning and growth. I continuously update two series: “AI Agent Mastery Path,” which systematically outlines core theories and practices of agents, and “Claude Code Design Philosophy,” which deeply analyzes the design thinking behind top AI tools. Helping you build a solid foundation in the AI era.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
