catherd-cli 0.2.0 → 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/README.md +114 -30
- package/THIRD_PARTY_NOTICES.md +37 -0
- package/catalog/jev.json +89 -0
- package/catalog/models.json +236 -0
- package/catalog/scores.json +366 -0
- package/package.json +24 -8
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.mcp.json +1 -1
- package/plugin/commands/catherd.md +1 -1
- package/plugin/skills/catherd/SKILL.md +97 -51
- package/plugin/skills/catherd-setup/SKILL.md +34 -24
- package/src/adapters/all.ts +8 -0
- package/src/adapters/backend.ts +144 -0
- package/src/adapters/claude-code/events.ts +86 -0
- package/src/adapters/claude-code/index.ts +223 -0
- package/src/adapters/claude-code/models-api.ts +65 -0
- package/src/adapters/claude-code/models.ts +26 -0
- package/src/adapters/cli.ts +74 -0
- package/src/adapters/codex/events.ts +65 -0
- package/src/adapters/codex/home.ts +47 -0
- package/src/adapters/codex/index.ts +227 -0
- package/src/adapters/discovery.ts +87 -0
- package/src/adapters/opencode/agents.ts +84 -0
- package/src/adapters/opencode/events.ts +109 -0
- package/src/adapters/opencode/index.ts +316 -0
- package/src/adapters/registry.ts +14 -0
- package/src/cli.ts +159 -19
- package/src/domain/agents.ts +60 -0
- package/src/domain/budget.ts +45 -0
- package/src/domain/catalog.ts +262 -0
- package/src/domain/changes.ts +52 -0
- package/src/domain/cost.ts +89 -0
- package/src/domain/errors.ts +58 -0
- package/src/domain/hints.ts +22 -0
- package/src/domain/ids.ts +97 -0
- package/src/domain/jev.ts +283 -0
- package/src/domain/lane.ts +69 -0
- package/src/domain/profile-rules.ts +205 -0
- package/src/domain/profile.ts +383 -0
- package/src/domain/record.ts +84 -0
- package/src/{profile → domain}/role-prompts.ts +42 -25
- package/src/domain/roles.ts +25 -0
- package/src/domain/route.ts +126 -0
- package/src/domain/runtime.ts +21 -0
- package/src/domain/sanitize.ts +29 -0
- package/src/domain/secrets.ts +57 -0
- package/src/domain/select.ts +136 -0
- package/src/domain/state.ts +33 -0
- package/src/domain/util.ts +18 -0
- package/src/entry/capture-fixtures-command.ts +57 -0
- package/src/entry/catalog-command.ts +106 -0
- package/src/entry/cli-kit.ts +36 -0
- package/src/entry/deps.ts +16 -0
- package/src/entry/doctor-command.ts +45 -0
- package/src/entry/glyphs.ts +33 -0
- package/src/entry/init-command.ts +142 -0
- package/src/entry/lock-command.ts +123 -0
- package/src/entry/mcp/dispatch-tools.ts +82 -0
- package/src/entry/mcp/handshake.ts +48 -0
- package/src/entry/mcp/lane-tools.ts +83 -0
- package/src/entry/mcp/result.ts +51 -0
- package/src/entry/mcp/run-tools.ts +144 -0
- package/src/entry/mcp/server.ts +72 -0
- package/src/entry/mcp/setup-tools.ts +81 -0
- package/src/entry/profile-command.ts +320 -0
- package/src/entry/prompt.ts +103 -0
- package/src/entry/runs-command.ts +217 -0
- package/src/entry/supervise-bin.ts +18 -0
- package/src/entry/supervise-command.ts +37 -0
- package/src/entry/tui/commands.ts +545 -0
- package/src/entry/tui/effects.ts +270 -0
- package/src/entry/tui/fixtures.ts +318 -0
- package/src/entry/tui/profile-edits.ts +138 -0
- package/src/entry/tui/profile-tree.ts +419 -0
- package/src/entry/tui/providers/app.tsx +162 -0
- package/src/entry/tui/providers/boundary.tsx +57 -0
- package/src/entry/tui/providers/data.tsx +133 -0
- package/src/entry/tui/providers/keymap.tsx +166 -0
- package/src/entry/tui/providers/root.tsx +45 -0
- package/src/entry/tui/providers/theme.tsx +17 -0
- package/src/entry/tui/providers/toast.tsx +77 -0
- package/src/entry/tui/run.tsx +98 -0
- package/src/entry/tui/state.ts +336 -0
- package/src/entry/tui/stories.ts +75 -0
- package/src/entry/tui/text.ts +118 -0
- package/src/entry/tui/theme.ts +139 -0
- package/src/entry/tui/views/app.tsx +208 -0
- package/src/entry/tui/views/dialogs.tsx +41 -0
- package/src/entry/tui/views/profile-actions.ts +321 -0
- package/src/entry/tui/views/profiles.tsx +440 -0
- package/src/entry/tui/views/runs.tsx +281 -0
- package/src/entry/tui/views/save-dialog.tsx +332 -0
- package/src/entry/tui/views/status.tsx +206 -0
- package/src/entry/tui/widgets/chrome.tsx +114 -0
- package/src/entry/tui/widgets/dialog-confirm.tsx +58 -0
- package/src/entry/tui/widgets/dialog-prompt.tsx +52 -0
- package/src/entry/tui/widgets/dialog-select.tsx +212 -0
- package/src/entry/tui/widgets/dialog.tsx +68 -0
- package/src/entry/tui/widgets/line.tsx +92 -0
- package/src/entry/tui/widgets/list.tsx +196 -0
- package/src/entry/tui/widgets/spinner.tsx +49 -0
- package/src/entry/tui/widgets/toast.tsx +62 -0
- package/src/infra/assets.ts +4 -0
- package/src/infra/dispatch-dir.ts +278 -0
- package/src/infra/env.ts +43 -0
- package/src/infra/filelock.ts +159 -0
- package/src/infra/git.ts +91 -0
- package/src/infra/heavy-lock.ts +36 -0
- package/src/infra/jev-client.ts +162 -0
- package/src/infra/launch.ts +25 -0
- package/src/infra/log.ts +84 -0
- package/src/infra/paths.ts +38 -0
- package/src/infra/proc.ts +110 -0
- package/src/infra/store.ts +229 -0
- package/src/infra/supervisor.ts +257 -0
- package/src/infra/version.ts +6 -0
- package/src/services/admission.ts +277 -0
- package/src/services/agent-links.ts +139 -0
- package/src/services/backends.ts +44 -0
- package/src/services/budget.ts +47 -0
- package/src/services/capture.ts +233 -0
- package/src/services/catalog-service.ts +382 -0
- package/src/services/dispatch-service.ts +479 -0
- package/src/services/dispatches.ts +145 -0
- package/src/services/doctor-backends.ts +185 -0
- package/src/services/doctor-checks.ts +103 -0
- package/src/services/doctor.ts +358 -0
- package/src/services/finalize.ts +359 -0
- package/src/services/jev-service.ts +183 -0
- package/src/services/lane-service.ts +248 -0
- package/src/services/ports.ts +132 -0
- package/src/services/preflight.ts +207 -0
- package/src/services/profile-service.ts +292 -0
- package/src/services/profile-store.ts +141 -0
- package/src/services/reconcile.ts +101 -0
- package/src/services/routing-service.ts +190 -0
- package/src/services/run-debug.ts +79 -0
- package/src/services/run-service.ts +161 -0
- package/src/services/run-store.ts +316 -0
- package/src/services/setup.ts +87 -0
- package/src/services/state.ts +104 -0
- package/src/services/summary.ts +227 -0
- package/catalog/catalog.json +0 -112
- package/catalog/models-dev.json +0 -56453
- package/src/core/codex-events.ts +0 -49
- package/src/core/codex.ts +0 -166
- package/src/core/harness.ts +0 -89
- package/src/core/lanes.ts +0 -67
- package/src/core/lock.ts +0 -111
- package/src/core/opencode.ts +0 -207
- package/src/core/reconcile.ts +0 -26
- package/src/core/reply.ts +0 -54
- package/src/core/runstore.ts +0 -163
- package/src/core/spawn.ts +0 -89
- package/src/core/status.ts +0 -193
- package/src/files.ts +0 -19
- package/src/mcp/dispatch.ts +0 -154
- package/src/mcp/lane-tools.ts +0 -200
- package/src/mcp/out.ts +0 -6
- package/src/mcp/preflight.ts +0 -69
- package/src/mcp/run-tools.ts +0 -121
- package/src/mcp/runs.ts +0 -118
- package/src/mcp/server.ts +0 -26
- package/src/mcp/setup-tools.ts +0 -175
- package/src/paths.ts +0 -20
- package/src/profile/agents.ts +0 -130
- package/src/profile/profile.ts +0 -228
- package/src/routing/catalog.ts +0 -227
- package/src/routing/commands.ts +0 -22
- package/src/routing/jev.ts +0 -185
- package/src/routing/route.ts +0 -155
- package/src/routing/select.ts +0 -90
- package/src/tui/backends.ts +0 -57
- package/src/tui/commands.ts +0 -53
- package/src/tui/dashboard.tsx +0 -245
- package/src/tui/editor.tsx +0 -214
- package/src/tui/init.tsx +0 -208
- package/src/tui/matrix-model.ts +0 -279
- package/src/tui/matrix.tsx +0 -512
- package/src/tui/profiles.ts +0 -38
- package/src/tui/theme.ts +0 -177
- package/src/tui/ui.tsx +0 -267
- package/src/tui/watch-model.ts +0 -83
- package/src/tui/watch.tsx +0 -236
- package/src/types.ts +0 -184
- package/src/version.ts +0 -7
- /package/src/{mcp/commands.ts → entry/mcp/command.ts} +0 -0
package/README.md
CHANGED
|
@@ -6,27 +6,34 @@
|
|
|
6
6
|
(")(")
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Autopilot builds from your own Claude Code session. Claude plans and verifies, Codex
|
|
10
|
-
workers write the code, and [Jev](https://typesafe.ai) picks the model and effort for each piece
|
|
9
|
+
Autopilot builds from your own Claude Code session. Claude plans and verifies, Codex, opencode or
|
|
10
|
+
headless Claude Code workers write the code, and [Jev](https://typesafe.ai) picks the model and effort for each piece
|
|
11
11
|
of work, climbing a ladder only when a cheaper rung falls short.
|
|
12
12
|
|
|
13
13
|
- **Your harness, as you set it up.** Every role runs in its vendor's own CLI with your config,
|
|
14
14
|
hooks, skills and `AGENTS.md`. Isolation is an opt-in toggle per profile and harness, for when
|
|
15
15
|
you'd rather save the tokens your customizations cost.
|
|
16
|
-
- **Claude roles stay native.**
|
|
17
|
-
opencode run through catherd's MCP server.
|
|
16
|
+
- **Claude roles stay native.** `claude:` rungs run as ordinary Claude Code subagents; Codex,
|
|
17
|
+
opencode and headless `claude-code:` rungs run through catherd's MCP server.
|
|
18
18
|
- **Survives restarts.** Workers are detached processes writing straight to disk, so a dropped
|
|
19
19
|
MCP server never loses a run.
|
|
20
|
-
- **Guard rails for autopilot.** Quota failover to another
|
|
20
|
+
- **Guard rails for autopilot.** Quota failover to a rung on another quota, a preflight check before any
|
|
21
21
|
worker starts, per-repo knowledge carried between runs, and a run budget.
|
|
22
22
|
|
|
23
23
|
## Requirements
|
|
24
24
|
|
|
25
25
|
- [Bun](https://bun.sh) ≥ 1.4
|
|
26
26
|
- [Claude Code](https://claude.com/claude-code) (desktop app or CLI)
|
|
27
|
-
- At least one worker backend
|
|
28
|
-
[
|
|
29
|
-
-
|
|
27
|
+
- At least one worker backend, logged in:
|
|
28
|
+
- [Codex CLI](https://github.com/openai/codex) 0.157.0 or newer
|
|
29
|
+
- [opencode](https://opencode.ai) **v2**, 2.0.16 or newer: `curl -fsSL https://opencode.ai/v2/install | bash`
|
|
30
|
+
(the npm package `opencode-ai` is v1 and is not supported)
|
|
31
|
+
- Claude Code's `claude` CLI 2.1.282 or newer, for headless `claude-code:` rungs
|
|
32
|
+
- Optional: a TypeSafe API key for Jev, in `TYPESAFE_API_KEY` or saved by `catherd init`
|
|
33
|
+
|
|
34
|
+
`catherd doctor` checks each backend's version and login and prints the fix for anything missing. The default
|
|
35
|
+
profile runs its workers on Codex; without Codex, doctor's fix also names how to move those roles to a backend
|
|
36
|
+
you have (`/catherd-setup` in Claude Code, or `catherd profile set roles.<role>.rungs <rung>`).
|
|
30
37
|
|
|
31
38
|
## Install
|
|
32
39
|
|
|
@@ -34,15 +41,18 @@ of work, climbing a ladder only when a cheaper rung falls short.
|
|
|
34
41
|
bunx catherd-cli init
|
|
35
42
|
```
|
|
36
43
|
|
|
37
|
-
The npm package is `catherd-cli`; the command it installs is `catherd`. `init` asks for the Jev key,
|
|
38
|
-
|
|
44
|
+
The npm package is `catherd-cli`; the command it installs is `catherd`. `init` asks for the optional Jev key,
|
|
45
|
+
writes the default profile and links its Claude agents, lists your backends' models, and ends with a readiness
|
|
46
|
+
report (`--no-input` asks nothing and keeps what exists; `--profile <name>` sets up and activates that profile
|
|
47
|
+
instead of `default`; piped, it reads one answer per line once stdin closes: the Jev key, the profile, whether to replace it, each on its own line even when a question is skipped). Then add the plugin to Claude Code:
|
|
39
48
|
|
|
40
49
|
```sh
|
|
41
50
|
claude plugin marketplace add 47vigen/catherd
|
|
42
51
|
claude plugin install catherd@catherd
|
|
43
52
|
```
|
|
44
53
|
|
|
45
|
-
Start a new Claude Code session so the plugin, its MCP server and the agent files load
|
|
54
|
+
Start a new Claude Code session so the plugin, its MCP server and the agent files load, then check with
|
|
55
|
+
`bunx catherd-cli doctor`.
|
|
46
56
|
|
|
47
57
|
## Use
|
|
48
58
|
|
|
@@ -54,29 +64,103 @@ In Claude Code:
|
|
|
54
64
|
|
|
55
65
|
In a terminal:
|
|
56
66
|
|
|
57
|
-
| Command
|
|
58
|
-
|
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
| Command | What it does |
|
|
68
|
+
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
69
|
+
| `catherd` | The dashboard: Status, Profiles and Runs (below) |
|
|
70
|
+
| `catherd init [--no-input] [--profile <p>]` | First-run setup |
|
|
71
|
+
| `catherd doctor [--json]` | Readiness report, one row per check with its fix; exits 3 when not ready |
|
|
72
|
+
| `catherd profile list\|show\|use [--repo]\|new [--from <p>]\|copy\|rm\|diff\|validate` | Profiles; `use --repo` binds one to the repo you are in |
|
|
73
|
+
| `catherd profile use --repo --clear` | Unbinds the repo you are in; it runs on the active profile again |
|
|
74
|
+
| `catherd profile set <path> <value> [--profile <p>]` | One field, e.g. `roles.verifier.access read-only`, `budget.usd 20` |
|
|
75
|
+
| `catherd status [run]`, `catherd watch [--once] [--interval <s>]` | Where runs stand |
|
|
76
|
+
| `catherd runs list [--repo <path>]\|show <id> [--debug [--name <n>]]\|cancel <id> <name>` | Past runs; `--debug` adds exit.json and the stderr and event tails, `--name` one role's |
|
|
77
|
+
| `catherd catalog refresh\|list [--backend <b>] [--role <r>] [--text <t>] [--scored]` | The models catherd can place, filtered |
|
|
78
|
+
| `catherd catalog treat-like <rung> <like>` | Scores an unscored rung as a scored one |
|
|
79
|
+
| `catherd lock [--slots N] -- <cmd>` | Runs a heavy command behind the machine-wide semaphore, in its own session (no /dev/tty) |
|
|
80
|
+
| `catherd mcp` | The MCP server on stdio; the plugin starts it, you never need to |
|
|
81
|
+
| `catherd capture-fixtures [--backend <b>] [--out <dir>]` | Contributors: records sanitized test fixtures from real runs (see CONTRIBUTING.md) |
|
|
82
|
+
|
|
83
|
+
A profile command without a profile name (`show`, `set`, `diff`, `validate`), like the MCP profile tools, acts
|
|
84
|
+
on the profile the repo you are in runs on: the one bound to it, else the active one. Run them as
|
|
85
|
+
`bunx catherd-cli <command>` when catherd is not installed globally. Every read command takes `--json`; a bare `catherd runs` is `catherd runs list`. Exit codes: 0 ok, 1 error, 2 usage, 3 not ready, 130 interrupted; an error prints
|
|
86
|
+
`error E_CODE: message` and a `fix:` line. `--verbose` (or `CATHERD_LOG=debug`) logs more to
|
|
87
|
+
`~/.local/share/catherd/logs/`, kept for 7 days with secrets redacted. The dashboard takes `--plain` (ASCII, no colour)
|
|
88
|
+
and `--reduced-motion`; `doctor` and `init` take `--plain` for ASCII glyphs too. `NO_COLOR` drops colour, never glyphs.
|
|
65
89
|
|
|
66
90
|
Run data lives in `~/.local/share/catherd/`, config in `~/.config/catherd/` (both follow
|
|
67
91
|
`XDG_*`).
|
|
68
92
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`
|
|
93
|
+
### Environment variables
|
|
94
|
+
|
|
95
|
+
| Variable | What it does |
|
|
96
|
+
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| `TYPESAFE_API_KEY` | The Jev key, instead of the one `catherd init` saves |
|
|
98
|
+
| `CATHERD_HOME` | Puts config and data under `$CATHERD_HOME/config` and `$CATHERD_HOME/data` instead of XDG |
|
|
99
|
+
| `CATHERD_LOG` | Log level: `off`, `error`, `warn`, `info` (default) or `debug` (what `--verbose` sets) |
|
|
100
|
+
| `CATHERD_LOCK_SLOTS` | `catherd lock`'s slot count when `--slots` is not given (before the profile's `lock.heavy`) |
|
|
101
|
+
| `CATHERD_REDUCED_MOTION` | Any value: the dashboard's `--reduced-motion` |
|
|
102
|
+
| `CATHERD_NO_KITTY` | Any value: turns off the kitty keyboard protocol in the dashboard, for terminals it breaks |
|
|
103
|
+
| `CATHERD_CLAUDE_AGENTS_DIR` | Where catherd links its Claude agents (default: `$CLAUDE_CONFIG_DIR/agents`, else `~/.claude/agents`) |
|
|
104
|
+
| `NO_COLOR` | Drops colour (the dashboard's and `--help`'s; piped `--help` has none either) |
|
|
105
|
+
|
|
106
|
+
For development only: `CATHERD_STORY=1` opens the dashboard's storybook, `CATHERD_TICK_MS` sets how often a blocked
|
|
107
|
+
`wait` reports progress (default 30000), and `CATHERD_LIVE=1` enables the live tests
|
|
108
|
+
(CONTRIBUTING.md has the rest).
|
|
109
|
+
|
|
110
|
+
### The dashboard
|
|
111
|
+
|
|
112
|
+
`catherd` opens three tabs: **1 Status** (every check with its fix; `y` copies the fix, `r` checks again),
|
|
113
|
+
**2 Profiles** (one tree per profile: roles with their access, default rung, models and efforts, then routing,
|
|
114
|
+
harness, budget, failover, timeouts and notify) and **3 Runs** (live roles, climbs, routes, the budget, landed
|
|
115
|
+
milestones; `p` pauses). `catherd watch` opens it on Runs.
|
|
116
|
+
|
|
117
|
+
- `ctrl+p` lists every command with its key and CLI twin; `?` lists the keys that work where you are.
|
|
118
|
+
- `ctrl+x` is the leader: `ctrl+x 1`–`3` tabs, `ctrl+x n` new profile, `ctrl+x l` profiles, `ctrl+x u` and
|
|
119
|
+
`ctrl+x r` undo and redo, `ctrl+x q` quit.
|
|
120
|
+
- Lists: arrows or `j`/`k`, `pgup`/`pgdn`, `home`/`g`, `end`/`G`, `/` to filter; `space` ticks, `enter`
|
|
121
|
+
changes or opens, `→`/`←` expand and collapse.
|
|
122
|
+
- Edits are staged: nothing is written until `ctrl+s` shows the diff and you choose Save or Save & make active.
|
|
123
|
+
`enter` never saves.
|
|
124
|
+
- Inside a repo bound to a profile, the dashboard opens on that profile, and making a profile active binds the
|
|
125
|
+
repo to it (as `catherd profile use <name> --repo`).
|
|
126
|
+
- `esc` backs out one level and never quits. `q` quits, asking first if something is unsaved; `ctrl+c` quits
|
|
127
|
+
when nothing is, and pressed twice within 1.5 s discards and exits 130.
|
|
128
|
+
- Deleting a profile or cancelling a live role takes `ctrl+d` twice.
|
|
129
|
+
- `--plain` draws ASCII without colour, `NO_COLOR` drops the colour, `--reduced-motion` stops the spinner.
|
|
130
|
+
- Rebind a key in `~/.config/catherd/config.json`: `"keybinds": { "profile.save": "ctrl+w", "app.help": "none" }`
|
|
131
|
+
(the palette shows each command by title; the ids are listed in
|
|
132
|
+
[`src/entry/tui/commands.ts`](src/entry/tui/commands.ts)).
|
|
133
|
+
|
|
134
|
+
## Upgrading from 0.x
|
|
135
|
+
|
|
136
|
+
1.0 is a clean break: run `bunx catherd-cli init` once. It moves your 0.x `config.json`, `projects.json` and
|
|
137
|
+
profiles into a `0.x-backup-<time>/` folder next to them (it never reads or deletes them), writes the 1.0
|
|
138
|
+
default profile, replaces the 0.x Claude agent links with 1.0 ones and keeps your saved Jev key; 0.x run
|
|
139
|
+
folders stay where they are, unread. Then update the plugin
|
|
140
|
+
(`claude plugin marketplace update catherd && claude plugin update catherd@catherd`) and start a new Claude
|
|
141
|
+
Code session. The details are in [MIGRATION.md](MIGRATION.md).
|
|
142
|
+
|
|
143
|
+
## Docs
|
|
144
|
+
|
|
145
|
+
| Where | What |
|
|
146
|
+
| -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
147
|
+
| [MIGRATION.md](MIGRATION.md) | Upgrading from 0.x |
|
|
148
|
+
| [CHANGELOG.md](CHANGELOG.md) | Releases |
|
|
149
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Development setup, the checks, commits, changesets, live tests |
|
|
150
|
+
| [SECURITY.md](SECURITY.md) | Reporting a vulnerability; what catherd stores and how |
|
|
151
|
+
| [`docs/superpowers/specs/2026-09-25-catherd-1.0-design.md`](docs/superpowers/specs/2026-09-25-catherd-1.0-design.md) | The 1.0 design (binding) |
|
|
152
|
+
| [`docs/dev/`](docs/dev/) | Maintainer docs: live verification, manual tests, dependencies, ideas |
|
|
153
|
+
| [`docs/dev/live-verification.md`](docs/dev/live-verification.md) | What CI cannot run: live tests, fixture capture, the Codex sandbox |
|
|
154
|
+
| [`docs/tui-frames.md`](docs/tui-frames.md) | Every dashboard screen as text (generated, checked in CI) |
|
|
155
|
+
| [`docs/superpowers/`](docs/superpowers/), [`docs/research/`](docs/research/) | How 1.0 was designed and built: plans, reviews, research |
|
|
156
|
+
| [`docs/archive/0.x/`](docs/archive/0.x/) | The 0.x design and plans, for history |
|
|
157
|
+
|
|
158
|
+
## Contributing
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). CI runs the checks on Linux and macOS, on Bun 1.4.0 and the latest Bun;
|
|
161
|
+
what CI cannot run is in [`docs/dev/live-verification.md`](docs/dev/live-verification.md). Report security issues
|
|
162
|
+
privately, as [SECURITY.md](SECURITY.md) describes. Everyone taking part follows the
|
|
163
|
+
[Code of Conduct](CODE_OF_CONDUCT.md).
|
|
80
164
|
|
|
81
165
|
## License
|
|
82
166
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
catherd's TUI adapts code and designs from opencode (<https://github.com/anomalyco/opencode>), used under
|
|
4
|
+
the MIT license below. Each derived file says so in its first lines:
|
|
5
|
+
|
|
6
|
+
- `src/entry/tui/commands.ts`: command ids and default keys (`packages/tui/src/config/keybind.ts`)
|
|
7
|
+
- `src/entry/tui/providers/keymap.tsx`: the keymap setup (`packages/tui/src/context/keymap.tsx`)
|
|
8
|
+
- `src/entry/tui/providers/toast.tsx` and `src/entry/tui/widgets/toast.tsx`: toasts (`packages/tui/src/ui/toast.tsx`)
|
|
9
|
+
- `src/entry/tui/widgets/dialog.tsx`: the dialog panel (`packages/tui/src/ui/dialog.tsx`)
|
|
10
|
+
- `src/entry/tui/widgets/dialog-select.tsx`: the picker (`packages/tui/src/ui/dialog-select.tsx`)
|
|
11
|
+
- `src/entry/tui/widgets/dialog-confirm.tsx`: confirmations (`packages/tui/src/ui/dialog-confirm.tsx`)
|
|
12
|
+
- `src/entry/tui/widgets/dialog-prompt.tsx`: value editors (`packages/tui/src/ui/dialog-prompt.tsx`)
|
|
13
|
+
- `src/entry/tui/widgets/spinner.tsx`: the spinner and its delayed presence (`packages/tui/src/component/spinner.tsx`, `startup-loading.tsx`)
|
|
14
|
+
|
|
15
|
+
## opencode
|
|
16
|
+
|
|
17
|
+
MIT License
|
|
18
|
+
|
|
19
|
+
Copyright (c) 2025 opencode
|
|
20
|
+
|
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
23
|
+
in the Software without restriction, including without limitation the rights
|
|
24
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
26
|
+
furnished to do so, subject to the following conditions:
|
|
27
|
+
|
|
28
|
+
The above copyright notice and this permission notice shall be included in all
|
|
29
|
+
copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
34
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
35
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
36
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
37
|
+
SOFTWARE.
|
package/catalog/jev.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"model": "jev-1.13.0",
|
|
4
|
+
"sets": {
|
|
5
|
+
"route-v2": {
|
|
6
|
+
"questions": {
|
|
7
|
+
"kind": {
|
|
8
|
+
"type": "choice",
|
|
9
|
+
"instructions": "What kind of work does the lane in the state describe?",
|
|
10
|
+
"criteria": {
|
|
11
|
+
"repo_code": "Code and tests inside an application or library repository",
|
|
12
|
+
"terminal": "Shell, build, CI, infrastructure or environment work, where the terminal is the main tool",
|
|
13
|
+
"ui": "User-interface work judged on screen: layout, styling, components",
|
|
14
|
+
"prose": "Writing that is not code: docs, a changelog, release notes, a merge request body",
|
|
15
|
+
"research": "Finding facts to answer a question, with no change to the product",
|
|
16
|
+
"other": "None of the above"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"difficulty": {
|
|
20
|
+
"type": "score",
|
|
21
|
+
"instructions": "Which situation matches the work the lane in the state asks for?",
|
|
22
|
+
"criteria": [
|
|
23
|
+
"A mechanical change: rename, move, delete or copy existing code, or change constants, with no new behaviour",
|
|
24
|
+
"New code that follows an existing example which the lane names or the repository already has",
|
|
25
|
+
"New logic with state, concurrency, data invariants or tricky edge cases",
|
|
26
|
+
"A cause nobody has found yet, a design across systems to settle, or no example to follow"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"names_pattern": {
|
|
30
|
+
"type": "noul",
|
|
31
|
+
"instructions": "Does the lane in the state name an existing file, function, endpoint or test in the repository that the new work should copy or follow?",
|
|
32
|
+
"criteria": {
|
|
33
|
+
"true": "It names a concrete existing example by path or name",
|
|
34
|
+
"false": "It names no existing example, or only says to follow conventions in general"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"mechanical": {
|
|
38
|
+
"type": "noul",
|
|
39
|
+
"instructions": "Is the work in the lane in the state only mechanical: renaming, moving, deleting or copying code, or changing constants, with no new behaviour?"
|
|
40
|
+
},
|
|
41
|
+
"shared_state": {
|
|
42
|
+
"type": "noul",
|
|
43
|
+
"instructions": "Does the work in the lane in the state involve concurrency, caching, shared mutable state, transactions, or the ordering of events?"
|
|
44
|
+
},
|
|
45
|
+
"unclear_cause": {
|
|
46
|
+
"type": "noul",
|
|
47
|
+
"instructions": "Does the lane in the state ask the worker to find the cause of a bug or failure that the lane does not already explain?"
|
|
48
|
+
},
|
|
49
|
+
"open_design": {
|
|
50
|
+
"type": "noul",
|
|
51
|
+
"instructions": "Does the lane in the state leave an interface, data shape or algorithm for the worker to decide?"
|
|
52
|
+
},
|
|
53
|
+
"cross_boundary": {
|
|
54
|
+
"type": "noul",
|
|
55
|
+
"instructions": "Must the work in the lane in the state keep two or more services, processes or data stores consistent, such as a schema migration together with the code that reads it?"
|
|
56
|
+
},
|
|
57
|
+
"outside_repo": {
|
|
58
|
+
"type": "noul",
|
|
59
|
+
"instructions": "Does the work in the lane in the state depend on something outside the repository: a running service, credentials, network access, hardware or CI configuration?"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"rule": { "kindMin": 0.8, "trackMin": 0.8, "trackA": ["0", "1"], "trackB": ["2", "3"] }
|
|
63
|
+
},
|
|
64
|
+
"finding": {
|
|
65
|
+
"questions": {
|
|
66
|
+
"finding": {
|
|
67
|
+
"type": "choice",
|
|
68
|
+
"instructions": "A reviewer reported `finding` on the work planned in `lane`. Where is the defect?",
|
|
69
|
+
"criteria": {
|
|
70
|
+
"design": "The plan itself is wrong: its decisions, signatures or data shapes cannot meet the goal",
|
|
71
|
+
"code": "The plan is sound and the code does not implement it correctly",
|
|
72
|
+
"unclear": "The finding does not say enough to tell"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"rule": { "min": 0.83, "fallback": "code" }
|
|
77
|
+
},
|
|
78
|
+
"same-defect": {
|
|
79
|
+
"questions": {
|
|
80
|
+
"same-defect": {
|
|
81
|
+
"type": "choice",
|
|
82
|
+
"instructions": "Does `after` report the same underlying defect as `before`, even if worded differently or at another line?",
|
|
83
|
+
"criteria": { "yes": "Same underlying defect", "no": "A different defect" }
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"rule": { "min": 0.85, "fallback": "no" }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"version": "2026-09-25",
|
|
4
|
+
"sources": {
|
|
5
|
+
"claude": "https://platform.claude.com/docs/en/models/overview (2026-09-25); efforts https://platform.claude.com/docs/en/build-with-claude/effort; prices https://platform.claude.com/docs/en/about-claude/pricing",
|
|
6
|
+
"codex": "codex debug models --bundled, Codex CLI 0.157.0 (2026-09-25); prices https://developers.openai.com/api/docs/pricing; plan weights https://learn.chatgpt.com/docs/pricing",
|
|
7
|
+
"opencode": "opencode models <provider> --verbose on 1.18.32 and the v2 model.list (2026-09-25); https://opencode.ai/docs/zen, https://opencode.ai/docs/go"
|
|
8
|
+
},
|
|
9
|
+
"backends": {
|
|
10
|
+
"codex": {
|
|
11
|
+
"imageGen": {
|
|
12
|
+
"tool": "gpt-image-2",
|
|
13
|
+
"requires": "chatgpt-login",
|
|
14
|
+
"source": "https://learn.chatgpt.com/docs/image-generation"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"families": [
|
|
19
|
+
{
|
|
20
|
+
"id": "gpt-6-astra",
|
|
21
|
+
"name": "GPT-6 Astra",
|
|
22
|
+
"vendor": "openai",
|
|
23
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
24
|
+
"price": { "input": 10, "cached": 1, "output": 50 },
|
|
25
|
+
"planWeight": 60,
|
|
26
|
+
"on": {
|
|
27
|
+
"codex": {
|
|
28
|
+
"id": "gpt-6-astra",
|
|
29
|
+
"efforts": ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
30
|
+
"context": 272000
|
|
31
|
+
},
|
|
32
|
+
"opencode": {
|
|
33
|
+
"id": "opencode/gpt-6-astra",
|
|
34
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
35
|
+
"context": 1050000
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"notes": {
|
|
39
|
+
"ultra": "maximum reasoning with automatic task delegation to parallel subagents; never in a default ladder"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "gpt-6-sol",
|
|
44
|
+
"name": "GPT-6 Sol",
|
|
45
|
+
"vendor": "openai",
|
|
46
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
47
|
+
"price": { "input": 2, "cached": 0.2, "output": 10 },
|
|
48
|
+
"planWeight": 20,
|
|
49
|
+
"on": {
|
|
50
|
+
"codex": {
|
|
51
|
+
"id": "gpt-6-sol",
|
|
52
|
+
"efforts": ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
53
|
+
"context": 272000
|
|
54
|
+
},
|
|
55
|
+
"opencode": {
|
|
56
|
+
"id": "opencode/gpt-6-sol",
|
|
57
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
58
|
+
"context": 1050000
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"notes": {
|
|
62
|
+
"ultra": "maximum reasoning with automatic task delegation to parallel subagents; never in a default ladder"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "gpt-6-luna",
|
|
67
|
+
"name": "GPT-6 Luna",
|
|
68
|
+
"vendor": "openai",
|
|
69
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
70
|
+
"price": { "input": 0.1, "cached": 0.01, "output": 0.5 },
|
|
71
|
+
"planWeight": 1,
|
|
72
|
+
"on": {
|
|
73
|
+
"codex": {
|
|
74
|
+
"id": "gpt-6-luna",
|
|
75
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
76
|
+
"context": 272000
|
|
77
|
+
},
|
|
78
|
+
"opencode": {
|
|
79
|
+
"id": "opencode/gpt-6-luna",
|
|
80
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
81
|
+
"context": 1050000
|
|
82
|
+
},
|
|
83
|
+
"opencode-go": {
|
|
84
|
+
"id": "opencode-go/gpt-6-luna",
|
|
85
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
86
|
+
"context": 1050000
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "gpt-5.6-sol",
|
|
92
|
+
"name": "GPT-5.6 Sol",
|
|
93
|
+
"vendor": "openai",
|
|
94
|
+
"status": "legacy",
|
|
95
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
96
|
+
"price": { "input": 4, "cached": 0.4, "output": 20 },
|
|
97
|
+
"planWeight": 30,
|
|
98
|
+
"on": {
|
|
99
|
+
"codex": {
|
|
100
|
+
"id": "gpt-5.6-sol",
|
|
101
|
+
"efforts": ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
102
|
+
"context": 272000
|
|
103
|
+
},
|
|
104
|
+
"opencode": {
|
|
105
|
+
"id": "opencode/gpt-5.6-sol",
|
|
106
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
107
|
+
"context": 1050000
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"notes": { "upgrade": "Codex offers gpt-6-sol as its upgrade" }
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "gpt-5.6-terra",
|
|
114
|
+
"name": "GPT-5.6 Terra",
|
|
115
|
+
"vendor": "openai",
|
|
116
|
+
"status": "legacy",
|
|
117
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
118
|
+
"price": { "input": 2, "cached": 0.2, "output": 12 },
|
|
119
|
+
"planWeight": 15,
|
|
120
|
+
"on": {
|
|
121
|
+
"codex": {
|
|
122
|
+
"id": "gpt-5.6-terra",
|
|
123
|
+
"efforts": ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
124
|
+
"context": 272000
|
|
125
|
+
},
|
|
126
|
+
"opencode": {
|
|
127
|
+
"id": "opencode/gpt-5.6-terra",
|
|
128
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
129
|
+
"context": 1050000
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"notes": { "upgrade": "Codex offers gpt-6-sol as its upgrade" }
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "gpt-5.6-luna",
|
|
136
|
+
"name": "GPT-5.6 Luna",
|
|
137
|
+
"vendor": "openai",
|
|
138
|
+
"status": "legacy",
|
|
139
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
140
|
+
"price": { "input": 0.2, "cached": 0.02, "output": 1.2 },
|
|
141
|
+
"planWeight": 1.5,
|
|
142
|
+
"on": {
|
|
143
|
+
"codex": {
|
|
144
|
+
"id": "gpt-5.6-luna",
|
|
145
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
146
|
+
"context": 272000
|
|
147
|
+
},
|
|
148
|
+
"opencode": {
|
|
149
|
+
"id": "opencode/gpt-5.6-luna",
|
|
150
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
151
|
+
"context": 1050000
|
|
152
|
+
},
|
|
153
|
+
"opencode-go": {
|
|
154
|
+
"id": "opencode-go/gpt-5.6-luna",
|
|
155
|
+
"efforts": ["none", "low", "medium", "high", "xhigh", "max"],
|
|
156
|
+
"context": 1050000
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"notes": { "upgrade": "Codex offers gpt-6-luna as its upgrade" }
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "claude-fable-5-1",
|
|
163
|
+
"name": "Claude Fable 5.1",
|
|
164
|
+
"vendor": "anthropic",
|
|
165
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
166
|
+
"price": { "input": 10, "cached": 0.25, "output": 50 },
|
|
167
|
+
"meteredOnPlan": true,
|
|
168
|
+
"on": {
|
|
169
|
+
"claude-code": {
|
|
170
|
+
"id": "claude-fable-5-1",
|
|
171
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
172
|
+
"context": 1000000
|
|
173
|
+
},
|
|
174
|
+
"opencode": {
|
|
175
|
+
"id": "opencode/claude-fable-5-1",
|
|
176
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
177
|
+
"context": 1000000
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"notes": {
|
|
181
|
+
"plan": "Pro and Team Standard pay usage credits for Fable; Max includes it up to half the weekly limit"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "claude-opus-5-5",
|
|
186
|
+
"name": "Claude Opus 5.5",
|
|
187
|
+
"vendor": "anthropic",
|
|
188
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
189
|
+
"price": { "input": 4, "cached": 0.2, "output": 20 },
|
|
190
|
+
"on": {
|
|
191
|
+
"claude-code": {
|
|
192
|
+
"id": "claude-opus-5-5",
|
|
193
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
194
|
+
"context": 1000000
|
|
195
|
+
},
|
|
196
|
+
"opencode": {
|
|
197
|
+
"id": "opencode/claude-opus-5-5",
|
|
198
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
199
|
+
"context": 1000000
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"notes": { "effort": "the API default effort is medium" }
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"id": "claude-sonnet-5",
|
|
206
|
+
"name": "Claude Sonnet 5",
|
|
207
|
+
"vendor": "anthropic",
|
|
208
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
209
|
+
"price": { "input": 2, "cached": 0.2, "output": 10 },
|
|
210
|
+
"on": {
|
|
211
|
+
"claude-code": {
|
|
212
|
+
"id": "claude-sonnet-5",
|
|
213
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
214
|
+
"context": 1000000
|
|
215
|
+
},
|
|
216
|
+
"opencode": {
|
|
217
|
+
"id": "opencode/claude-sonnet-5",
|
|
218
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
219
|
+
"context": 1000000
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"id": "claude-haiku-4-5",
|
|
225
|
+
"name": "Claude Haiku 4.5",
|
|
226
|
+
"vendor": "anthropic",
|
|
227
|
+
"capabilities": { "toolUse": true, "imageIn": true, "reasoning": true },
|
|
228
|
+
"price": { "input": 1, "cached": 0.1, "output": 5 },
|
|
229
|
+
"on": {
|
|
230
|
+
"claude-code": { "id": "claude-haiku-4-5-20251001", "efforts": [], "context": 200000 },
|
|
231
|
+
"opencode": { "id": "opencode/claude-haiku-4-5", "efforts": ["high", "max"], "context": 200000 }
|
|
232
|
+
},
|
|
233
|
+
"notes": { "effort": "no effort parameter in Claude Code: its only rung there is #default" }
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
}
|