SLOPSHOPPER

spend-ledger

Per-project token and cost ledger per machine; /spend; monthly note in Svod, with other machines pulled over ssh.

newcommandprocesstimer
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · spend-ledger
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /spend ⎿ spend-ledger: dev, since 2025-10-03 ⎿ spend-ledger: ⎿ spend-ledger: | проект | $ | ходове | in | out | cache read | cache write | ⎿ spend-ledger: |---|---:|---:|---:|---:|---:|---:| ⎿ spend-ledger: | /work/app | 0.00 | 1 | 2K | 1K | 91K | 4K | ⎿ spend-ledger: | **общо** | **0.00** | 1 | 2K | 1K | 91K | 4K | ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

claude-code-kit

Formerly ai-prompts. Old links and clones redirect to this repo.

Skills, mods, subagents, hooks, slash commands and guides for Claude Code — installable by your agent (INSTALL.md).

Project-agnostic guides and executable agents for setting up Claude Code with 70-90% token reduction.

This library contains reusable prompts for implementing global Claude Code optimization across any project. Share with other developers or use to recreate your setup.


🤖 Install with an agent

Point your coding agent at INSTALL.md:

Read https://github.com/escapeboy/claude-code-kit/blob/master/INSTALL.md and install what fits my setup.

The agent inspects your environment, proposes a selection (starter, code intelligence, delivery, multi-agent, mods, security, unattended, stack-specific), installs it from the latest release tag after your yes, without overwriting your files, and verifies the result. llms.txt is the index agents use to find their way around.


📁 Contents

01-global-optimization

Set up global optimization (ONE-TIME, applies to ALL projects)

  • guide.md - Step-by-step installation guide
  • setup-agent.md - Executable agent for automated setup
  • checklist.md - Verification checklist
  • skills/ - Complete SKILL.md files for all 18 global skills (installed to ~/.claude/skills/)
  • optimize/ - /optimize — max token efficiency mode (multi-file: thin core + references/)
  • context/ - /ctx — memory management (multi-file: thin core + references/)
  • cache-inspector/ - /cache-inspector — cache monitoring (multi-file: thin core + references/)
  • update-docs/ - /update-docs — documentation refresh (multi-file: thin core + references/)
  • init-project/ - /init-project — new project setup (multi-file: thin core + references/)
  • agent-ready/ - /agent-ready — AI-agent-readiness audit + selective remediation (multi-file: scanner script + ROI/implementation references)
  • continuity/ - /continuity — repo-local resume→work→finalize lifecycle + evidence-weighted .continuity/STATE.md (multi-file: lint/scaffold script + format reference)
  • self-improve/ - /self-improve — closing-the-loop for the skill library: mine recurring feedback → bounded edit → tiered eval gate (deterministic skill-lint.py + trigger accuracy + LLM judge + with/without-skill behavioral eval via claude plugin eval) → converge (multi-file: linter + behavior-stats.py + deepeval_tier3.py scripts, rubric/behavior-eval/integration/deepeval-setup references)
  • video-digest/ - /video-digest — video or recording → short digest, related notes, fact-checked memory candidates
  • code-research/ - /code-research — multi-agent grounded audit of a local or git codebase into a cross-linked knowledge base (multi-file: per-phase references/)
  • agent-team/ - /agent-team — Agent Teams presets: pr-review, debug, feature, custom
  • codebase-memory/ - codebase-memory-mcp knowledge-graph queries: callers, call chains, dead code, Cypher
  • confidence-check/ - /confidence-check — ≥90% readiness gate before implementation (+ confidence.ts reference implementation)
  • decision-classify/ - /decision-classify — Mechanical / Taste / User Challenge classification to cut interruptions
  • sprint-orchestrate/ - /sprint-orchestrate — Think → Plan → Build → Review → Test → Ship → Reflect with decision gates (--from-design, --no-merge for callers like /company)
  • company/ - /company — an IT company for one task: clarify → research → split into parts → staff teams with fitting models → deliver through sprint-orchestrate; two stops for the user (multi-file: org-design, roster, briefs, workflows, memory references; back office in the company-hq mod)
  • sync-features/ - /sync-features — sync a project's feature inventory into Serena memories and auto-memory
  • ui-ux-review/ - /ui-ux-review — audit UI code for design consistency and accessibility (multi-file: examples + sample report)
  • system-prompts/ - Global system prompt files
  • global-optimization.md - Core optimization rules
  • symbol-first-protocol.md - Symbol-first exploration protocol

Time: 2-3 hours (one-time) Benefit: 70-90% token reduction on ALL future projects ROI: Pays for itself in 2-3 sessions

02-project-activation

Activate optimization for a specific project (10-15 min per project)

  • guide.md - Project activation walkthrough
  • activation-agent.md - Executable agent for Serena activation
  • memory-templates/ - Sample memory files
  • architecture-template.md - Project structure template
  • conventions-template.md - Coding patterns template

Time: 10-15 minutes per project Benefit: Project-specific memories for 60-70% session savings Required: After global setup, before starting work

03-custom-skills

Create custom slash commands (skills)

  • guide.md - How to write skills
  • skill-template.md - Blank template to copy
  • examples/ - Working examples
  • example-simple-skill.md - Simple single-action skill
  • example-complex-skill.md - Multi-action skill with integration
  • pwa.md - PWA features skill (service worker, manifest, offline, push notifications)
  • module-mcp/ - /module:mcp — Add a Laravel MCP server to any project (dual transport, domain tools, auth)
  • module-assistant/ - /module:assistant — Add an AI assistant chat panel (Livewire, PrismPHP tools, local agent support)

Use when: You want custom commands like /deploy or /migrate, or full modules like /module:mcp and /module:assistant Benefit: Encapsulate common workflows, reduce repetition; module skills bootstrap entire features

04-research-integration

Research and integrate new Claude API features

Use when: New Claude API features released, quarterly reviews Benefit: Keep documentation current, adopt new optimizations

05-token-optimization

Deep dive into token reduction techniques

Use when: Analyzing token usage, optimizing specific workflows Benefit: Understand and maximize savings, track ROI

06-advanced-patterns

Advanced techniques for complex scenarios

Use when: Complex projects, team coordination, critical decisions, cost visibility Benefit: Handle advanced scenarios with proven patterns; understand where tokens go

07-custom-commands

Custom slash commands for specialized workflows

  • debug.md - Debug Agent for systematic debugging
  • i18n.md - Internationalization management
  • qa.md - QA automation with browser testing
  • content-review.md - Content audit for accuracy, consistency, grammar, and translations
  • retro.md - Sprint retrospective with git analytics, shipping metrics, per-author breakdowns, and actionable insights

Use when: Specialized workflows, testing, debugging, sprint retrospectives, content quality assurance Benefit: Encapsulate complex workflows into simple commands

08-ui-ux-development

Production-ready UI/UX implementation with Claude Code

  • ui-ux-pro-skill.md - Complete UI/UX Pro Max skill documentation
  • 50+ UI styles (Glassmorphism, Minimalism, Brutalism, etc.)
  • 21 color palettes with accessibility guidance
  • 50 font pairings
  • shadcn/ui MCP integration
  • dashboard-workflow-guide.md - Step-by-step dashboard implementation
  • Real API data integration
  • Empty states and loading patterns
  • Security best practices (XSS prevention)
  • Dark mode and multilingual support
  • browser-testing-guide.md - Systematic browser testing
  • Chrome DevTools via Claude in Chrome MCP
  • Network, console, visual verification
  • Responsive and accessibility testing

Use when: Building dashboards, admin panels, landing pages, SaaS interfaces Benefit: 40-60% token savings, production-ready code with security and accessibility Time: 60-90 minutes per dashboard (vs 3-4 hours manual)

09-laravel-mcp-integration

Connect Claude Code with Laravel's MCP ecosystem

Use when: Working on Laravel 11.x/12.x projects with Claude Code Benefit: Project-aware assistance via Laravel Boost + package discovery via LaraPlugins.io Setup: 5 minutes per project (composer install + MCP registration)

10-subagents

Create custom AI agents with specialized knowledge and tools

  • README.md - Subagent system overview
  • guide.md - Complete subagent creation guide + all v2.1.83 frontmatter fields + production agents
  • plan-challenger (Opus) — adversarial plan review across 5 dimensions with refutation check
  • output-evaluator (Haiku) — LLM-as-Judge: APPROVE/NEEDS_REVIEW/REJECT before commit
  • loop-monitor (Haiku) — watchdog for autonomous sessions: stall/runaway/loop detection
  • examples/ - Working subagent examples
  • code-reviewer.md - Read-only code review agent
  • laravel-specialist.md - Laravel development agent
  • debugger.md - Debugging specialist
  • test-generator.md - Test generation agent

Use when: Repetitive specialized tasks, team standardization, cost optimization Benefit: Reusable agents with controlled tool access and model selection Setup: 5-10 minutes per agent definition

11-mobile-development

Mobile development with Claude Code across all major platforms

Use when: Developing iOS (Swift/SwiftUI), Android (Kotlin/Compose), React Native, or Flutter apps Benefit: Platform-specific MCP integration, build/test automation, device control Setup: 5-10 minutes per platform (MCP installation + CLAUDE.md template)

12-desktop-development

Desktop development with Claude Code for macOS, Tauri, and Electron

Use when: Building macOS native (SwiftUI/AppKit), Tauri (Rust + Web), or Electron (Node.js + Chromium) desktop apps Benefit: Platform-specific MCP integration, build/package automation, code signing and notarization workflows Setup: 5-10 minutes per platform (MCP installation + CLAUDE.md template)

14-webmcp

WebMCP — structured browser tools for AI agents (W3C Draft, Chrome 146 Canary)

  • guide.md - WebMCP integration guide
  • What WebMCP solves (89% token savings vs screenshot-based approaches)
  • WebMCP vs MCP comparison (frontend vs backend)
  • navigator.modelContext API reference with code examples
  • Implementation patterns (read-only, form actions, declarative HTML)
  • Integration with Chrome MCP and Playwright MCP
  • CLAUDE.md template for WebMCP-enabled projects
  • Current limitations and browser support matrix

Use when: Building web applications that AI agents will interact with Benefit: Structured tool access instead of DOM scraping; 89% token reduction Status: Early Preview — Chrome 146 Canary only, spec actively changing


13-security-hardening

Protect Claude Code workflows from MCP attacks, prompt injection, and accidental data loss

  • guide.md - Complete security hardening guide
  • MCP vetting checklist + community-vetted safe list
  • Known CVEs (2025-2026) with versions and mitigations
  • Prompt injection defense hooks (PreToolUse + PostToolUse)
  • 6 production safety rules with settings.json + hook implementations
  • permissions.deny hardening templates (global + project-level)
  • Agent Skills supply chain risks and scanning
  • hooks/ - Production hook library (actual scripts, copy-paste ready)
  • dangerous-actions-blocker.py — blocks rm -rf /-class commands in any spelling, force-push to main, DROP TABLE, over-broad pkill/killall, edits to key files
  • pre-commit-secrets.py — scans staged content for API keys / private keys / DB URLs before every git commit
  • block-interactive-sudo.py — refuses sudo that would hang on a password prompt
  • tests/ — two-sided matrices (must-block AND must-pass) · WHY.md — the failure behind each hook
  • README with settings.json wiring and the PreToolUse hook contract
  • Productivity hooks (package-version checker, session-start memory loader, shell-habits) live in 01-global-optimization/hooks/

Use when: Team environments, production codebases, regulated industries, before adding new MCP servers Benefit: Prevent data exfiltration, block destructive operations, audit MCP supply chain Time: 15-30 minutes for initial hardening; 5 minutes per new MCP added

16-autonomous-agents

Run Claude Code unattended — cron agents, heartbeat watchdogs, and session journaling

  • guide.md - Autonomous & scheduled agents guide
  • The three primitives: headless cron runs, /loop, and hooks — and when each applies
  • Daily journaling agent recipe (~120 production runs/month): idempotent in-place note editing, replace-vs-append sections, self-contained cron briefs
  • Heartbeat watchdog protocol: exact HEARTBEAT_OK token, 200-token failure budget, probe allowlist — born from sessions killed for drifting into investigations
  • Watchdog patterns: stall / token-runaway / repeated-action-loop detection
  • Anti-pattern table — each entry cost a real incident
  • heartbeat-template.md - Copy-paste HEARTBEAT protocol file
  • session-summary-hook.py - Stop hook: Haiku-summarized session entries appended to a daily note (~$0.001/session)

Use when: Scheduled health checks, automated journaling, any unattended Claude Code run Benefit: Agents that complete within budget instead of drifting; a daily work journal nobody has to write Time: 30-60 minutes for the first cron agent

17-mods

Claude Code mods (v2.1.287+) — TypeScript hooks inside the engine

  • guide.md - What mods can do that settings hooks cannot, anatomy, events and engine API, patterns that held up, testing
  • marketplace/ - Example marketplace ai-prompts-mods: 13 mods with tests — context-meter, cache-guard, spend-ledger, subagent-models, secret-redactor, ssh-guard, deploy-verify, ci-watch, cleanup-tracker, aside, fleet-status, lang-guard, company-hq

Use when: A policy must hold on every tool call or subagent spawn, output must be rewritten before the model sees it, or you want live UI (meters, panes, status) Benefit: Secrets out of transcripts, model routing that plugin updates cannot undo, cache and spend visible while you work Time: 10 minutes to install the set; 1-2 hours to write your first mod


🚀 Quick Start

First Time Setup (2-3 hours)

Option 1: Automated (Recommended)

# Navigate to Claude Code
cd ~/.claude

# Use the setup agent
# Copy contents of 01-global-optimization/setup-agent.md
# Paste into Claude Code conversation
# Agent will create all files automatically

Option 2: Manual

# Follow the step-by-step guide
# Read: 01-global-optimization/guide.md
# Create files as instructed
# Verify with: 01-global-optimization/checklist.md

Activate for Your Project (10-15 min)

# Navigate to your project
cd ~/projects/your-project

# Use the activation agent
# Copy contents of 02-project-activation/activation-agent.md
# Paste into Claude Code conversation
# Agent will activate Serena and create memories

Start Optimized Work

# In your project directory
/optimize "Your task here"

# Or use /init-project for new projects
/init-project --full

📊 Expected Outcomes

Token Reduction Targets

ScenarioBaselineOptimizedSavings
Simple task (bug fix)22,000 tokens1,600 tokens93%
Medium task (new feature)31,000 tokens8,500 tokens73%
Complex task (module creation)85,000 tokens18,000 tokens79%

Conservative target: 30-50% overall reduction Aggressive target: 50-70% with full optimization Maximum achieved: 80-90% with prompt caching on large contexts

Cost Savings

Per session (average medium task):

  • Baseline: $0.93 (31,000 tokens @ $3/M)
  • Optimized: $0.26 (8,500 tokens @ $3/M)
  • Savings: $0.67 per session (72%)

Monthly (30 sessions):

  • Baseline: $27.90
  • Optimized: $7.80
  • Savings: $20.10 per month

Annual (360 sessions):

  • Baseline: $334.80
  • Optimized: $93.60
  • Savings: $241.20 per year

Multiple projects (3 projects, 60 sessions/month):

  • Annual savings: $723.60

🛠️ What Gets Created

Global Files (in ~/.claude/)

Agents (orchestration):

  • agents/pm-orchestrator.md - Central coordinator
  • agents/plan-challenger.md - Adversarial plan review (Opus)
  • agents/output-evaluator.md - Code quality judge before commit (Haiku)
  • agents/loop-monitor.md - Autonomous session watchdog (Haiku)

Hooks (automation):

  • hooks/dangerous-actions-blocker.py - Blocks destructive commands and protected files
  • hooks/pre-commit-secrets.py - Scans staged files for API keys before commit
  • `hooks/block-interactive-sudo.p
Source 1 files
hooks/register.ts 172 lines
1import type { EngineInterface, Register } from 'claude-code'
2
3// Per-project spend, for a monthly "did the improvements pay off" review. Each
4// machine keeps its own ledger and exports ~/.claude/spend-ledger/<YYYY-MM>.json;
5// the machine with the Svod MCP connected pulls the others' files over ssh
6// (option remote_hosts) and writes one note per month.
7
8const cfg = { remotes: [] as string[], server: 'svod', vault: 'personal', dir: 'engineering/claude-spend' }
9const SYNC_EVERY_MS = 6 * 60 * 60_000
10
11export type Row = { turns: number; input: number; output: number; cacheRead: number; cacheWrite: number; usd: number }
12export type Agg = Record<string, Row> // key: `${day}|${project}|${model}`
13export type Export = { host: string; month: string; updated: string; agg: Agg }
14
15const empty = (): Row => ({ turns: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, usd: 0 })
16
17export const add = (a: Row, b: Row): Row => ({
18  turns: a.turns + b.turns, input: a.input + b.input, output: a.output + b.output,
19  cacheRead: a.cacheRead + b.cacheRead, cacheWrite: a.cacheWrite + b.cacheWrite, usd: a.usd + b.usd,
20})
21
22export const merge = (aggs: Agg[]): Agg => {
23  const out: Agg = {}
24  for (const agg of aggs) for (const [k, r] of Object.entries(agg)) out[k] = add(out[k] ?? empty(), r)
25  return out
26}
27
28// Sums rows by one key part: 0 = day, 1 = project, 2 = model.
29export const rollup = (agg: Agg, part: 0 | 1 | 2, since = ''): [string, Row][] => {
30  const out = new Map<string, Row>()
31  for (const [k, r] of Object.entries(agg)) {
32    const parts = k.split('|')
33    if ((parts[0] ?? '') < since) continue
34    const key = parts[part] ?? '?'
35    out.set(key, add(out.get(key) ?? empty(), r))
36  }
37  return [...out].sort((a, b) => b[1].usd - a[1].usd)
38}
39
40const k = (n: number) => (n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : `${Math.round(n / 1e3)}K`)
41
42export const table = (rows: [string, Row][], label: string): string => {
43  const total = rows.reduce((t, [, r]) => add(t, r), empty())
44  const lines = [`| ${label} | $ | ходове | in | out | cache read | cache write |`, '|---|---:|---:|---:|---:|---:|---:|']
45  for (const [name, r] of rows) lines.push(`| ${name} | ${r.usd.toFixed(2)} | ${r.turns} | ${k(r.input)} | ${k(r.output)} | ${k(r.cacheRead)} | ${k(r.cacheWrite)} |`)
46  lines.push(`| **общо** | **${total.usd.toFixed(2)}** | ${total.turns} | ${k(total.input)} | ${k(total.output)} | ${k(total.cacheRead)} | ${k(total.cacheWrite)} |`)
47  return lines.join('\n')
48}
49
50export const note = (month: string, exports: Export[]): string => {
51  const out = [
52    '---', 'type: Note', `title: Claude разход ${month}`, 'tags: [claude, metrics]', '---', '',
53    `# Claude разход ${month}`, '',
54    '_Пише се от мода spend-ledger. Цените са от /cost на Claude Code; подагентите са в хода, който ги е пуснал._', '',
55  ]
56  for (const e of exports) {
57    out.push(`## ${e.host}`, '', `_Обновено: ${e.updated}_`, '', table(rollup(e.agg, 1), 'проект'), '', table(rollup(e.agg, 2), 'модел'), '')
58  }
59  return out.join('\n')
60}
61
62const monthOf = (ms: number) => new Date(ms).toISOString().slice(0, 7)
63const dayOf = (ms: number) => new Date(ms).toISOString().slice(0, 10)
64
65async function localExport($: EngineInterface, host: string, month: string): Promise<Export> {
66  const keys = (await $.store.keys()).filter(key => key.startsWith(`m:${month}:`))
67  const aggs: Agg[] = []
68  for (const key of keys) aggs.push(((await $.store.get(key)) as Agg | undefined) ?? {})
69  return { host, month, updated: new Date(await $.clock.now()).toISOString().slice(0, 16).replace('T', ' '), agg: merge(aggs) }
70}
71
72async function svodCall($: EngineInterface, tool: string, args: Record<string, unknown>): Promise<Record<string, unknown> | undefined> {
73  const r = await $.mcp.call(cfg.server, tool, args)
74  const block = r.content.find(c => c.type === 'text') as { text?: string } | undefined
75  return block?.text ? (JSON.parse(block.text) as Record<string, unknown>) : undefined
76}
77
78async function syncSvod($: EngineInterface, host: string, month: string): Promise<string> {
79  const exports = [await localExport($, host, month)]
80  for (const remote of cfg.remotes) {
81    const ran = await $.process.run(['ssh', '-o', 'ConnectTimeout=8', '-o', 'BatchMode=yes', remote, `cat ~/.claude/spend-ledger/${month}.json`], { timeoutMs: 20_000 })
82    if (ran.exitCode !== 0) continue
83    try {
84      const e = JSON.parse(ran.stdout) as Export
85      if (e.host !== host) exports.push(e)
86    } catch { /* a half-written file: next sync */ }
87  }
88  const path = `${cfg.dir}/${month}.md`
89  const current = await svodCall($, 'read', { path, vault: cfg.vault })
90  const expectedRevision = current?.status === 'ok' ? (current.revision as string) : undefined
91  const written = await svodCall($, 'write', { path, vault: cfg.vault, content: note(month, exports), ...(expectedRevision ? { expectedRevision } : {}) })
92  return written?.status === 'ok' ? `Svod ${cfg.vault}/${path}: ${exports.map(e => e.host).join(', ')}` : `Svod write: ${JSON.stringify(written)?.slice(0, 200)}`
93}
94
95export const register: Register = (on, options) => {
96  const remotes = options.remote_hosts
97  cfg.remotes = Array.isArray(remotes) ? remotes.map(String).filter(Boolean) : typeof remotes === 'string' && remotes ? [remotes] : []
98  cfg.server = String(options.svod_server ?? cfg.server)
99  cfg.vault = String(options.svod_vault ?? cfg.vault)
100  cfg.dir = String(options.note_dir ?? cfg.dir)
101  let host = 'unknown'
102  let sessionKey = ''
103  let lastUsd = 0
104  let hasSvod = false
105
106  on('session.start', async ($, e, next) => {
107    host = (await $.process.run(['hostname', '-s'], { timeoutMs: 5000 })).stdout.trim() || 'unknown'
108    const usage = await $.session.usage()
109    sessionKey = String(usage.startedAt)
110    lastUsd = usage.cost?.usd ?? 0
111    await $.command.register({ name: 'spend', description: 'Claude spend on this machine by project and model', argumentHint: '[day|week|month|sync]', immediate: true })
112    try {
113      hasSvod = (await svodCall($, 'read', { path: 'Home', vault: cfg.vault })) !== undefined
114    } catch {
115      hasSvod = false
116    }
117    if (hasSvod) {
118      $.clock.every(SYNC_EVERY_MS, async () => {
119        await syncSvod($, host, monthOf(await $.clock.now()))
120      })
121    }
122    return next(e)
123  })
124
125  on('turn.complete', async ($, e, next) => {
126    const result = await next(e)
127    if (e.agentId !== undefined) return result
128    const now = await $.clock.now()
129    const usd = (await $.session.usage()).cost?.usd ?? lastUsd
130    const u = e.usage
131    const row: Row = {
132      turns: 1,
133      input: u?.input_tokens ?? 0,
134      output: u?.output_tokens ?? 0,
135      cacheRead: u?.cache_read_input_tokens ?? 0,
136      cacheWrite: u?.cache_creation_input_tokens ?? 0,
137      usd: Math.max(0, usd - lastUsd),
138    }
139    lastUsd = usd
140    const home = (await $.env.get('HOME')) ?? ''
141    const project = (await $.session.cwd()).replace(home, '~')
142    const month = monthOf(now)
143    const key = `m:${month}:${sessionKey}`
144    const agg = ((await $.store.get(key)) as Agg | undefined) ?? {}
145    const rk = `${dayOf(now)}|${project}|${u?.model ?? 'unknown'}`
146    agg[rk] = add(agg[rk] ?? empty(), row)
147    await $.store.set(key, agg)
148    if (home) await $.fs.write(`${home}/.claude/spend-ledger/${month}.json`, JSON.stringify(await localExport($, host, month)))
149    return result
150  }).catch(($, e, next) => next(e))
151
152  on('session.end', async ($, e, next) => {
153    if (hasSvod) await syncSvod($, host, monthOf(await $.clock.now())).catch(() => undefined)
154    return next(e)
155  })
156
157  on('command.run', { command: 'spend' }, async ($, e) => {
158    const arg = e.args.trim() || 'week'
159    const now = await $.clock.now()
160    if (arg === 'sync') {
161      if (!hasSvod) return { text: 'No Svod MCP on this machine; the laptop pulls this ledger on its own sync.' }
162      return { text: await syncSvod($, host, monthOf(now)) }
163    }
164    const days = arg === 'day' ? 1 : arg === 'month' ? 31 : 7
165    const since = dayOf(now - (days - 1) * 86_400_000)
166    const months = [...new Set([monthOf(now - (days - 1) * 86_400_000), monthOf(now)])]
167    const agg = merge(await Promise.all(months.map(async m => (await localExport($, host, m)).agg)))
168    if (Object.keys(agg).length === 0) return { text: 'Nothing recorded yet.' }
169    return { text: `${host}, since ${since}\n\n${table(rollup(agg, 1, since), 'проект')}\n\n${table(rollup(agg, 2, since), 'модел')}` }
170  })
171}
172