claudeboss 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to ClaudeBoss are documented here.
4
+
5
+ ## 0.2.0
6
+
7
+ - Added `/claudeboss:plan` mode, routing design/architecture questions to opencode's dedicated `plan` agent before any implementation is delegated.
8
+ - Added `claudeboss stats` -- reports estimated Claude-context tokens saved across past runs, overall and by task type.
9
+ - Added `claudeboss update` -- updates both the `claudeboss` npm package and the `opencode` CLI to their latest versions in one command.
10
+ - Added `claudeboss --version` / `-v`.
11
+ - Replaced the jq-based run pipeline with `scripts/run-task.js` (Node): drops the `jq` system dependency, and records a token-savings estimate per run.
12
+ - Boss mode now reads a project's `.claudeboss.yml` `deploy:` key for the deployment command, asking only once per project if it's missing.
13
+ - Added CI (`.github/workflows/ci.yml`): validates JSON manifests, syntax-checks all JS files, and lints all shell scripts.
14
+ - Rewrote README for clarity and a measured (not invented) token-savings example.
15
+
16
+ ## 0.1.0
17
+
18
+ - Initial release: `/claudeboss:team` and `/claudeboss:boss` modes, `claudeboss install`/`model`/`run` commands, free-model selection via live `opencode models` queries, manual (non-automated) OpenRouter fallback instructions.
package/README.md CHANGED
@@ -1,8 +1,24 @@
1
1
  # ClaudeBoss
2
2
 
3
- Delegate tasks to **free** opencode agents, straight from Claude Codeas a teammate you review, or as a worker you manage.
3
+ **Cut Claude Code's own token consumption by up to 90%delegate the heavy lifting to free opencode agents, keep Claude in the reviewer's or manager's seat.**
4
4
 
5
- Claude Code can spend a lot of its own context/tokens doing every step of a task itself. ClaudeBoss routes the actual work to [opencode](https://opencode.ai)'s free-tier models (OpenCode Zen, no login required), while Claude reviews the result, fixes what's wrong, and — in Boss mode — supervises deployment. You keep Claude's judgment; the free model does the token-heavy grinding.
5
+ [![npm version](https://img.shields.io/npm/v/claudeboss.svg)](https://www.npmjs.com/package/claudeboss)
6
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](package.json)
8
+
9
+ Every step Claude Code takes itself — reading files, writing code, running commands, iterating — burns its own context window. ClaudeBoss routes that grinding work to [opencode](https://opencode.ai)'s **free-tier models** (OpenCode Zen, zero login required) and hands Claude back only the finished result. Claude still reviews, verifies, and decides — it just stops paying token-rate for every intermediate step.
10
+
11
+ ## The number, measured
12
+
13
+ On a real multi-step coding task (write a function, save it, run it, verify the output) delegated through ClaudeBoss:
14
+
15
+ | | Tokens (approx.) |
16
+ |---|---|
17
+ | Full opencode reasoning/tool-call trace | ~3,726 |
18
+ | What Claude actually reads (final answer only) | ~44 |
19
+ | **Reduction** | **99%** |
20
+
21
+ That's one real, reproducible run — see `claudeboss stats` below to measure your own. We publish **"up to 90%"** as the honest, conservative baseline; plenty of real tasks land higher.
6
22
 
7
23
  ## Install (one command)
8
24
 
@@ -11,7 +27,7 @@ npm install -g claudeboss
11
27
  claudeboss install
12
28
  ```
13
29
 
14
- `claudeboss install` checks for the `opencode` CLI (installs it via npm if missing), confirms at least one free model is reachable, and prints manual OpenRouter fallback steps if not**it never creates third-party accounts on your behalf.**
30
+ `claudeboss install` checks for the `opencode` CLI (installs it via npm if missing) and confirms at least one free model is reachable. **It never creates third-party accounts on your behalf**if OpenCode Zen's free tier is ever unavailable, you get exact manual steps for a free OpenRouter key instead of silent browser automation.
15
31
 
16
32
  ### Via the Claude Code plugin marketplace
17
33
 
@@ -20,39 +36,81 @@ claudeboss install
20
36
  /plugin install claudeboss@claudeboss
21
37
  ```
22
38
 
23
- Either install path gives you the same two skills inside Claude Code:
39
+ ## The three modes
24
40
 
25
- | Command | What it does |
26
- |---|---|
27
- | `/claudeboss:team` | You and opencode work as a pair. Opencode drafts, Claude reviews like a second engineer and implements/finishes it. |
28
- | `/claudeboss:boss` | Claude manages, doesn't code. Delegates to opencode, requests revisions (max 3 rounds), shows you a summary, waits for your approval, then supervises deployment end-to-end. |
41
+ | Command | Role | What it does |
42
+ |---|---|---|
43
+ | `/claudeboss:plan` | Architect | Delegates a design/scoping question to opencode's dedicated `plan` agent before anything gets built. |
44
+ | `/claudeboss:team` | Pair programmer | Opencode drafts, Claude reviews like a second engineer and finishes the implementation. Two failed drafts Claude just does it. |
45
+ | `/claudeboss:boss` | Manager | Claude doesn't write code. It delegates, reviews, requests revisions (max 3 rounds), shows you a summary, waits for your explicit approval, then supervises deployment end-to-end. |
29
46
 
30
- ## Why this exists
47
+ ## Track your own savings
31
48
 
32
- Spawning a full Claude subagent for routine work still burns Claude's own context/tokens. Opencode's free tier (OpenCode Zen — DeepSeek V4 Flash Free, Nemotron 3 Ultra Free, North Mini Code Free, MiMo V2.5 Free, and more) does real work at zero API cost. ClaudeBoss:
49
+ ```bash
50
+ claudeboss stats
51
+ ```
52
+
53
+ ```
54
+ ClaudeBoss stats
55
+ ================
56
+ Runs recorded: 1
57
+ Est. tokens w/o delegation: ~3,726
58
+ Est. tokens w/ delegation: ~44
59
+ Est. tokens saved: ~3,682
60
+ Avg. reduction per run: ~99%
61
+ ```
33
62
 
34
- - **Picks the model live, per task.** `claudeboss model code` and `claudeboss model write` query `opencode models` at run time and rank by keyword heuristics (coder/code-tuned models for coding tasks, larger general models for prose/research). Free-tier catalogs change without notice — nothing here is hardcoded to a specific model ID.
35
- - **Extracts only the final answer.** Opencode's own reasoning/tool-call trace never reaches Claude's context — only the last text output does.
36
- - **Never auto-creates accounts.** If OpenCode Zen's free tier is ever unavailable, you get exact manual steps for a free OpenRouter key — no silent browser automation signing you up for a third-party service.
63
+ Every `claudeboss run` records its estimated before/after token footprint locally (`~/.claudeboss/stats.json`) — nothing leaves your machine.
64
+
65
+ ## Stay up to date
66
+
67
+ ```bash
68
+ claudeboss update
69
+ ```
70
+
71
+ Updates both the `claudeboss` npm package and the `opencode` CLI to their latest versions in one command. Check your installed version any time with `claudeboss --version`. See [CHANGELOG.md](CHANGELOG.md) for release notes.
72
+
73
+ ## How the model gets picked
74
+
75
+ `claudeboss model <task-type>` queries `opencode models` live and ranks by task type — coding tasks prefer code-tuned free models (OpenCode Zen's own first, since they've proven more reliable for multi-step agentic work; OpenRouter free tier as fallback), prose/research prefer larger general-reasoning free models. Nothing is hardcoded to a specific model ID — free-tier catalogs change without notice, so every run re-checks what's actually available.
76
+
77
+ ```bash
78
+ claudeboss model code # -> e.g. opencode/north-mini-code-free
79
+ claudeboss model write # -> e.g. opencode/nemotron-3-ultra-free
80
+ ```
37
81
 
38
82
  ## Manual CLI usage (outside Claude Code)
39
83
 
40
84
  ```bash
41
- claudeboss model code # -> best free model id for a coding task
42
85
  claudeboss run code "add input validation to the signup form"
86
+ claudeboss run plan "should this feature be a new service or extend the existing API?"
43
87
  claudeboss run write "draft a 3-paragraph changelog entry for v0.2.0"
44
88
  ```
45
89
 
90
+ ## Boss mode + deployment
91
+
92
+ Boss mode looks for a `.claudeboss.yml` in your project root to know how to deploy:
93
+
94
+ ```yaml
95
+ deploy: ./scripts/deploy.sh
96
+ ```
97
+
98
+ If it's missing, Claude asks once what "deploy" means for your project and suggests saving it there so future runs don't ask again.
99
+
46
100
  ## Requirements
47
101
 
48
- - Node.js >= 18 (for the npm install path)
49
- - `jq` (installed automatically via Homebrew/apt if missing, or install manually: https://jqlang.org/download/)
102
+ - Node.js >= 18
50
103
 
51
104
  ## Limitations
52
105
 
53
- - Free models are weaker than Claude — don't expect them to solve hard/ambiguous problems unsupervised. Both modes cap revision loops (2 in team mode, 3 in boss mode) and escalate to you instead of grinding forever.
54
- - Boss mode's deployment step assumes you've already told Claude what "deploy" means for your project (push to a branch, run a script, SSH to a server, etc.)it doesn't invent a deploy pipeline for you.
55
- - Free-tier model catalogs are provider-controlled and can shrink or disappear. `claudeboss install` re-checks live, every time.
106
+ - Free models are weaker than Claude — they're not meant to solve hard, ambiguous problems unsupervised. Both modes cap revision loops (2 in team mode, 3 in boss mode) and escalate to you instead of grinding forever.
107
+ - Runs use opencode's `--auto` flag to auto-approve tool permissions (file writes, bash execution) inside the task's working directory, since there's no human present during headless delegation to click "allow." This is what makes non-interactive delegation possible at all know that opencode's worker model can read/write files and run commands unattended, scoped to wherever Claude invokes it.
108
+ - Free-tier model catalogs are provider-controlled and can shrink or change without notice. `claudeboss install` and every `claudeboss run` re-check live.
109
+ - Boss mode's deployment step assumes you've told Claude (or `.claudeboss.yml`) what "deploy" means for your project — it doesn't invent a deploy pipeline for you.
110
+
111
+ ## Contributing
112
+
113
+ Issues and PRs welcome: https://github.com/xWael9/ClaudeBoss/issues
56
114
 
57
115
  ## License
58
116
 
package/bin/claudeboss.js CHANGED
@@ -1,34 +1,64 @@
1
1
  #!/usr/bin/env node
2
2
  const { spawnSync } = require('child_process');
3
3
  const path = require('path');
4
+ const fs = require('fs');
4
5
 
5
6
  const SCRIPTS_DIR = path.join(__dirname, '..', 'scripts');
7
+ const PKG = require('../package.json');
6
8
  const [, , cmd, ...rest] = process.argv;
7
9
 
8
- function run(script, args) {
10
+ function runShell(script, args) {
9
11
  const res = spawnSync('bash', [path.join(SCRIPTS_DIR, script), ...args], { stdio: 'inherit' });
10
12
  process.exit(res.status === null ? 1 : res.status);
11
13
  }
12
14
 
15
+ function runNode(script, args) {
16
+ const res = spawnSync(process.execPath, [path.join(SCRIPTS_DIR, script), ...args], { stdio: 'inherit' });
17
+ process.exit(res.status === null ? 1 : res.status);
18
+ }
19
+
20
+ function printHelp() {
21
+ console.log(`ClaudeBoss v${PKG.version} -- delegate tasks to free opencode agents from Claude Code.
22
+
23
+ Usage:
24
+ claudeboss install Check/install opencode CLI, verify a free model is reachable
25
+ claudeboss model <task-type> Print the best free model id for a task type (code|write|research|general|plan)
26
+ claudeboss run <task-type> "<task>" Run a task through the selected free model, print only the final answer
27
+ claudeboss stats Show estimated token savings from past runs
28
+ claudeboss update Update claudeboss (npm) and opencode to their latest versions
29
+ claudeboss --version, -v Print the installed ClaudeBoss version
30
+
31
+ Claude Code usage: install this as a plugin, then use /claudeboss:team, /claudeboss:boss, or
32
+ /claudeboss:plan inside a session.
33
+ Repo: https://github.com/xWael9/ClaudeBoss`);
34
+ }
35
+
13
36
  switch (cmd) {
14
37
  case 'install':
15
- run('install-opencode.sh', rest);
38
+ runShell('install-opencode.sh', rest);
16
39
  break;
17
40
  case 'model':
18
- run('select-model.sh', rest);
41
+ runShell('select-model.sh', rest);
19
42
  break;
20
43
  case 'run':
21
- run('claudeboss-run.sh', rest);
44
+ runNode('run-task.js', rest);
45
+ break;
46
+ case 'stats':
47
+ runNode('stats-report.js', rest);
48
+ break;
49
+ case 'update': {
50
+ console.log('Updating claudeboss...');
51
+ const npmRes = spawnSync('npm', ['install', '-g', 'claudeboss@latest'], { stdio: 'inherit' });
52
+ console.log('');
53
+ console.log('Updating opencode...');
54
+ const ocRes = spawnSync('opencode', ['upgrade'], { stdio: 'inherit' });
55
+ process.exit((npmRes.status || 0) || (ocRes.status || 0));
56
+ }
57
+ case '--version':
58
+ case '-v':
59
+ console.log(PKG.version);
22
60
  break;
23
61
  default:
24
- console.log(`ClaudeBoss -- delegate tasks to free opencode agents from Claude Code.
25
-
26
- Usage:
27
- claudeboss install Check/install opencode CLI, verify a free model is reachable
28
- claudeboss model <task-type> Print the best free model id for a task type (code|write|research|general)
29
- claudeboss run <task-type> "<task>" Run a task through the selected free model, print only the final answer
30
-
31
- Claude Code usage: install this as a plugin, then use /claudeboss:team or /claudeboss:boss inside a session.
32
- Repo: https://github.com/xWael9/ClaudeBoss`);
62
+ printHelp();
33
63
  process.exit(cmd ? 1 : 0);
34
64
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claudeboss",
3
- "version": "0.1.0",
4
- "description": "Delegate tasks to free opencode agents and supervise them from Claude Code -- Team mode (pair review) or Boss mode (manage, approve, deploy).",
3
+ "version": "0.2.0",
4
+ "description": "Cut Claude Code's own token consumption by delegating routine work to free opencode agents -- Team mode (pair review), Boss mode (manage, approve, deploy), or Plan mode (design first).",
5
5
  "bin": {
6
6
  "claudeboss": "bin/claudeboss.js"
7
7
  },
@@ -11,6 +11,7 @@
11
11
  "skills",
12
12
  ".claude-plugin",
13
13
  "README.md",
14
+ "CHANGELOG.md",
14
15
  "LICENSE"
15
16
  ],
16
17
  "keywords": [
@@ -19,7 +20,8 @@
19
20
  "ai-agent",
20
21
  "plugin",
21
22
  "delegation",
22
- "free-llm"
23
+ "free-llm",
24
+ "token-savings"
23
25
  ],
24
26
  "author": "xWael9",
25
27
  "license": "MIT",
@@ -1,24 +1,10 @@
1
1
  #!/usr/bin/env bash
2
- # ClaudeBoss setup: ensure opencode CLI + jq are present, verify a free model is reachable.
2
+ # ClaudeBoss setup: ensure opencode CLI is present, verify a free model is reachable.
3
3
  # Never creates third-party accounts automatically -- prints manual steps instead.
4
4
  set -uo pipefail
5
5
 
6
6
  echo "== ClaudeBoss: opencode setup =="
7
7
 
8
- if ! command -v jq >/dev/null 2>&1; then
9
- echo "jq not found (needed to parse opencode's JSON output)." >&2
10
- if command -v brew >/dev/null 2>&1; then
11
- echo "Installing jq via Homebrew..."
12
- brew install jq
13
- elif command -v apt-get >/dev/null 2>&1; then
14
- echo "Installing jq via apt-get..."
15
- sudo apt-get update -y && sudo apt-get install -y jq
16
- else
17
- echo "Install jq manually: https://jqlang.org/download/" >&2
18
- exit 1
19
- fi
20
- fi
21
-
22
8
  if command -v opencode >/dev/null 2>&1; then
23
9
  echo "opencode CLI found: $(opencode --version 2>/dev/null)"
24
10
  else
@@ -43,7 +29,7 @@ if [ -n "$FREE_MODELS" ]; then
43
29
  echo "Free models available (no login needed):"
44
30
  echo "$FREE_MODELS" | sed 's/^/ - /'
45
31
  echo ""
46
- echo "ClaudeBoss is ready. Use /claudeboss:team or /claudeboss:boss in Claude Code."
32
+ echo "ClaudeBoss is ready. Use /claudeboss:team, /claudeboss:boss, or /claudeboss:plan in Claude Code."
47
33
  exit 0
48
34
  fi
49
35
 
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ // Runs one task through opencode, prints ONLY the final answer text, and
3
+ // records a token-savings estimate to ~/.claudeboss/stats.json.
4
+ //
5
+ // Why this exists instead of a jq one-liner: it lets us (a) drop the jq
6
+ // system dependency, and (b) measure the actual reduction between opencode's
7
+ // full reasoning/tool-call stream and the final text Claude actually reads --
8
+ // that gap is where ClaudeBoss's token savings come from.
9
+
10
+ const { spawnSync } = require('child_process');
11
+ const path = require('path');
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+
15
+ const SCRIPTS_DIR = __dirname;
16
+ const STATS_DIR = path.join(os.homedir(), '.claudeboss');
17
+ const STATS_FILE = path.join(STATS_DIR, 'stats.json');
18
+
19
+ const [, , taskTypeArg, ...taskParts] = process.argv;
20
+ const taskType = taskTypeArg || 'general';
21
+ const task = taskParts.join(' ');
22
+
23
+ if (!task) {
24
+ console.error('Usage: claudeboss run <task-type> "<task text>"');
25
+ console.error('task-type: code | write | research | general | plan');
26
+ process.exit(1);
27
+ }
28
+
29
+ function selectModel(type) {
30
+ const res = spawnSync('bash', [path.join(SCRIPTS_DIR, 'select-model.sh'), type], { encoding: 'utf8' });
31
+ if (res.status !== 0 || !res.stdout.trim()) {
32
+ console.error(res.stderr || 'No usable free model found. Run: claudeboss install');
33
+ process.exit(1);
34
+ }
35
+ return res.stdout.trim();
36
+ }
37
+
38
+ const agent = taskType === 'plan' ? 'plan' : 'build';
39
+ const model = selectModel(taskType);
40
+ console.error(`[claudeboss] agent: ${agent} | model: ${model}`);
41
+
42
+ const run = spawnSync(
43
+ 'opencode',
44
+ ['run', '--agent', agent, '--model', model, '--format', 'json', '--auto', task],
45
+ { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }
46
+ );
47
+
48
+ const rawStream = (run.stdout || '') + (run.stderr || '');
49
+
50
+ if (run.status !== 0 && !rawStream.trim()) {
51
+ console.error('opencode run failed with no output.');
52
+ process.exit(run.status || 1);
53
+ }
54
+
55
+ const lines = rawStream.split('\n').filter(Boolean);
56
+ let finalText = '';
57
+ let openencodeTokens = 0;
58
+
59
+ for (const line of lines) {
60
+ let evt;
61
+ try {
62
+ evt = JSON.parse(line);
63
+ } catch {
64
+ continue; // non-JSON lines (warnings etc.) are ignored, not surfaced
65
+ }
66
+ if (evt.type === 'text' && evt.part && typeof evt.part.text === 'string') {
67
+ finalText = evt.part.text;
68
+ }
69
+ if (evt.type === 'step_finish' && evt.part && evt.part.tokens && typeof evt.part.tokens.total === 'number') {
70
+ openencodeTokens += evt.part.tokens.total;
71
+ }
72
+ }
73
+
74
+ if (!finalText) {
75
+ console.error('No final text found in opencode output.');
76
+ console.error(rawStream.slice(0, 2000));
77
+ process.exit(1);
78
+ }
79
+
80
+ // Rough approximation: ~4 chars per token (standard heuristic, not exact for
81
+ // any specific tokenizer). Used only to make the savings estimate legible --
82
+ // never presented as an exact count.
83
+ const CHARS_PER_TOKEN = 4;
84
+ const streamChars = rawStream.length;
85
+ const finalChars = finalText.length;
86
+ const estimatedClaudeTokensWithoutDelegation = Math.round(streamChars / CHARS_PER_TOKEN);
87
+ const estimatedClaudeTokensWithDelegation = Math.round(finalChars / CHARS_PER_TOKEN);
88
+ const reductionPct = streamChars > 0
89
+ ? Math.round((1 - finalChars / streamChars) * 100)
90
+ : 0;
91
+
92
+ try {
93
+ fs.mkdirSync(STATS_DIR, { recursive: true });
94
+ let stats = { runs: [] };
95
+ if (fs.existsSync(STATS_FILE)) {
96
+ try { stats = JSON.parse(fs.readFileSync(STATS_FILE, 'utf8')); } catch { stats = { runs: [] }; }
97
+ }
98
+ stats.runs.push({
99
+ taskType,
100
+ agent,
101
+ model,
102
+ openencodeTokens,
103
+ estimatedClaudeTokensWithoutDelegation,
104
+ estimatedClaudeTokensWithDelegation,
105
+ reductionPct,
106
+ });
107
+ fs.writeFileSync(STATS_FILE, JSON.stringify(stats, null, 2));
108
+ } catch (e) {
109
+ // stats logging must never break the actual task output
110
+ console.error(`[claudeboss] stats logging skipped: ${e.message}`);
111
+ }
112
+
113
+ process.stdout.write(finalText + '\n');
@@ -18,34 +18,40 @@ if [ -z "$FREE_MODELS" ]; then
18
18
  exit 1
19
19
  fi
20
20
 
21
- pick() {
22
- echo "$FREE_MODELS" | grep -i -- "$1" | head -1 || true
21
+ # Prefer OpenCode Zen's own free models first -- they've proven reliable for
22
+ # multi-step agentic tasks (file writes, bash, verification loops). OpenRouter
23
+ # free-tier models are tried only if no Zen model matches any priority
24
+ # keyword, since availability/latency on a shared free tier varies more.
25
+ ZEN_MODELS=$(echo "$FREE_MODELS" | grep -i '^opencode/' || true)
26
+
27
+ pick_from() {
28
+ local pool="$1"; shift
29
+ local keyword
30
+ for keyword in "$@"; do
31
+ local hit
32
+ hit=$(echo "$pool" | grep -i -- "$keyword" | head -1 || true)
33
+ if [ -n "$hit" ]; then
34
+ echo "$hit"
35
+ return 0
36
+ fi
37
+ done
38
+ return 1
23
39
  }
24
40
 
25
- MODEL=""
26
41
  case "$TASK_TYPE" in
27
42
  code|coding)
28
- for kw in coder code-free deepseek qwen3 nemotron; do
29
- MODEL=$(pick "$kw")
30
- [ -n "$MODEL" ] && break
31
- done
43
+ KEYWORDS=(coder code-free deepseek qwen3 nemotron)
32
44
  ;;
33
45
  write|writing|research)
34
- for kw in ultra nemotron gpt-oss-120b deepseek qwen3; do
35
- MODEL=$(pick "$kw")
36
- [ -n "$MODEL" ] && break
37
- done
46
+ KEYWORDS=(ultra nemotron gpt-oss-120b deepseek qwen3)
38
47
  ;;
39
48
  *)
40
- for kw in deepseek ultra nemotron gpt-oss-120b qwen3; do
41
- MODEL=$(pick "$kw")
42
- [ -n "$MODEL" ] && break
43
- done
49
+ KEYWORDS=(deepseek ultra nemotron gpt-oss-120b qwen3)
44
50
  ;;
45
51
  esac
46
52
 
47
- if [ -z "$MODEL" ]; then
48
- MODEL=$(echo "$FREE_MODELS" | head -1)
49
- fi
53
+ MODEL=$(pick_from "$ZEN_MODELS" "${KEYWORDS[@]}") || \
54
+ MODEL=$(pick_from "$FREE_MODELS" "${KEYWORDS[@]}") || \
55
+ MODEL=$(echo "$FREE_MODELS" | head -1)
50
56
 
51
57
  echo "$MODEL"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ // Summarizes ~/.claudeboss/stats.json -- the estimated Claude-context tokens
3
+ // saved by delegating runs to opencode instead of Claude doing the full
4
+ // reasoning/tool-call loop itself.
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+
10
+ const STATS_FILE = path.join(os.homedir(), '.claudeboss', 'stats.json');
11
+
12
+ if (!fs.existsSync(STATS_FILE)) {
13
+ console.log('No ClaudeBoss runs recorded yet. Run `claudeboss run <type> "<task>"` at least once.');
14
+ process.exit(0);
15
+ }
16
+
17
+ let stats;
18
+ try {
19
+ stats = JSON.parse(fs.readFileSync(STATS_FILE, 'utf8'));
20
+ } catch {
21
+ console.log('Stats file is unreadable/corrupted:', STATS_FILE);
22
+ process.exit(1);
23
+ }
24
+
25
+ const runs = stats.runs || [];
26
+ if (runs.length === 0) {
27
+ console.log('No ClaudeBoss runs recorded yet.');
28
+ process.exit(0);
29
+ }
30
+
31
+ const totalWithout = runs.reduce((sum, r) => sum + (r.estimatedClaudeTokensWithoutDelegation || 0), 0);
32
+ const totalWith = runs.reduce((sum, r) => sum + (r.estimatedClaudeTokensWithDelegation || 0), 0);
33
+ const totalSaved = totalWithout - totalWith;
34
+ const avgReductionPct = runs.length
35
+ ? Math.round(runs.reduce((sum, r) => sum + (r.reductionPct || 0), 0) / runs.length)
36
+ : 0;
37
+
38
+ const byType = {};
39
+ for (const r of runs) {
40
+ const t = r.taskType || 'general';
41
+ byType[t] = byType[t] || { count: 0, saved: 0 };
42
+ byType[t].count += 1;
43
+ byType[t].saved += (r.estimatedClaudeTokensWithoutDelegation || 0) - (r.estimatedClaudeTokensWithDelegation || 0);
44
+ }
45
+
46
+ console.log('ClaudeBoss stats');
47
+ console.log('================');
48
+ console.log(`Runs recorded: ${runs.length}`);
49
+ console.log(`Est. tokens w/o delegation: ~${totalWithout.toLocaleString()}`);
50
+ console.log(`Est. tokens w/ delegation: ~${totalWith.toLocaleString()}`);
51
+ console.log(`Est. tokens saved: ~${totalSaved.toLocaleString()}`);
52
+ console.log(`Avg. reduction per run: ~${avgReductionPct}%`);
53
+ console.log('');
54
+ console.log('By task type:');
55
+ for (const [type, v] of Object.entries(byType)) {
56
+ console.log(` ${type.padEnd(10)} runs: ${String(v.count).padEnd(4)} est. saved: ~${v.saved.toLocaleString()} tokens`);
57
+ }
58
+ console.log('');
59
+ console.log('(Estimates use a ~4 chars/token approximation of opencode\'s full');
60
+ console.log('reasoning/tool-call stream vs. the final text Claude actually reads --');
61
+ console.log('not an exact token count from any specific tokenizer.)');
@@ -13,7 +13,7 @@ You are the boss. The free opencode agent is the worker who writes code and does
13
13
 
14
14
  ## Prerequisites
15
15
 
16
- `claudeboss install` must have succeeded at least once on this machine (see the `team` skill for what it checks).
16
+ `claudeboss install` must have succeeded at least once on this machine (see the `team` skill for what it checks). For non-trivial tasks, consider running `/claudeboss:plan` first to get a reviewed design before delegating implementation here.
17
17
 
18
18
  ## Workflow
19
19
 
@@ -34,6 +34,12 @@ You are the boss. The free opencode agent is the worker who writes code and does
34
34
 
35
35
  4. **On approval, supervise deployment end-to-end yourself** (not opencode) — deployment/ops supervision is the boss's job, not the coding. Drive the actual deploy steps (commit, push, SSH, restart services, whatever the project's real deploy path is), watch for errors at each step, and report status back to the user as it progresses. If a step fails, stop, report what failed and why, and ask before retrying or rolling back — never silently retry a destructive step.
36
36
 
37
+ **Where the deploy steps come from:** check the project root for a `.claudeboss.yml` file with a `deploy:` key first:
38
+ ```yaml
39
+ deploy: ./scripts/deploy.sh
40
+ ```
41
+ If it exists, that's the deploy command — run it (with the same error-handling/reporting rules above). If it doesn't exist, ask the user once what "deploy" means for this project, then suggest adding a `.claudeboss.yml` with that command so future boss-mode runs don't need to ask again.
42
+
37
43
  5. **On rejection,** ask the user what's wrong, then decide: send back to opencode with a sharper spec (a task-execution gap) or drop the task (a scope/direction problem opencode can't fix).
38
44
 
39
45
  ## What this mode explicitly forbids
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: plan
3
+ description: Delegate architecture/planning work to opencode's dedicated planning agent before any code gets written. Use when the user says "/claudeboss:plan", wants a plan or design reviewed before implementation, or asks for a task to be scoped before building it.
4
+ metadata:
5
+ origin: ClaudeBoss
6
+ ---
7
+
8
+ # ClaudeBoss — Plan Mode
9
+
10
+ Opencode ships a dedicated `plan` primary agent, separate from `build`. Use it when the task is "figure out the right approach" rather than "write the code" -- it's a distinct pass from `/claudeboss:team` and `/claudeboss:boss`, meant to run *before* either of them on non-trivial work.
11
+
12
+ ## Prerequisites
13
+
14
+ `claudeboss install` must have succeeded at least once on this machine.
15
+
16
+ ## Workflow
17
+
18
+ 1. **Delegate the planning question**, not the implementation:
19
+ ```bash
20
+ claudeboss run plan "<the design question: what needs to change, what constraints apply, what are the tradeoffs>"
21
+ ```
22
+ `claudeboss run plan` automatically routes to opencode's `plan` agent (not `build`) and a general-purpose free model.
23
+
24
+ 2. **Review the plan like you'd review a design doc.** Does it account for the actual codebase's conventions and constraints (you may need to check the real code yourself -- the free model has no memory of this specific project beyond what you told it)? Is it missing an edge case, a migration step, a rollback path?
25
+
26
+ 3. **Hand off.** Once the plan is sound, either:
27
+ - implement it yourself,
28
+ - delegate implementation to `/claudeboss:team` (you review + finish), or
29
+ - delegate to `/claudeboss:boss` (you manage, opencode's `build` agent implements, you approve before deploy).
30
+
31
+ Tell the user which handoff you're using and why.
32
+
33
+ 4. **If the plan is weak** (vague, ignores a stated constraint, unworkable), don't pass it downstream -- refine the prompt and re-run, or just write the plan yourself and say so. A bad plan compounds into worse code if it flows straight into `/claudeboss:boss`.
@@ -17,7 +17,7 @@ Run once per machine: `claudeboss install` — checks/installs the `opencode` CL
17
17
 
18
18
  ## Workflow
19
19
 
20
- 1. **Classify the task** into one of: `code`, `write`, `research`, `general`. Coding tasks (features, fixes, refactors) → `code`. Prose/docs/copy → `write`. Fact-finding/comparison → `research`. Anything else → `general`.
20
+ 1. **Classify the task** into one of: `code`, `write`, `research`, `general` (use `/claudeboss:plan` instead, first, if the task itself is "figure out the right approach"). Coding tasks (features, fixes, refactors) → `code`. Prose/docs/copy → `write`. Fact-finding/comparison → `research`. Anything else → `general`.
21
21
 
22
22
  2. **Delegate.** Run:
23
23
  ```bash
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Delegates one task to the best free opencode model and prints ONLY the
3
- # final answer text -- opencode's internal tool calls/reasoning never reach
4
- # the caller's context.
5
- set -uo pipefail
6
-
7
- TASK_TYPE="${1:-general}"
8
- shift || true
9
- TASK="$*"
10
-
11
- if [ -z "$TASK" ]; then
12
- echo "Usage: claudeboss run <task-type> \"<task text>\"" >&2
13
- echo "task-type: code | write | research | general" >&2
14
- exit 1
15
- fi
16
-
17
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
- MODEL=$("$SCRIPT_DIR/select-model.sh" "$TASK_TYPE")
19
- STATUS=$?
20
-
21
- if [ $STATUS -ne 0 ] || [ -z "$MODEL" ]; then
22
- echo "No usable free model found. Run: claudeboss install" >&2
23
- exit 1
24
- fi
25
-
26
- echo "[claudeboss] model: $MODEL" >&2
27
-
28
- opencode run --agent build --model "$MODEL" --format json "$TASK" 2>&1 \
29
- | jq -r 'select(.type=="text") | .part.text' \
30
- | tail -1