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 +18 -0
- package/README.md +77 -19
- package/bin/claudeboss.js +43 -13
- package/package.json +5 -3
- package/scripts/install-opencode.sh +2 -16
- package/scripts/run-task.js +113 -0
- package/scripts/select-model.sh +24 -18
- package/scripts/stats-report.js +61 -0
- package/skills/boss/SKILL.md +7 -1
- package/skills/plan/SKILL.md +33 -0
- package/skills/team/SKILL.md +1 -1
- package/scripts/claudeboss-run.sh +0 -30
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
|
-
|
|
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
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/claudeboss)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](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)
|
|
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
|
-
|
|
39
|
+
## The three modes
|
|
24
40
|
|
|
25
|
-
| Command | What it does |
|
|
26
|
-
|
|
27
|
-
| `/claudeboss:
|
|
28
|
-
| `/claudeboss:
|
|
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
|
-
##
|
|
47
|
+
## Track your own savings
|
|
31
48
|
|
|
32
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
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 —
|
|
54
|
-
-
|
|
55
|
-
- Free-tier model catalogs are provider-controlled and can shrink or
|
|
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
|
|
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
|
-
|
|
38
|
+
runShell('install-opencode.sh', rest);
|
|
16
39
|
break;
|
|
17
40
|
case 'model':
|
|
18
|
-
|
|
41
|
+
runShell('select-model.sh', rest);
|
|
19
42
|
break;
|
|
20
43
|
case 'run':
|
|
21
|
-
|
|
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
|
-
|
|
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.
|
|
4
|
-
"description": "
|
|
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
|
|
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:
|
|
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');
|
package/scripts/select-model.sh
CHANGED
|
@@ -18,34 +18,40 @@ if [ -z "$FREE_MODELS" ]; then
|
|
|
18
18
|
exit 1
|
|
19
19
|
fi
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
MODEL=$(pick "$kw")
|
|
36
|
-
[ -n "$MODEL" ] && break
|
|
37
|
-
done
|
|
46
|
+
KEYWORDS=(ultra nemotron gpt-oss-120b deepseek qwen3)
|
|
38
47
|
;;
|
|
39
48
|
*)
|
|
40
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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.)');
|
package/skills/boss/SKILL.md
CHANGED
|
@@ -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`.
|
package/skills/team/SKILL.md
CHANGED
|
@@ -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
|
|
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
|