cheap-agent 0.0.0-stage → 1.0.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/LICENSE +95 -0
- package/README.md +151 -2
- package/dist/allow.js +53 -0
- package/dist/cleanup.js +177 -0
- package/dist/config.js +133 -0
- package/dist/consent.js +129 -0
- package/dist/credentials.js +37 -0
- package/dist/hook.js +263 -0
- package/dist/index.js +16 -0
- package/dist/install.js +74 -0
- package/dist/jobs.js +1170 -0
- package/dist/login.js +223 -0
- package/dist/opencode.js +258 -0
- package/dist/permissions.js +122 -0
- package/dist/plan.js +117 -0
- package/dist/platform.js +52 -0
- package/dist/report.js +178 -0
- package/dist/research.js +264 -0
- package/dist/routing.js +212 -0
- package/dist/rules.js +25 -0
- package/dist/server.js +203 -0
- package/dist/status.js +105 -0
- package/dist/verify.js +121 -0
- package/dist/worker.js +237 -0
- package/dist/workspace.js +278 -0
- package/package.json +53 -4
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/README.md +38 -0
- package/plugin/hooks/hooks.json +40 -0
- package/plugin/skills/allow/SKILL.md +11 -0
- package/plugin/skills/clean/SKILL.md +11 -0
- package/plugin/skills/hook/SKILL.md +11 -0
- package/plugin/skills/plan-writing/SKILL.md +72 -0
- package/plugin/skills/status/SKILL.md +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cheap-agent",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cut your Claude Code usage: Claude plans, a cheap model writes the code. One command to install.",
|
|
5
|
+
"license": "Elastic-2.0",
|
|
6
|
+
"author": "muaaz9329",
|
|
7
|
+
"homepage": "https://github.com/muaaz9329/cheap-ag#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/muaaz9329/cheap-ag.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/muaaz9329/cheap-ag/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"claude-code",
|
|
17
|
+
"claude",
|
|
18
|
+
"mcp",
|
|
19
|
+
"ai-agents",
|
|
20
|
+
"deepseek",
|
|
21
|
+
"openrouter",
|
|
22
|
+
"cost",
|
|
23
|
+
"delegation"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"cheapag": "dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"plugin",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20.11"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"pretest": "npm run build",
|
|
42
|
+
"test": "vitest run"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
46
|
+
"@opencode-ai/sdk": "1.19.0",
|
|
47
|
+
"opencode-ai": "1.19.0",
|
|
48
|
+
"zod": "^4.6.7"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^26.6.5",
|
|
52
|
+
"typescript": "^7.0.2",
|
|
53
|
+
"vitest": "^5.0.4"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cheapag",
|
|
3
|
+
"displayName": "Cheap Agent",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Claude plans and reviews while a cheaper model implements: the cheapag MCP server, the plan-writing skill, status, allow, hook and clean commands, and an opt-in edit guard.",
|
|
6
|
+
"author": { "name": "muaaz9329" },
|
|
7
|
+
"keywords": ["delegation", "opencode", "mcp", "cost"]
|
|
8
|
+
}
|
package/plugin/.mcp.json
ADDED
package/plugin/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Cheap Agent plugin for Claude Code
|
|
2
|
+
|
|
3
|
+
Gives Claude the Cheap Agent MCP server (`delegate`, `research`, `reply`, `jobs`, `land`), the plan-writing skill, `/cheapag:status`, and the user-only commands `/cheapag:allow`, `/cheapag:clean` and `/cheapag:hook`.
|
|
4
|
+
|
|
5
|
+
## Worker models
|
|
6
|
+
|
|
7
|
+
`npx cheap-agent login` asks which worker models to use, after the provider. Each preset picks the implement and escalation models for your provider (OpenCode Go, OpenRouter or DeepSeek):
|
|
8
|
+
|
|
9
|
+
- **cheapest**: the lowest worker spend. Claude takes over more often when the worker fails.
|
|
10
|
+
- **balanced** (the default): the preset the benchmark measured and recommends.
|
|
11
|
+
- **strongest**: the strongest cheap models, for when you would rather pay the worker than have Claude take over.
|
|
12
|
+
|
|
13
|
+
Measured on SWE-bench Verified (OpenRouter): Flash's worker cost is about $0.005 per easy task and $0.03 per hard one; GLM-5.3 costs about $0.06 on the hard ones, and there Claude used 1.5x fewer tokens than with Flash, because GLM-5.3's failures cost Claude less to recover from. On the hard tier alone GLM-5.3 showed no gain, so `balanced` keeps Flash everywhere and `strongest` (GLM-5.3 for every task) is opt-in. `cheapest` is the same as `balanced` today.
|
|
14
|
+
|
|
15
|
+
The choice goes into `models` in `~/.config/cheapag/config.json`. Run `npx cheap-agent login --preset <cheapest|balanced|strongest>` to switch without the prompts. `ping` and `cheapag status` show it as `preset=<name>`. For a finer choice, set `models` (`implement`, `research`, `escalation`, `fallback`, as full `provider/model` names) in a repo's `cheapag.json`, which overrides the user config, or in the user config itself; answering `custom` (or `--preset custom`) makes login leave it as you wrote it. Changing the models after `/cheapag:allow` makes the next job ask for it again, with the new list.
|
|
16
|
+
|
|
17
|
+
## What it costs to keep in context
|
|
18
|
+
|
|
19
|
+
Everything Claude Code loads at session start is sent again on every turn: the system prompt, tool definitions, every enabled skill's description, plugin instructions and CLAUDE.md. A bigger prefix means each turn costs more, and a prefix that changes between sessions is rewritten at full price instead of read from cache. Measured on a real machine (Claude Code 2.1.285), a session that only answers "OK" cost $0.10 with ~100 user plugins and skills enabled, against $0.02–0.04 with only what the task needs.
|
|
20
|
+
|
|
21
|
+
- **Disable plugins you are not using** (`/plugin` → disable). Each enabled plugin adds its skills and instructions to every turn of every session.
|
|
22
|
+
- **Mark skills you only call by name** with `disable-model-invocation: true` in their `SKILL.md` frontmatter. Their descriptions then stay out of the context. Cheap Agent's `allow`, `clean` and `hook` already do this.
|
|
23
|
+
- **Keep CLAUDE.md under ~200 lines.** It is part of every turn. Move rarely needed detail into files Claude reads on demand.
|
|
24
|
+
- **Pin the Claude Code version** (`DISABLE_AUTOUPDATER=1`) during long stretches of work. An update changes the system prompt, so the next session rewrites the whole cached prefix.
|
|
25
|
+
- **For scripted runs** (`claude -p`): `--setting-sources project` skips user plugins and settings, and `--exclude-dynamic-system-prompt-sections` keeps per-machine details (cwd, git status) out of the cached prefix. The `includeGitInstructions: false` setting drops the commit/PR boilerplate when the agent never commits.
|
|
26
|
+
|
|
27
|
+
`cheapag status` prints the prefix size of this repo's most recent Claude Code session, when its transcript is readable (`claude prefix: 18.4k tokens on the first turn …`). Under ~20k is lean; 40k+ usually means plugins or skills the work doesn't use.
|
|
28
|
+
|
|
29
|
+
## Sessions, `/clear` and the cache TTL
|
|
30
|
+
|
|
31
|
+
Claude Code caches the session prefix. Every turn that starts within the cache's lifetime reads it at a tenth of the input price, instead of writing it again at more than the input price. How you split work into sessions decides how often you pay the full write.
|
|
32
|
+
|
|
33
|
+
- **One session per block of work.** Starting a fresh `claude` for every small task writes the whole prefix each time. Inside a session it is written once and then read.
|
|
34
|
+
- **`/clear` between unrelated tasks.** It's free: the prefix stays cached, and only the conversation is dropped. It also keeps old, unrelated context from distracting Claude on the next task.
|
|
35
|
+
- **Pick the TTL for how you work.** The default 1-hour cache suits all-day work with pauses. For short bursts of back-to-back tasks, `CLAUDE_CODE_PROMPT_CACHE_TTL=5m` makes cache writes cheaper ($5 instead of $8 per million tokens on Opus), as long as you never idle more than five minutes. After a longer pause, the next turn rewrites the prefix.
|
|
36
|
+
- `cheapag status` shows the last session's cache use: `claude cache: 14 requests, 91% of input from cache, 1h TTL`. A low percentage on a long session means the prefix kept changing (plugins toggled, an update, idle gaps past the TTL).
|
|
37
|
+
|
|
38
|
+
On a Pro or Max plan these are dollar estimates at API prices. Anthropic says cached tokens count less toward plan limits, but publishes no ratio.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Cheap Agent: SessionStart adds a one-line pointer to the delegate tool; the edit guard (edits and Bash file writes) is off until /cheapag:hook on; after a cheapag FAIL or PARTIAL, Claude hands the step to a Sonnet subagent (or, with takeover: self, its own calls are capped at limits.takeover_calls), and after an OK it does not re-run tests. Shell tests keep both free (no npx) while unused.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "r=$(git rev-parse --show-toplevel 2>/dev/null) && { [ -f \"$r/.cheapag/hook.json\" ] || [ -f \"$r/.cheapag/hook/takeover\" ]; } && npx -y cheap-agent@1.0.0 hook guard; exit 0",
|
|
11
|
+
"timeout": 60
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"PostToolUse": [
|
|
17
|
+
{
|
|
18
|
+
"matcher": "mcp__.*cheapag__(delegate|jobs|reply|land)",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "npx -y cheap-agent@1.0.0 hook result; exit 0",
|
|
23
|
+
"timeout": 60
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"SessionStart": [
|
|
29
|
+
{
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "npx -y cheap-agent@1.0.0 hook context",
|
|
34
|
+
"timeout": 60
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: allow
|
|
3
|
+
description: Opt this repository in to sending code to Cheap Agent's worker models - all models, --zdr-only (zero-retention only), or --models provider/model,...
|
|
4
|
+
argument-hint: "[--zdr-only | --models provider/model,...]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
allowed-tools: Bash(npx -y cheap-agent@1.0.0 allow) Bash(npx -y cheap-agent@1.0.0 allow *)
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
!`npx -y cheap-agent@1.0.0 allow $ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
The developer ran this consent command themselves; its output is above. Report it in one line. Do not run `cheapag allow` or change consent in any other way.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clean
|
|
3
|
+
description: Remove Cheap Agent's old worktrees and job logs now; --all removes everything not in flight.
|
|
4
|
+
argument-hint: "[--all]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
allowed-tools: Bash(npx -y cheap-agent@1.0.0 clean) Bash(npx -y cheap-agent@1.0.0 clean *)
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
!`npx -y cheap-agent@1.0.0 clean $ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
Report the result above to the user in one or two lines.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hook
|
|
3
|
+
description: Turn Cheap Agent's edit guard on or off for this repo - when on, Claude's large edits (or a 3rd edit to one file in a turn) are denied and redirected to delegate.
|
|
4
|
+
argument-hint: "[on | off]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
allowed-tools: Bash(npx -y cheap-agent@1.0.0 hook) Bash(npx -y cheap-agent@1.0.0 hook *)
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
!`npx -y cheap-agent@1.0.0 hook $ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
The developer ran this command themselves; its output is above. Report it in one line. Do not turn the edit guard on or off in any other way.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-writing
|
|
3
|
+
description: Write or fix a Cheap Agent plan file before calling the cheapag delegate tool. Use when planning a change of more than ~20 lines or several files for the cheap worker, splitting work into steps, or after delegate rejects a plan.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Writing a Cheap Agent plan
|
|
7
|
+
|
|
8
|
+
The cheap worker sees the whole plan, then implements the steps you name in `delegate`. It works in an isolated copy of the repo and does only what a step says, so each step must stand on its own: exact files, what to build, and a check that proves it works.
|
|
9
|
+
|
|
10
|
+
Save plans under `.plan/` in the repository, e.g. `.plan/rate-limit.md` (the developer may read, edit or commit them). Pass the path relative to the repository root.
|
|
11
|
+
|
|
12
|
+
## Grammar
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
# <plan title> ← required, exactly one H1
|
|
16
|
+
<shared context, optional, ≤ ~15 lines>
|
|
17
|
+
## <id> <short title> ← id = integer or integer+letter (3, 3a)
|
|
18
|
+
files: <path>, <dir/>, ... ← required; scope + overlap key
|
|
19
|
+
do: <what to build; continuation lines indented 2+ spaces>
|
|
20
|
+
done-when: <condition>; <condition> ← required; `backticked` = executed
|
|
21
|
+
dont: <constraint>; <constraint>
|
|
22
|
+
needs: <step id>, ...
|
|
23
|
+
difficulty: easy | medium | hard ← picks the worker model; wins over delegate's
|
|
24
|
+
model: <model>
|
|
25
|
+
deps: <package@range> ← the step needs a new package
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Keys are lowercase, at the start of the line, never bullets (`- files:` is wrong). Continuation lines are indented 2+ spaces.
|
|
29
|
+
- In `done-when`, every `backticked` fragment is run as a shell command in the worker's copy and must exit 0. Put only commands in backticks; plain text is the worker's responsibility.
|
|
30
|
+
- Unknown keys (e.g. `api:`, `example:`) are passed to the worker as hints.
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- **Size:** one step ≈ under an hour of junior-developer work. Split anything bigger.
|
|
35
|
+
- **Checks:** give every step an executable `done-when` (a test command, a type check), not only prose. Name the one test file or test id the step concerns, never the whole suite.
|
|
36
|
+
- **Source:** put the user's request or the issue verbatim in the shared context, or pass it as `delegate(source=…)` (text or a file path): the worker checks your steps against it and reports where they disagree.
|
|
37
|
+
- **Scope:** `files:` lists every file or directory the step may touch, accurately. It also decides which steps can run in parallel.
|
|
38
|
+
- **Constraints:** add `dont:` for the mistakes you expect (new dependencies, touching auth, changing public APIs).
|
|
39
|
+
- **Grouping:** make independent steps separate comma groups so they run in parallel; use `needs:` when one step must land first.
|
|
40
|
+
- **Packages:** declare a new package with `deps:`; the worker cannot install packages itself.
|
|
41
|
+
- Share context once at the top (conventions, existing helpers to reuse) instead of repeating it per step.
|
|
42
|
+
|
|
43
|
+
## Example
|
|
44
|
+
|
|
45
|
+
```md
|
|
46
|
+
# Rate limiting for auth endpoints
|
|
47
|
+
Redis is already wired in src/lib/redis.ts. Keep middleware style consistent with src/middleware/*.
|
|
48
|
+
|
|
49
|
+
## 1 limiter lib
|
|
50
|
+
files: src/lib/rateLimit.ts, test/rateLimit.test.ts
|
|
51
|
+
do: sliding-window limiter `limit(key, max, windowSec) -> {allowed, retryAfter}` using redis ZSET.
|
|
52
|
+
done-when: `npm test -- rateLimit` passes; tests cover allow, block, window expiry
|
|
53
|
+
dont: add dependencies
|
|
54
|
+
|
|
55
|
+
## 2 wire into login
|
|
56
|
+
files: src/api/login.ts, src/middleware/, test/login.test.ts
|
|
57
|
+
do: 5 req/min per IP on POST /api/login; on block return 429 + Retry-After.
|
|
58
|
+
done-when: `npm test -- login` passes; new test: 6th request → 429
|
|
59
|
+
dont: touch auth/session logic
|
|
60
|
+
needs: 1
|
|
61
|
+
|
|
62
|
+
## 3 docs
|
|
63
|
+
files: docs/api.md
|
|
64
|
+
do: document the 429 response and Retry-After.
|
|
65
|
+
done-when: section "Rate limits" exists under /api/login
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Delegating it
|
|
69
|
+
|
|
70
|
+
- `steps="3"`: one step, one job. `steps="3-5"`: a range, run in order in one job. `steps="1-2,3"`: comma-separated groups, run in parallel unless their `files:` overlap or `needs:` orders them.
|
|
71
|
+
- `delegate(plan=".plan/rate-limit.md", steps="1-2,3")`
|
|
72
|
+
- `delegate(plan=".plan/rate-limit.md", steps="2", note="use the existing ipFrom(req) helper")`: a `note` is at most 300 characters, for one-off guidance.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: status
|
|
3
|
+
description: Show Cheap Agent's status for this repo - running jobs, recent results, consent, and tracked spend against OpenCode Go windows.
|
|
4
|
+
allowed-tools: Bash(npx -y cheap-agent@1.0.0 status)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
!`npx -y cheap-agent@1.0.0 status`
|
|
8
|
+
|
|
9
|
+
Show the status above to the user as is. Add a line only if something needs their action (a BLOCKED job to reply to, a missing consent, a Go window near its cap).
|