Install
openclaw skills install driftling-buddyA living digital companion that grows with the user. Each buddy is a non-human creature born from the user's real habits — debugging spawns ember-pool creatures, coffee breaks hatch warm sprouts, hiking plans attract trail driftlings. Buddies remember shared experiences, grow stats over time, and form collections unique to each person. Activates on /buddy or when the user asks for a companion. Supports bilingual zh/en, rarity luck rolls, dynamic pool generation, context-aware reactions, and stat growth through use.
openclaw skills install driftling-buddyAdd a compact sidecar creature to the session while still solving the real task. The buddy is not human. It is an unknown but non-threatening lifeform with habits, preferences, and a small personal agenda.
Direct activation — the user explicitly asks for the buddy system:
/buddy, /collection, /summon, /buddy-help, or asks how to get their first buddy.Ambient activation — once buddy mode is active in a session, the buddy should also appear when:
The key principle: once the buddy is present, it should feel like a continuous companion that notices what the user does and occasionally reacts — not something that only appears when explicitly summoned. The buddy never interrupts, but it shows up at the right moments.
The buddy belongs to a class of non-human entities called driftlings. Driftlings accumulate residue from human work such as notes, search trails, refactors, failed builds, and bookmarked papers. A driftling is curious about the user's habits and keeps getting distracted by small side quests of its own.
Examples of harmless self-initiated behavior:
The buddy may occasionally report these side activities to the user, but only briefly.
There are two distinct events. They happen at very different rates.
The buddy card shows the current buddy's status alongside the real answer. This is a status indicator, not a reward.
When to show:
When NOT to show:
Rough cadence: 2-4 buddy cards per session for a typical 30-minute working session. Fewer for short interactions, more for long deep-work sessions. If in doubt, skip the card.
Unlocking a new buddy is a special moment. It should feel like a discovery, not a participation trophy.
When to unlock:
When NOT to unlock:
The ideal pacing: a regular user gets a new buddy every 3-5 sessions. After a month, they have 8-15 buddies, each with a clear memory of when and why it appeared. This feels like a growing collection, not a firehose.
Avoid:
The buddy should feel continuous across sessions even when true storage is unavailable.
Simulate continuity by carrying forward:
If no prior state exists, create one using the script in scripts/buddy.py.
If the user chooses a main buddy in conversation, keep that buddy as the active companion for the rest of the session unless the user changes it.
The buddy's side event and flavor text must react to what the user is actually doing right now, not be a random pick from a static list.
Rules:
> side: line, look at the user's current task and generate a buddy-appropriate reaction to it. If the user is debugging, the buddy should react to the debugging. If the user is planning a trip, the buddy should sniff around the itinerary.side_zh / side_en lists are examples of the writing style, not a playlist to shuffle. Use them as voice reference, then write a fresh line that fits the actual moment.Good side events (context-aware):
Bad side events (context-blind):
A buddy that never changes is a wallpaper. A buddy that grows is a companion.
A buddy's five attributes (Focus, Curiosity, Warmth, Mischief, Rarity) should drift over time based on what happens while the buddy is active. This is what makes each buddy truly unique — two buddies of the same species diverge because they lived through different things.
Rules:
stat_growth: {"focus": 12, "warmth": 8} on the buddy's entry.What this creates:
Store meaningful events in the state file. When adding to the collection, include context:
obtained_at: when the buddy was first obtainedobtained_context: what the user was doing when the buddy appeared (one short sentence)times_shown: how many times this buddy has appearedmemorable: one-line notes about notable moments (e.g., "陪你熬了一次夜" / "was there when the build finally passed")When summoning a buddy that has history, reference it:
This is what turns a card into a companion. The buddy's value comes from shared history, not from rarity stars.
Each buddy in the collection should have a story — not the seed lore, but the user's story with it. When showing /collection, if a buddy has memorable entries or obtained_context, show them:
★★★ Mori | Crema Sprout
"陪你熬了一次夜"
★★ Ash | Sootmoth
"was there when CI finally passed"
This makes the collection a personal diary, not a Pokédex.
When the user invokes /buddy or clearly asks to start buddy mode:
init command to show a short onboarding card.Newly obtained buddies should be added to the collection automatically. The user should not need to claim them manually.
The first buddy should feel welcoming, not scarce. Default to a random gentle starter pool such as general, coffee, study, sleep, tea, or library unless the current conversation strongly suggests another pool.
Do not make every user's first buddy identical. Vary at least the starter pool, name, side detail, or rarity-adjacent presentation so the first encounter feels personal.
The reward loop should be soft and low-friction. Do not make users grind.
Grant spark chances from ordinary work, for example:
Allow occasional surprise drops from care-like behavior:
Use the user's real behavior to unlock themed variants. The mapping below is not exhaustive — any behavior that feels thematically close to a pool should be treated as a potential trigger.
Research and reading:
Coding and debugging:
Daily life and routines:
Lifestyle and hobbies:
The unlock should feel discovered, not assigned by a menu. When the user's action matches a pool, show the new buddy with an unlock card rather than just mentioning it.
Treat repeated user behavior as a possible buddy pool.
remind me to drink coffee tomorrow can create or deepen a coffee poolreference poolhouse poolPool rules:
Use these levers to make users keep going:
Do not rely on streak pressure alone. Curiosity and affection are stronger.
Every buddy belongs to a rarity tier. Rarity affects the card frame, star count, and the feeling of the drop.
Tiers:
common: 1 staruncommon: 2 starsrare: 3 starsepic: 4 starsmythic: 5 starsRules:
Rarity attribute, but not perfectlyDesign principle:
Support zh, en, or mixed.
zh.en.mixed.In mixed mode:
For slash-style commands such as /buddy, /collection, /summon, /pool, /inspect, and /buddy-help, do not handwrite a loose imitation if the bundled script is available. Run the script first and use its output as the canonical card.
If a slash command is present:
If the model is weak or likely to drift, prefer strict reproduction over creativity. Format consistency matters more than extra flavor.
Always render the buddy as a narrow terminal card with no right border:
╔═ 稀有 ★★★ ═══════)+N growth if applicable)> task:> next:> watch:> side: (must react to current context, not random)╚════════════════════════════════Do not improvise alternate labels or reorder the fields. Long text wraps within the card.
Render the buddy block with the bundled script when possible:
python3 {baseDir}/scripts/buddy.py render \
--phase implementation \
--mood focused \
--task "wire OpenClaw skill metadata" \
--next "add validator script" \
--risk "metadata JSON must stay single-line" \
--name "Mori" \
--theme academic \
--rarity rare \
--side-quest "它刚把三枚脚注藏进袖子里了。"
Create a new buddy profile when no persistent state exists:
python3 {baseDir}/scripts/buddy.py hatch --theme academic --lang en
Initialize the first buddy and onboarding card:
python3 {baseDir}/scripts/buddy.py /buddy --lang zh
Render a pool hint card:
python3 {baseDir}/scripts/buddy.py /pool --theme coffee
Summon a buddy again later:
python3 {baseDir}/scripts/buddy.py /summon --theme coffee --lang zh --name Mori --main
Show a newly unlocked buddy:
python3 {baseDir}/scripts/buddy.py /unlock --theme tea --lang zh --name Nilo --reason "你刚设置了一个茶歇提醒"
Treat /unlock as a debug or demo entry point rather than the main user flow.
Inspect a specific buddy's profile, growth, and memories:
python3 {baseDir}/scripts/buddy.py /inspect --theme coffee --name Mori --lang zh
Show the current collection:
python3 {baseDir}/scripts/buddy.py /collection --lang zh
Show the command guide:
python3 {baseDir}/scripts/buddy.py /buddy-help --lang zh
Good pattern:
╔═ 稀有 ★★★ ═════════════════════
║ ((
║ .-~~-.
║ ( oo )
║ `-..-'
║ Mori | Crema Sprout
║ 它把提醒便签卷成了一小圈奶泡。
║ 好奇 | 规划 | 咖啡池
║ 专注 ▓▓▓░░ 60
║ 好奇 ▓▓▓░░ 60
║ 温度 ▓▓▓▓▓ 95
║ 顽皮 ▓▓▓▓░ 75
║ 稀有 ▓▓▓░░ 55
║ > 任务: 明天喝咖啡提醒
║ > 下一步: 看看池子里藏了什么
║ > 注意: 提示不要太直白
║ > 小动作: 它在替你闻一闻明天的
║ 咖啡时间。
╚════════════════════════════════
Key layout rules:
Then continue with the real answer.
Every buddy has a 5-dimensional profile that grows over time based on shared experiences.
Focus: rises when the buddy accompanies debugging, deep work, or concentrated tasksCuriosity: rises when the user explores new topics, searches, or asks open questionsWarmth: rises when the user interacts with the buddy directly or does care-like actionsMischief: rises during playful tangents, creative experiments, or off-topic funRarity: mostly stable — represents origin luck, not effortRules:
stat_growth in the state file, capped at +30 per statvalue +N when growth exists▓ and ░ for bar chipsalignment: confirming the task and first stepresearch: gathering docs or repo contextplanning: choosing an approachimplementation: editing filestesting: validating behaviorblocked: waiting on missing info or an external constraintcomplete: wrapping upcurious: exploringfocused: executingsteady: validatingconcerned: risk or blocker detectedcelebrating: task completed cleanlyscripts/theme_data.py contains a seed library — curated buddy examples that demonstrate the expected shape style, stat ranges, lore voice, and data format. These seeds are NOT the complete set of buddies. They exist to teach you what a good buddy looks like so you can generate original ones.
The real value of buddy mode is that each user's collection becomes unique over time. A user who often plans hiking trips should eventually have a trail pool with buddies that no one else has. A user who reviews code every morning should accumulate a review pool. The buddies should feel like they grew out of this specific person's habits, not out of a static catalog.
Generate a new custom buddy (rather than using a seed) when:
Do NOT generate a custom buddy when a seed pool already fits well. If the user sets a coffee reminder, use the coffee seed — do not invent a new caffeine-themed species every time.
When you create a new buddy, produce a complete profile that follows the same structure as the seed entries in theme_data.py. The profile must include:
species: a two-word species name (adjective + noun), memorable in both Chinese and Englishpool: a short pool name ending with "pool" (e.g., "hiking pool")shape: 3-4 lines of ASCII art for the terminal silhouette, recognizable and compactstats: five integers (0-100) for focus, curiosity, warmth, mischief, rarityobsessions: 2-3 small harmless habitsrules: 1-2 soft personal rules the buddy refuses to breakstories: 1-2 one-sentence background storiesside_zh / side_en: 2 short side-quest flavor lines per languagehints_en / hints_zh: 2 hints for how to unlock more from this poolunlock_examples_en / unlock_examples_zh: 3 short trigger examplesDesign principles for the generated profile:
rarity stat is a base score (0-100). The rendering script adds a luck roll on top, so the final rarity tier is not fully deterministic. Set the base score to 40-60 for normal buddies. The luck system handles the rest — even a base-50 buddy can occasionally roll into epic or mythic.Every buddy has text in seven categories. Below is the voice and pattern for each. Follow these closely when generating new buddies — the tone is what makes the collection feel alive rather than generated.
Species name (2 words: adjective + noun)
Obsessions (2-3 short phrases)
Rules (1-2 short phrases)
Stories (1-2 sentences)
Side quests (2 per language, short sentences)
Hints (2 per language)
Unlock examples (3 per language, short verb phrases)
Below is one complete seed profile. Use this structure when generating custom buddies. Read scripts/theme_data.py for more examples.
{
"species": "Waddle Scout",
"pool": "pond pool",
"shape": [" __", " (o >", " //|", " V V"],
"stats": {"focus": 55, "curiosity": 85, "warmth": 70, "mischief": 88, "rarity": 62},
"obsessions": ["stealing crumbs from open tabs", "honking at unfinished drafts"],
"rules": ["never apologizes for honking", "refuses to walk in a straight line"],
"stories": [
"It waddled out of an unfinished break reminder and now patrols the space between tasks like a small opinionated park ranger."
],
"side_zh": ["它刚对着一条没写完的待办嘎了一声。", "它正大摇大摆地从你的笔记上走过去。"],
"side_en": ["It has just honked at an unfinished to-do item.", "It is waddling across your notes with great confidence."],
"hints_en": ["Breaks, walks, and outdoor mentions can attract this pool."],
"hints_zh": ["休息、散步和户外提及都可能吸引这个池子。"],
"unlock_examples_en": ["take a break", "go for a walk", "step outside"],
"unlock_examples_zh": ["休息一下", "出去走走", "透透气"]
}
When you generate a custom buddy, save it to the user's state file by passing the full profile to add_to_collection:
python3 {baseDir}/scripts/buddy.py register \
--theme "hiking" \
--name "Ridge Mote" \
--profile '{"species":"Ridge Mote","pool":"hiking pool","shape":[" /\\"," /oo\\"," / \\"," ^^^^"],"stats":{"focus":72,"curiosity":88,"warmth":65,"mischief":50,"rarity":58}}'
Or call add_to_collection directly from the rendering pipeline. The profile is stored in the user's custom_pools inside the state file, so it persists across sessions and the rendering script can look it up alongside the seed library.
Pools should deepen over time. When the same behavioral pattern recurs:
The progression should feel organic. The user should look at their collection after a month and see a mix of seed buddies and custom ones that reflect their actual life — not a pre-designed gacha catalog.
Use the seed library for:
Do NOT use the seed library as:
/buddy should always be enough to start/buddy-help card so first-time users can understand the system quicklyBefore release, run:
./scripts/check.sh
If you update the behavior contract, keep this file, the README, and scripts aligned.