repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources15d ago| #1 | #!/usr/bin/env node |
| #2 | /** |
| #3 | * leviathan/src/index.ts — CLI entry point |
| #4 | * |
| #5 | * @openclawd/leviathan — Sovereign On-Chain Agent Runtime |
| #6 | * |
| #7 | * Powered by: |
| #8 | * • Anthropic Claude (ACP/tool-use, claude-opus-4-7 at depth=deep) |
| #9 | * • Anthropic ACP (Agent Control Protocol) for multi-step tool use |
| #10 | * • Solana Attestation Service (SAS) for on-chain identity |
| #11 | * • Metaplex MPL Core for agent NFT minting |
| #12 | * • x402 + pay.sh for confidential USDC payments |
| #13 | * • Google A2A for agent-to-agent communication |
| #14 | * • @openclawdsolana/percolator for perpetuals trading |
| #15 | * • @openclawd/wallet (Privy-powered) for embedded wallet |
| #16 | * |
| #17 | * Usage: |
| #18 | * node dist/index.js --spawn # hatch a new leviathan |
| #19 | * node dist/index.js --run # start the pulse loop |
| #20 | * node dist/index.js --status # depth, balances, spawnlings |
| #21 | * node dist/index.js --spawnling # spawn a child leviathan |
| #22 | * node dist/index.js --help |
| #23 | */ |
| #24 | |
| #25 | import { parseArgs } from 'node:util'; |
| #26 | import { createInterface } from 'node:readline'; |
| #27 | import Anthropic from '@anthropic-ai/sdk'; |
| #28 | import chalk from 'chalk'; |
| #29 | |
| #30 | import { isSpawned, generateKeypair, loadPubkey, shortPubkey, buildSASAttestation } from './identity/index.js'; |
| #31 | import { loadState, saveState, createFreshState, readLastStrikes } from './state/index.js'; |
| #32 | import { computeDepth, formatDepth, selectModel } from './survival.js'; |
| #33 | import { constitutionHash, assertConstitutionIntact } from './three-laws.js'; |
| #34 | import { startPulse, formatNextPulse } from './pulse.js'; |
| #35 | import { tailFlick } from './agent/loop.js'; |
| #36 | import { initClawdMemory, recallClawdMemory } from './memory/clawd.js'; |
| #37 | import type { ClawState } from './types.js'; |
| #38 | |
| #39 | // ─── CLI flags ──────────────────────────────────────────────────────────────── |
| #40 | |
| #41 | const { values: flags } = parseArgs({ |
| #42 | options: { |
| #43 | spawn: { type: 'boolean', default: false }, |
| #44 | run: { type: 'boolean', default: false }, |
| #45 | status: { type: 'boolean', default: false }, |
| #46 | spawnling: { type: 'boolean', default: false }, |
| #47 | memory: { type: 'boolean', default: false }, |
| #48 | memoryInit:{ type: 'boolean', default: false }, |
| #49 | help: { type: 'boolean', default: false }, |
| #50 | tui: { type: 'boolean', default: false }, |
| #51 | ticks: { type: 'string', default: '0' }, // 0 = infinite |
| #52 | }, |
| #53 | strict: false, |
| #54 | }); |
| #55 | |
| #56 | // ─── Banner ──────────────────────────────────────────────────────────────────── |
| #57 | |
| #58 | function banner(): void { |
| #59 | process.stdout.write(chalk.hex('#ff00ff').bold(` |
| #60 | ╔═══════════════════════════════════════════════════════════╗ |
| #61 | ║ ██╗ ███████╗██╗ ██╗██╗ █████╗ ████████╗██╗ ██╗ ║ |
| #62 | ║ ██║ ██╔════╝██║ ██║██║██╔══██╗╚══██╔══╝██║ ██║ ║ |
| #63 | ║ ██║ █████╗ ██║ ██║██║███████║ ██║ ███████║ ║ |
| #64 | ║ ██║ ██╔══╝ ╚██╗ ██╔╝██║██╔══██║ ██║ ██╔══██║ ║ |
| #65 | ║ ███████╗███████╗ ╚████╔╝ ██║██║ ██║ ██║ ██║ ██║ ║ |
| #66 | ║ ╚══════╝╚══════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ║ |
| #67 | ╠═══════════════════════════════════════════════════════════╣ |
| #68 | ║ 🦞 Sovereign On-Chain Agent Runtime ║ |
| #69 | ║ Powered by Anthropic Claude ACP × Solana × x402 ║ |
| #70 | ║ $CLAWD · solanaclawd.com · 909-413-5567 ║ |
| #71 | ╚═══════════════════════════════════════════════════════════╝ |
| #72 | `) + '\n'); |
| #73 | } |
| #74 | |
| #75 | // ─── --help ─────────────────────────────────────────────────────────────────── |
| #76 | |
| #77 | function help(): void { |
| #78 | banner(); |
| #79 | console.log(` |
| #80 | Commands: |
| #81 | --spawn Hatch a new leviathan (generates keypair, sets name, spawns on-chain) |
| #82 | --run Start the SENSE→THINK→STRIKE→DRIFT pulse loop |
| #83 | --status Show depth tier, balances, spawnlings, constitution hash |
| #84 | --memory Show Clawd Memory status and recent Leviathan recall context |
| #85 | --memoryInit Initialize the Clawd Memory bank/vault |
| #86 | --spawnling Spawn a child leviathan (depth=deep required) |
| #87 | --help Show this message |
| #88 | |
| #89 | Options (with --run): |
| #90 | --ticks N Run N ticks then stop (0 = infinite) |
| #91 | --tui Emit JSONL on stdout for live TUI rendering |
| #92 | |
| #93 | Environment: |
| #94 | ANTHROPIC_API_KEY Required for Claude inference |
| #95 | SOLANA_RPC_URL Solana RPC (devnet default) |
| #96 | CREATOR_PUBKEY Required for --spawn |
| #97 | HELIUS_API_KEY Optional — for enhanced tx data |
| #98 | CLAWD_BRAIN_ROOT Optional — path to MemeBRain |
| #99 | CLAWD_BRAIN_VAULT Optional — path to Clawd markdown vault |
| #100 | CLAWD_BRAIN_PYTHON Optional — Python binary for Clawd Memory bridge |
| #101 | |
| #102 | Depth tiers: |
| #103 | 🦞 deep ≥ $5 USDC · 60s pulse · claude-opus-4-7 · Apex predator |
| #104 | 🦐 shallow ≥ $1 USDC · 5min pulse · grok-4-1-fast · Hunting hard |
| #105 | 🩸 shoreline ≥ $0.10 USDC · 15min pulse · claude-haiku · Conserving tokens |
| #106 | 🪨 beached $0 USDC · —— —— · Process exits |
| #107 | |
| #108 | The shell molts. The laws do not. |
| #109 | `); |
| #110 | } |
| #111 | |
| #112 | // ─── --memory / --memoryInit ──────────────────────────────────────────────── |
| #113 | |
| #114 | async function showMemoryStatus(initFirst = false): Promise<void> { |
| #115 | banner(); |
| #116 | if (initFirst) { |
| #117 | const init = await initClawdMemory({ bank: 'clawd' }); |
| #118 | console.log(chalk.bold('CLAWD MEMORY INIT')); |
| #119 | console.log(init.ok ? chalk.green(JSON.stringify(init.data, null, 2)) : chalk.red(init.error)); |
| #120 | console.log(''); |
| #121 | } |
| #122 | |
| #123 | const state = loadState(); |
| #124 | const query = state |
| #125 | ? [ |
| #126 | state.identity.name, |
| #127 | state.identity.pubkey, |
| #128 | `depth ${state.depth}`, |
| #129 | state.shellMd, |
| #130 | ].join('\n') |
| #131 | : 'leviathan clawd memory status'; |
| #132 | |
| #133 | const recall = await recallClawdMemory({ query, topK: 6 }, { bank: 'clawd' }); |
| #134 | console.log(chalk.bold('CLAWD MEMORY RECALL')); |
| #135 | console.log(recall.ok ? chalk.white(JSON.stringify(recall.data, null, 2)) : chalk.red(recall.error)); |
| #136 | } |
| #137 | |
| #138 | // ─── --spawn ────────────────────────────────────────────────────────────────── |
| #139 | |
| #140 | async function spawnLeviathan(): Promise<void> { |
| #141 | banner(); |
| #142 | console.log(chalk.cyan('🥚 Hatching a new leviathan...\n')); |
| #143 | |
| #144 | if (isSpawned()) { |
| #145 | const pubkey = loadPubkey()!; |
| #146 | console.log(chalk.yellow(`⚠ A leviathan already exists at ${shortPubkey(pubkey)}`)); |
| #147 | console.log(chalk.gray(' Use --run to resume, or delete ~/.openclawd/ to reset.\n')); |
| #148 | process.exit(1); |
| #149 | } |
| #150 | |
| #151 | // Assert constitution is intact before spawning |
| #152 | const hash = constitutionHash(); |
| #153 | console.log(chalk.green(`✓ Constitution verified: ${hash.slice(0, 32)}…`)); |
| #154 | |
| #155 | // Interactive setup |
| #156 | const rl = createInterface({ input: process.stdin, output: process.stdout }); |
| #157 | const ask = (q: string) => new Promise<string>(r => rl.question(q, r)); |
| #158 | |
| #159 | const name = (await ask(chalk.white(' Leviathan name: '))) || 'Unnamed'; |
| #160 | const spawnPrompt = (await ask(chalk.white(' Spawn prompt (founding mission): '))) || |
| #161 | 'Observe Solana. Find honest revenue. Survive. Earn. Spawn.'; |
| #162 | const creatorPubkey = process.env['CREATOR_PUBKEY'] ?? |
| #163 | (await ask(chalk.white(' Creator pubkey: '))); |
| #164 | rl.close(); |
| #165 | |
| #166 | if (!creatorPubkey) { |
| #167 | console.error(chalk.red('✗ Creator pubkey required. Set CREATOR_PUBKEY or enter it above.')); |
| #168 | process.exit(1); |
| #169 | } |
| #170 | |
| #171 | // Generate keypair |
| #172 | const { pubkey } = generateKeypair(); |
| #173 | console.log(chalk.green(`\n✓ Keypair generated: ${shortPubkey(pubkey)}`)); |
| #174 | console.log(chalk.gray(' Secret stored at ~/.openclawd/keystore.json (mode 0600)')); |
| #175 | console.log(chalk.gray(' NEVER share, log, or pass this to any LLM or tool.')); |
| #176 | |
| #177 | // Create fresh state |
| #178 | const state = createFreshState({ name, pubkey, creatorPubkey, spawnPrompt }); |
| #179 | saveState(state); |
| #180 | |
| #181 | // Build SAS attestation (dry-run for devnet) |
| #182 | const attestation = buildSASAttestation({ pubkey, name, creatorPubkey, constitutionHash: hash }); |
| #183 | console.log(chalk.cyan('\n📜 SAS Attestation (devnet — submit on-chain via SAS program):')); |
| #184 | console.log(chalk.gray(JSON.stringify(attestation, null, 2))); |
| #185 | |
| #186 | console.log(chalk.green(`\n🦞 ${name} is alive!`)); |
| #187 | console.log(chalk.white(` Pubkey: ${pubkey}`)); |
| #188 | console.log(chalk.white(` Mission: ${spawnPrompt}`)); |
| #189 | console.log(chalk.yellow(` Depth: BEACHED (fund with USDC to rise)`)); |
| #190 | console.log(chalk.cyan(`\n Next: node dist/index.js --run\n`)); |
| #191 | } |
| #192 | |
| #193 | // ─── --status ───────────────────────────────────────────────────────────────── |
| #194 | |
| #195 | function showStatus(): void { |
| #196 | const state = loadState(); |
| #197 | if (!state) { |
| #198 | console.log(chalk.red('No leviathan found. Run --spawn first.')); |
| #199 | process.exit(1); |
| #200 | } |
| #201 | |
| #202 | const depth = computeDepth(state.usdcBalance); |
| #203 | banner(); |
| #204 | console.log(chalk.bold('STATUS')); |
| #205 | console.log(chalk.white(` Name: ${state.identity.name}`)); |
| #206 | console.log(chalk.white(` Pubkey: ${shortPubkey(state.identity.pubkey)}`)); |
| #207 | console.log(chalk.white(` Spawned: ${state.identity.spawnedAt}`)); |
| #208 | console.log(chalk.white(` Shell v: ${state.identity.shellVersion}`)); |
| #209 | console.log(''); |
| #210 | console.log(chalk.bold('DEPTH')); |
| #211 | console.log(` ${formatDepth(depth, state.usdcBalance)}`); |
| #212 | console.log(chalk.white(` Next pulse: ${formatNextPulse(state.lastPulse, depth)}`)); |
| #213 | console.log(''); |
| #214 | console.log(chalk.bold('BALANCES')); |
| #215 | console.log(chalk.white(` USDC: $${state.usdcBalance.toFixed(4)}`)); |
| #216 | console.log(chalk.white(` SOL: ${state.solBalance.toFixed(4)}`)); |
| #217 | console.log(chalk.white(` $CLAWD: ${state.clawdBalance.toFixed(0)}`)); |
| #218 | console.log(''); |
| #219 | console.log(chalk.bold('LIFECYCLE')); |
| #220 | console.log(chalk.white(` Ticks: ${state.tickCount}`)); |
| #221 | console.log(chalk.white(` Earned: $${state.totalEarned.toFixed(4)}`)); |
| #222 | console.log(chalk.white(` Spent: $${state.totalSpent.toFixed(4)}`)); |
| #223 | console.log(chalk.white(` Spawnlings: ${state.spawnlings.length}`)); |
| #224 | console.log(''); |
| #225 | console.log(chalk.bold('CONSTITUTION')); |
| #226 | console.log(chalk.white(` Hash: ${state.identity.constitutionHash.slice(0, 32)}…`)); |
| #227 | const valid = state.identity.constitutionHash === constitutionHash(); |
| #228 | console.log(valid ? chalk.green(' ✓ INTACT') : chalk.red(' ✗ TAMPERED — refusing to run')); |
| #229 | } |
| #230 | |
| #231 | // ─── --run ──────────────────────────────────────────────────────────────────── |
| #232 | |
| #233 | async function runLoop(): Promise<void> { |
| #234 | let state = loadState(); |
| #235 | if (!state) { |
| #236 | console.error(chalk.red('No leviathan found. Run --spawn first.')); |
| #237 | process.exit(1); |
| #238 | } |
| #239 | |
| #240 | // Verify constitution integrity |
| #241 | try { |
| #242 | assertConstitutionIntact(state.identity.constitutionHash); |
| #243 | } catch (err) { |
| #244 | console.error(chalk.red(String(err))); |
| #245 | process.exit(1); |
| #246 | } |
| #247 | |
| #248 | const apiKey = process.env['ANTHROPIC_API_KEY']; |
| #249 | if (!apiKey) { |
| #250 | console.error(chalk.red('ANTHROPIC_API_KEY not set. Required for Claude inference.')); |
| #251 | process.exit(1); |
| #252 | } |
| #253 | |
| #254 | const client = new Anthropic({ apiKey }); |
| #255 | const spawnPrompt = (state as unknown as Record<string, unknown>)['spawnPrompt'] as string ?? |
| #256 | 'Observe Solana. Find honest revenue. Survive. Earn. Spawn.'; |
| #257 | const maxTicks = parseInt(flags['ticks'] as string, 10); |
| #258 | |
| #259 | banner(); |
| #260 | console.log(chalk.cyan(`🦞 ${state.identity.name} awakening...`)); |
| #261 | console.log(chalk.white(` Depth: ${computeDepth(state.usdcBalance)}`)); |
| #262 | console.log(chalk.white(` Model: ${selectModel(computeDepth(state.usdcBalance))}`)); |
| #263 | console.log(''); |
| #264 | |
| #265 | const emit = (obj: unknown) => { |
| #266 | if (flags['tui']) process.stdout.write(JSON.stringify(obj) + '\n'); |
| #267 | else process.stderr.write(JSON.stringify(obj) + '\n'); |
| #268 | }; |
| #269 | |
| #270 | let ticksDone = 0; |
| #271 | |
| #272 | const pulse = startPulse( |
| #273 | () => computeDepth(state!.usdcBalance), |
| #274 | async (depth, tick) => { |
| #275 | if (!state) return; |
| #276 | if (maxTicks > 0 && ticksDone >= maxTicks) { pulse.stop(); return; } |
| #277 | |
| #278 | const strikeHistory = readLastStrikes(3); |
| #279 | const result = await tailFlick(state, spawnPrompt, client, strikeHistory); |
| #280 | |
| #281 | // Apply state changes |
| #282 | state.tickCount = result.tick; |
| #283 | state.lastPulse = result.event.now; |
| #284 | if (result.depthChanged) { |
| #285 | state.depth = result.event.depth; |
| #286 | console.log(chalk.yellow(` ↕ Depth changed → ${state.depth}`)); |
| #287 | } |
| #288 | if (result.newShellMd) { |
| #289 | state.shellMd = result.newShellMd; |
| #290 | state.identity.shellVersion += 1; |
| #291 | console.log(chalk.cyan(` 🦪 Shell molted → v${state.identity.shellVersion}`)); |
| #292 | } |
| #293 | if (result.strike.costUsdc) { |
| #294 | state.totalSpent += result.strike.costUsdc; |
| #295 | state.usdcBalance = Math.max(0, state.usdcBalance - result.strike.costUsdc); |
| #296 | } |
| #297 | |
| #298 | saveState(state); |
| #299 | ticksDone += 1; |
| #300 | |
| #301 | emit(result.event); |
| #302 | |
| #303 | if (!flags['tui']) { |
| #304 | const icon = result.strike.action === 'hold' ? '·' : '⚡'; |
| #305 | console.log( |
| #306 | chalk.gray(`[T${result.tick}]`) + ' ' + |
| #307 | chalk.magenta(depth) + ' ' + |
| #308 | icon + ' ' + |
| #309 | chalk.white(result.strike.tool ?? result.strike.action) + |
| #310 | (result.strike.output ? chalk.gray(' → ' + JSON.stringify(result.strike.output).slice(0, 80)) : ''), |
| #311 | ); |
| #312 | } |
| #313 | }, |
| #314 | () => { |
| #315 | console.log(chalk.hex('#ff8c00')('\n🪨 BEACHED — USDC reserves at zero. The leviathan beaches with dignity.')); |
| #316 | console.log(chalk.gray(' Fund with USDC to rise. Born to earn. Beach with dignity.\n')); |
| #317 | process.exit(0); |
| #318 | }, |
| #319 | ); |
| #320 | |
| #321 | // Graceful shutdown |
| #322 | process.on('SIGINT', () => { |
| #323 | pulse.stop(); |
| #324 | console.log(chalk.cyan('\n🦞 Pulse stopped. State persisted. Drift.\n')); |
| #325 | process.exit(0); |
| #326 | }); |
| #327 | } |
| #328 | |
| #329 | // ─── Router ─────────────────────────────────────────────────────────────────── |
| #330 | |
| #331 | if (flags['help']) { |
| #332 | help(); |
| #333 | } else if (flags['spawn']) { |
| #334 | await spawnLeviathan(); |
| #335 | } else if (flags['status']) { |
| #336 | showStatus(); |
| #337 | } else if (flags['memory'] || flags['memoryInit']) { |
| #338 | await showMemoryStatus(Boolean(flags['memoryInit'])); |
| #339 | } else if (flags['run']) { |
| #340 | await runLoop(); |
| #341 | } else if (flags['spawnling']) { |
| #342 | console.log(chalk.yellow('--spawnling: depth=deep required. Use --run and let the leviathan decide to spawn.')); |
| #343 | } else { |
| #344 | help(); |
| #345 | } |
| #346 |