Claude code宠物(/buddy爆改宠物属性,从common的Octopus变成了传说级闪光Dragon)
1.先讲讲Claude code最近出来的/buddy小宠物,相信大家意见有很多玩家都生成了自己的小宠物 那先介绍一下这个宠物系统原理:
让 AI 分析了claude code泄露的源码(src/buddy/),整个系统分两层:
Bones(骨架) —— 外观、物种、稀有度、属性,全部由 hash(userID + SALT) 确定性生成,不存储在配置中,每次读取时实时计算。
Soul(灵魂) —— 名字和性格,由模型生成,存储在 ~/.claude.json (windows系统一般在C:\Users\用户名称.claude.json)的 companion 字段中。
// src/buddy/companion.ts
const SALT = 'friend-2026-401'
export function companionUserId(): string {
const config = getGlobalConfig()
return config.oauthAccount?.accountUuid ?? config.userID ?? 'anon'
}
一共有多少种?
18 个物种:
duck🦆,goose大鹅,blob泡泡,cat🐱,dragon🐉,octopus🐙,owl🦉,penguin🐧,turtle🐢,snail🐌,ghost👻,axolotl蝾螈,capybara水豚,cactus🌵,robot🤖,rabbit🐇mushroom🍄,chonk胖乎乎
5 个稀有度:
稀有度权重概率
★ common 60%
★★ uncommon 25%
★★★ rare 10%
★★★★ epic 4%
★★★★★ legendary 1%
还有 6 种眼睛(· ✦ × ◉ @ °)、8 种帽子、5 项属性(DEBUGGING / PATIENCE / CHAOS / WISDOM / SNARK),以及 1% 概率的 shiny 闪光版。
userID 是什么?
没登录 OAuth 账号的情况下,userID 是首次启动时随机生成的 32 字节 hex 字符串:
// src/utils/config.ts
const userID = randomBytes(32).toString('hex')
saveGlobalConfig(current => ({ ...current, userID }))
它只用于:遥测分析(匿名 device_id)、A/B 分桶、buddy 种子。跟对话历史、API key、本地配置完全无关。 换掉不影响任何东西。
如何重置
编辑 ~/.claude.json(或C:\Users\用户名称.claude.json),替换
2.先用powershell命令安装bun.exe或者node.js(node在上一篇文档中有教下载)
powershell -c "irm bun.sh/install.ps1 | iex"
2.使用buddy-reroll-top.js,用命令node或者bun去运行它,species代表物种,rarity代表稀有度,eye代表眼睛,shiny代表闪光,后面几个参数是找出top5个数值的宠物,然后将这些uid记录到自己的一个记事本或者任意文档中(值得注意的是你安装claude code用的是node安装的话就用node去找对应的宠物uid,不要用bun,不然找出的uid是对不上你这个宠物的,可能是解析字符串的算法不一样,博主亲测,切记)
#!/usr/bin/env node
// buddy-reroll-top.js
// 在原版基础上新增 --top-stats 模式:
// 扫描大量样本,按五项属性总分排序,输出最高的 N 个结果。
// 其余过滤条件(--species / --rarity / --eye / --hat / --shiny)照常生效。
//
// 新增选项:
// --top-stats 启用 top 模式(按总分排序,替代原来的 --min-stats)
// --top-count <n> 保留总分最高的前 N 个候选(默认 10)
//
// 推荐用法:
// node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
//
// 注意:Node.js 使用 FNV-1a hash,结果与真实 Claude Code (Bun.hash) 不同。
const crypto = require('crypto')
// --- Constants ---
const SALT = 'friend-2026-401'
const SPECIES = ['duck','goose','blob','cat','dragon','octopus','owl','penguin','turtle','snail','ghost','axolotl','capybara','cactus','robot','rabbit','mushroom','chonk']
const RARITIES = ['common','uncommon','rare','epic','legendary']
const RARITY_WEIGHTS = { common:60, uncommon:25, rare:10, epic:4, legendary:1 }
const RARITY_RANK = { common:0, uncommon:1, rare:2, epic:3, legendary:4 }
const EYES = ['·','✦','×','◉','@','°']
const HATS = ['none','crown','tophat','propeller','halo','wizard','beanie','tinyduck']
const STAT_NAMES = ['DEBUGGING','PATIENCE','CHAOS','WISDOM','SNARK']
const RARITY_FLOOR = { common:5, uncommon:15, rare:25, epic:35, legendary:50 }
const RARITY_STARS = { common:'★', uncommon:'★★', rare:'★★★', epic:'★★★★', legendary:'★★★★★' }
// --- Hash ---
function hashFNV1a(s) {
let h = 2166136261
for (let i = 0; i < s.length; i++) {
h ^= s.charCodeAt(i)
h = Math.imul(h, 16777619)
}
return h >>> 0
}
// --- PRNG ---
function mulberry32(seed) {
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 pick(rng, arr) { return arr[Math.floor(rng() * arr.length)] }
function rollRarity(rng) {
let roll = rng() * 100
for (const r of RARITIES) {
roll -= RARITY_WEIGHTS[r]
if (roll < 0) return r
}
return 'common'
}
function rollStats(rng, rarity) {
const floor = RARITY_FLOOR[rarity]
const peak = pick(rng, STAT_NAMES)
let dump = pick(rng, STAT_NAMES)
while (dump === peak) dump = pick(rng, STAT_NAMES)
const stats = {}
for (const name of STAT_NAMES) {
if (name === peak) stats[name] = Math.min(100, floor + 50 + Math.floor(rng() * 30))
else if (name === dump) stats[name] = Math.max(1, floor - 10 + Math.floor(rng() * 15))
else stats[name] = floor + Math.floor(rng() * 40)
}
return stats
}
function rollFull(uid) {
const rng = mulberry32(hashFNV1a(uid + SALT))
const rarity = rollRarity(rng)
const species = pick(rng, SPECIES)
const eye = pick(rng, EYES)
const hat = rarity === 'common' ? 'none' : pick(rng, HATS)
const shiny = rng() < 0.01
const stats = rollStats(rng, rarity)
return { rarity, species, eye, hat, shiny, stats }
}
// --- CLI ---
function parseArgs() {
const args = process.argv.slice(2)
const opts = { max: 5_000_000, count: 3, topCount: 10 }
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case '--species': opts.species = args[++i]; break
case '--rarity': opts.rarity = args[++i]; break
case '--eye': opts.eye = args[++i]; break
case '--hat': opts.hat = args[++i]; break
case '--shiny': opts.shiny = true; break
case '--top-stats': opts.topStats = true; break
case '--top-count': opts.topCount = parseInt(args[++i]); break
case '--max': opts.max = parseInt(args[++i]); break
case '--count': opts.count = parseInt(args[++i]); break
case '--check': opts.check = args[++i]; break
case '--min-stats': {
const next = args[i + 1]
opts.minStatsVal = (next && !next.startsWith('--')) ? parseInt(args[++i]) : 90
break
}
case '--help': case '-h':
console.log(`Usage: node buddy-reroll-top.js [options]
过滤选项(先缩小范围):
--species <name> ${SPECIES.join(', ')}
--rarity <name> ${RARITIES.join(', ')}(最低稀有度)
--eye <char> ${EYES.join(' ')}
--hat <name> ${HATS.join(', ')}
--shiny 只要闪光
属性排序模式(推荐):
--top-stats 按五项属性总分从高到低排序输出
--top-count <n> 保留总分最高的前 N 个(默认 10)
原有模式:
--min-stats [value] 要求全部属性 >= value(默认 90,legendary 下几乎不可达)
--count <n> 找到 n 个即停止(默认 3)
其他:
--max <n> 最大迭代次数(默认 5000000)
--check <uid> 查看某个 userID 的 buddy
示例(推荐):
node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
`)
process.exit(0)
}
}
if (opts.species && !SPECIES.includes(opts.species)) {
console.error(`未知 species: ${opts.species}\n可用: ${SPECIES.join(', ')}`); process.exit(1)
}
if (opts.rarity && !RARITIES.includes(opts.rarity)) {
console.error(`未知 rarity: ${opts.rarity}\n可用: ${RARITIES.join(', ')}`); process.exit(1)
}
if (opts.eye && !EYES.includes(opts.eye)) {
console.error(`未知 eye: ${opts.eye}\n可用: ${EYES.join(' ')}`); process.exit(1)
}
if (opts.hat && !HATS.includes(opts.hat)) {
console.error(`未知 hat: ${opts.hat}\n可用: ${HATS.join(', ')}`); process.exit(1)
}
return opts
}
// --- 打印单个结果 ---
function printResult(rank, uid, r) {
const total = Object.values(r.stats).reduce((a, b) => a + b, 0)
const avg = (total / STAT_NAMES.length).toFixed(1)
console.log(`#${rank} [${r.rarity}${RARITY_STARS[r.rarity]}] ${r.species} eye=${r.eye} hat=${r.hat} shiny=${r.shiny}`)
console.log(` 总分: ${total} 均值: ${avg}`)
for (const name of STAT_NAMES) {
const val = r.stats[name]
const bar = '█'.repeat(Math.floor(val / 5)) + '░'.repeat(20 - Math.floor(val / 5))
console.log(` ${name.padEnd(10)} ${bar} ${val}`)
}
console.log(` uid: ${uid}`)
console.log('')
}
// --- Main ---
const opts = parseArgs()
// Check 模式
if (opts.check) {
console.log(`[Node.js / FNV-1a — 仅供参考,与真实 Claude Code 不同]\n`)
const r = rollFull(opts.check)
printResult('?', opts.check, r)
process.exit(0)
}
const filters = []
if (opts.species) filters.push(`species=${opts.species}`)
if (opts.rarity) filters.push(`rarity>=${opts.rarity}`)
if (opts.eye) filters.push(`eye=${opts.eye}`)
if (opts.hat) filters.push(`hat=${opts.hat}`)
if (opts.shiny) filters.push('shiny=true')
if (opts.topStats) filters.push(`top-${opts.topCount}(按总分排序)`)
else if (opts.minStatsVal) filters.push(`all stats>=${opts.minStatsVal}`)
console.log(`[Node.js / FNV-1a — 结果与真实 Claude Code 不匹配]`)
console.log(`搜索条件: ${filters.join(', ') || '任意'}`)
console.log(`迭代上限: ${opts.max.toLocaleString()}`)
console.log('')
const minRarityRank = opts.rarity ? RARITY_RANK[opts.rarity] : 0
const startTime = Date.now()
// ---- top-stats 模式:维护一个最小堆(用数组模拟) ----
if (opts.topStats) {
// 简单做法:维护一个长度为 topCount 的数组,记录最高总分
// 每次新候选比堆顶大就替换,最后排序输出
const heap = [] // { total, uid, r }
let scanned = 0
let passed = 0
// 进度打点
const REPORT_INTERVAL = 500_000
let nextReport = REPORT_INTERVAL
for (let i = 0; i < opts.max; i++) {
const uid = crypto.randomBytes(32).toString('hex')
const r = rollFull(uid)
// 过滤
if (opts.rarity && RARITY_RANK[r.rarity] < minRarityRank) continue
if (opts.species && r.species !== opts.species) continue
if (opts.eye && r.eye !== opts.eye) continue
if (opts.hat && r.hat !== opts.hat) continue
if (opts.shiny && !r.shiny) continue
passed++
const total = Object.values(r.stats).reduce((a, b) => a + b, 0)
if (heap.length < opts.topCount) {
heap.push({ total, uid, r })
heap.sort((a, b) => a.total - b.total) // 升序,堆顶最小
} else if (total > heap[0].total) {
heap[0] = { total, uid, r }
heap.sort((a, b) => a.total - b.total)
}
scanned++
if (i + 1 >= nextReport) {
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
process.stdout.write(`\r 已扫描 ${(i+1).toLocaleString()} 次 命中过滤 ${passed} 当前最低总分 ${heap.length > 0 ? heap[0].total : '-'} 用时 ${elapsed}s `)
nextReport += REPORT_INTERVAL
}
}
process.stdout.write('\n\n')
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
console.log(`扫描完成:共 ${opts.max.toLocaleString()} 次,命中 ${passed} 个,用时 ${elapsed}s`)
console.log(`输出总分最高的 ${heap.length} 个结果:\n`)
// 降序输出
heap.sort((a, b) => b.total - a.total)
heap.forEach((entry, idx) => printResult(idx + 1, entry.uid, entry.r))
process.exit(0)
}
// ---- 原有模式(找到 count 个即停) ----
let found = 0
for (let i = 0; i < opts.max; i++) {
const uid = crypto.randomBytes(32).toString('hex')
const r = rollFull(uid)
if (opts.rarity && RARITY_RANK[r.rarity] < minRarityRank) continue
if (opts.species && r.species !== opts.species) continue
if (opts.eye && r.eye !== opts.eye) continue
if (opts.hat && r.hat !== opts.hat) continue
if (opts.shiny && !r.shiny) continue
if (opts.minStatsVal && !Object.values(r.stats).every(v => v >= opts.minStatsVal)) continue
found++
printResult(found, uid, r)
if (found >= opts.count) break
}
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
if (found === 0) {
console.log(`在 ${opts.max.toLocaleString()} 次内未找到匹配结果(${elapsed}s)`)
} else {
console.log(`找到 ${found} 个结果,用时 ${elapsed}s`)
}
node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
bun buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
3.打开自己电脑对应的.claude.json文件,找到useID、name、personality这三个字符串对应的值,把上一步得到的任意你满意数值的uid换到useID里面,name和personality你可以取任意名称和个性签名。

4.最后重启你的claude code,就可以得到对应数值拉满的传说级闪光宠物!!!

(结语:博主也是从common的Octopus变成了传说级闪光Dragon,当时出现智慧为1,我人都傻掉了,怎么能数值这么低感觉像是小时候玩洛克王国的感觉)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)