planr 1.1.18 → 1.2.0-alpha.1

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.
Files changed (35) hide show
  1. package/README.md +6 -3
  2. package/docs/ARCHITECTURE.md +18 -10
  3. package/docs/CLAUDE_CODE.md +19 -0
  4. package/docs/CLI_REFERENCE.md +26 -8
  5. package/docs/CODEX.md +12 -2
  6. package/docs/CURSOR.md +91 -7
  7. package/docs/EXAMPLE_WEBAPP.md +138 -0
  8. package/docs/GOALS.md +45 -6
  9. package/docs/INSTALL.md +3 -1
  10. package/docs/MCP_CONTRACT.md +6 -4
  11. package/docs/MODEL_ROUTING.md +190 -0
  12. package/docs/RELEASE.md +16 -0
  13. package/docs/SKILLS.md +7 -9
  14. package/docs/TROUBLESHOOTING.md +4 -0
  15. package/docs/fixtures/mcp-contract.json +12 -1
  16. package/npm/native/darwin-arm64/planr +0 -0
  17. package/npm/native/darwin-x86_64/planr +0 -0
  18. package/npm/native/linux-arm64/planr +0 -0
  19. package/npm/native/linux-x86_64/planr +0 -0
  20. package/package.json +1 -1
  21. package/plugins/planr/.claude-plugin/plugin.json +1 -1
  22. package/plugins/planr/.codex-plugin/plugin.json +1 -1
  23. package/plugins/planr/agents/planr-reviewer.md +7 -2
  24. package/plugins/planr/agents/planr-worker.md +6 -0
  25. package/plugins/planr/skills/planr-goal/SKILL.md +5 -3
  26. package/plugins/planr/skills/planr-loop/SKILL.md +7 -3
  27. package/plugins/planr/skills/planr-loop/agents/planr-reviewer.md +17 -0
  28. package/plugins/planr/skills/planr-loop/agents/planr-reviewer.toml +8 -2
  29. package/plugins/planr/skills/planr-loop/agents/planr-worker.md +13 -0
  30. package/plugins/planr/skills/planr-loop/agents/planr-worker.toml +7 -0
  31. package/plugins/planr/skills/planr-plan/SKILL.md +14 -0
  32. package/plugins/planr/skills/planr-review/SKILL.md +1 -1
  33. package/plugins/planr/skills/planr-task-graph/SKILL.md +2 -0
  34. package/plugins/planr/skills/planr-work/SKILL.md +1 -1
  35. package/docs/planr-spec.zip +0 -0
package/README.md CHANGED
@@ -82,13 +82,15 @@ Restart Claude Code afterwards. Skills are namespaced (`/planr:planr`, `/planr:p
82
82
  <details>
83
83
  <summary><strong>Cursor</strong></summary>
84
84
 
85
- Pending marketplace review. Until the plugin is listed, wire Planr in via MCP and the CLI prompt:
85
+ One command installs everything the plugin would carry:
86
86
 
87
87
  ```bash
88
- planr install cursor # writes .cursor/mcp.json
89
- planr prompt cli --client cursor
88
+ planr install cursor # writes .cursor/mcp.json, .cursor/agents/, and .cursor/skills/
89
+ planr install cursor --no-mcp # skills and subagents only, no MCP config
90
90
  ```
91
91
 
92
+ The dry-run also prints a one-click `cursor://` deeplink for user-level MCP install. Marketplace listing is pending review. Multitasking with Cursor subagents: [Cursor guide](docs/CURSOR.md).
93
+
92
94
  </details>
93
95
 
94
96
  <a id="install-plugin-opencode"></a>
@@ -134,6 +136,7 @@ Mid-project work (a new feature, refactor, or fix on an existing project) works
134
136
  - [Install](docs/INSTALL.md)
135
137
  - [Skills](docs/SKILLS.md)
136
138
  - [Long-Running Goals](docs/GOALS.md)
139
+ - [Model Routing](docs/MODEL_ROUTING.md) · [Worked Example: Web App](docs/EXAMPLE_WEBAPP.md)
137
140
  - [CLI Reference](docs/CLI_REFERENCE.md)
138
141
  - [MCP Guide](docs/MCP_GUIDE.md)
139
142
  - [Codex](docs/CODEX.md) · [Claude Code](docs/CLAUDE_CODE.md) · [Cursor](docs/CURSOR.md)
@@ -1,6 +1,6 @@
1
1
  # Planr Architecture
2
2
 
3
- Planr V1 is a single Rust binary with explicit module ownership. The crate stays small enough that a Cargo workspace would add more process overhead than value today, and there is only one deployable: the `planr` CLI. The source tree is split by ownership boundary inside that crate instead of using a premature workspace.
3
+ Planr V1 is a single Rust binary with explicit module ownership. The crate stays small enough that a Cargo workspace would add more process overhead than value today, and there is only one deployable: the `planr` CLI. The source tree is split by ownership boundary inside that crate instead of using a premature workspace. Shared mutations that must behave identically across CLI, MCP, and HTTP live in one place (`src/app/application.rs`) so the three surfaces cannot drift.
4
4
 
5
5
  ## Repository Layout
6
6
 
@@ -32,12 +32,18 @@ Planr V1 is a single Rust binary with explicit module ownership. The crate stays
32
32
  - `src/app/surfaces.rs`: non-CLI runtime surfaces. Owns trace, scrub, artifact, event, debug, export, and import command handlers.
33
33
  - `src/app/inspection.rs`: local inspection helpers. Owns debug bundles, context/link snapshots, pick context, secret scans, export value assembly, run recording, search results, and Planr-directory import parsing.
34
34
  - `src/app/audit.rs`: goal contract audit boundary. Owns the clause-by-clause `plan audit` verdict (items settled, reviews complete, approvals clear, verification logged) and its human rendering.
35
- - `src/model.rs`: JSON-facing data transfer types. Owns serializable Planr DTOs used by CLI JSON, MCP, HTTP, and tests.
35
+ - `src/app/application.rs`: shared surface-mutation boundary. Owns the approval request/approve/deny, context, log, artifact, and close mutations reused verbatim by CLI, MCP, and HTTP handlers so the three surfaces cannot drift.
36
+ - `src/app/repository/`: focused data-access submodules (`item.rs`, `plan.rs`, `project.rs`, `link.rs`, `context.rs`, `evidence.rs`, `search.rs`) split out of `src/app/repository.rs` by entity ownership.
37
+ - `src/model.rs`: JSON-facing data transfer types and typed vocabulary. Owns serializable Planr DTOs plus the `ItemStatus`, `WorkType`, `LinkKind`, and `ApprovalStatus` enums with their parsing and display behavior, used by CLI JSON, MCP, HTTP, storage rows, and tests.
36
38
  - `src/storage/mod.rs`: SQLite connection boundary. Owns default database path, connection setup, pragma configuration, and storage submodule exports.
37
39
  - `src/storage/schema.rs`: SQLite schema boundary. Owns DDL, additive schema upgrade helpers, and schema version recording.
38
40
  - `src/storage/rows.rs`: SQLite row mapping boundary. Owns row-to-DTO and row-to-JSON mapping functions.
39
- - `src/planpack.rs`: Markdown package generation. Owns project context templates and product/build plan file templates.
40
- - `src/integrations.rs`: agent-client integration descriptors. Owns Codex, Claude Code, Cursor, and MCP install metadata.
41
+ - `src/planpack.rs`: Markdown package generation and parsing. Owns project context templates, product/build plan templates, plan metadata parsing, hashes, search body extraction, and task extraction.
42
+ - `src/agents.rs`: agent profile registry core. Owns `.planr/agents.toml` parsing, registry validation warnings, and the pure advisory `resolve_route` precedence logic (override > work_type > plan > default); no storage or host concerns.
43
+ - `src/app/agents.rs`: routing application boundary. Owns the `agents` and `item route` command handlers, the shared `*_value` JSON shapes reused by MCP, per-item route facts assembly, and registry-aware role content selection for installs.
44
+ - `src/app/agents_init.rs`: registry bootstrap boundary. Owns `planr agents init` — the static cost-tiering scaffold and, per the agent-pool plan, the flag-spec builder and interactive wizard.
45
+ - `src/integrations.rs`: agent-client integration descriptor boundary. Owns Codex, Claude Code, Cursor, MCP install metadata, MCP tool schemas, MCP resources, and MCP text response wrapping.
46
+ - `src/rolefiles.rs`: host role file boundary. Owns the shipped static subagent role files and Cursor skills payloads, plus the pure renderers that re-pin role files from registry profiles (Codex TOML with strict field names, Claude/Cursor markdown frontmatter) under the generated-from header.
41
47
  - `src/util.rs`: small CLI-boundary utilities. Owns ids, timestamps, path helpers, output formatting, and safe file writes.
42
48
 
43
49
  ## Boundary Rules
@@ -45,10 +51,12 @@ Planr V1 is a single Rust binary with explicit module ownership. The crate stays
45
51
  - Command parsing belongs in `src/cli.rs`; process startup belongs in `src/main.rs`; command execution belongs under `src/app/`.
46
52
  - `src/main.rs` must stay small enough to be only a composition root. It must not own product use cases.
47
53
  - `src/app/mod.rs` must stay small enough to wire runtime state and dispatch. It must not absorb app submodule behavior.
48
- - SQLite schema belongs in `src/storage/schema.rs`; row mapping belongs in `src/storage/rows.rs`; app data access helpers belong in `src/app/repository.rs`.
54
+ - SQLite schema belongs in `src/storage/schema.rs`; row mapping belongs in `src/storage/rows.rs`; app data access helpers belong in `src/app/repository.rs` and its submodules.
55
+ - Mutations shared by more than one surface (CLI, MCP, HTTP) belong in `src/app/application.rs`; surface handlers must call the shared helper instead of repeating SQL.
49
56
  - Markdown templates belong in `planpack.rs`; command handlers should request generated file sets instead of embedding large template bodies.
50
- - Agent install metadata belongs in `integrations.rs`; client-specific strings should not drift across command handlers and docs.
51
- - DTO changes belong in `model.rs`; JSON response shapes should reuse those DTOs before adding ad hoc maps.
57
+ - Agent install metadata and MCP schema descriptors belong in `src/integrations.rs`; client-specific strings should not drift across command handlers and docs.
58
+ - DTO and vocabulary-enum changes belong in `src/model.rs`; JSON response shapes should reuse those DTOs before adding ad hoc maps.
59
+ - Item status, work type, link kind, and approval status values are typed enums; new states must be added to the enum, not smuggled in as strings.
52
60
  - Utility code must stay narrow. If a helper starts owning product behavior, move it to the owning module instead of growing `util.rs`.
53
61
  - Do not add catch-all `common`, `shared`, or broad utility modules. New modules must name a durable ownership boundary.
54
62
 
@@ -58,10 +66,10 @@ Planr remains a single crate for V1 because:
58
66
 
59
67
  - there is one deployable binary and no separate service or reusable library boundary;
60
68
  - the current behavior contract is tighter when CLI, MCP, HTTP, storage, and docs ship together;
61
- - module-level ownership now gives the needed architecture separation without duplicating Cargo settings or release packaging;
69
+ - module-level ownership gives the needed architecture separation without duplicating Cargo settings or release packaging;
62
70
  - npm, release, and external consumer tests assume one native binary named `planr`.
63
71
 
64
- A Cargo workspace should be introduced only after a concrete deployable, reuse, compilation, or team ownership boundary exists and package/release scripts are updated in the same change.
72
+ A Cargo workspace was tried and reverted: it produced anemic crates whose only job was being a layer, plus re-export shims in the binary. A workspace should be introduced only after a concrete deployable, reuse, compilation, or team ownership boundary exists and package/release scripts are updated in the same change.
65
73
 
66
74
  ## Future Extract Points
67
75
 
@@ -72,4 +80,4 @@ If Planr grows past the V1 binary shape, the first clean extraction path is:
72
80
  - `planr-cli`: `src/cli.rs`, human output, and install helpers.
73
81
  - `planr-server`: `src/app/http.rs`, `src/app/mcp.rs`, and runtime server adapters.
74
82
 
75
- Do not extract those crates until a real reuse, compile-time, or ownership boundary exists.
83
+ Do not extract those crates until a real reuse, compile-time, or ownership boundary exists. Every extraction must leave a real owner with runtime code, tests, and one-way dependencies.
@@ -11,6 +11,25 @@ The Planr repository is a Claude Code plugin. Install it to get the skills (name
11
11
 
12
12
  See [Skills](SKILLS.md) for the skill workflow. For autonomous goal runs with `/goal` or `/loop` on top of Planr state, see [Long-Running Goals](GOALS.md).
13
13
 
14
+ ## Long-Running Goals With `/goal`
15
+
16
+ Claude Code `/goal` drives autonomous Planr runs the same way Codex does: `/goal` supplies continuation pressure, Planr supplies durable state, evidence, reviews, and recovery. Run the driver session on your strongest model (`/model fable`, `/effort high`), prep once, then start:
17
+
18
+ ```text
19
+ /planr:planr-goal <your goal>
20
+ /goal Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract). Continue until the contract holds or the iteration budget is exhausted. You are operating autonomously: the user is not watching, so never end a turn on a plan, a question, or a promise — proceed until the contract holds or you are blocked on input only the user can provide.
21
+ ```
22
+
23
+ The plugin registers the `planr-worker` and `planr-reviewer` subagents automatically. The worker pins a cheaper tier in its frontmatter; the reviewer deliberately inherits the driver's model:
24
+
25
+ ```yaml
26
+ # planr-worker.md frontmatter
27
+ model: opus # alias tracks the current generation; budget alternative: sonnet
28
+ effort: medium
29
+ ```
30
+
31
+ Verify the pin once: `CLAUDE_CODE_SUBAGENT_MODEL` must be unset (it silently overrides all subagent frontmatter), then dispatch the worker on a trivial item and confirm the subagent's messages in `~/.claude/projects/<project>/*.jsonl` carry the worker model. Full workflow, recovery, and the tiering rationale: [Long-Running Goals](GOALS.md).
32
+
14
33
  ## MCP
15
34
 
16
35
  ```bash
@@ -13,7 +13,7 @@ planr plan check <plan-id>
13
13
  planr plan audit <plan-id>
14
14
  planr plan show <plan-id>
15
15
  planr plan archive <plan-id>
16
- planr map show
16
+ planr map show [--plan <plan-id>]
17
17
  planr map build --from <plan-id>
18
18
  planr map lane --critical
19
19
  planr map pressure
@@ -26,6 +26,8 @@ planr item breakdown <item-id> --into "A" --into "B" [--into "C"]
26
26
  planr item insert "title" --description "..." --after <item-id> [--before <item-id>] [--preview|--confirm]
27
27
  planr item amend <item-id> --note "..." [--tag amendment]
28
28
  planr item replan <parent-id> --into "A, B, C" [--preview|--confirm]
29
+ planr item update <item-id> [--title "..."] [--description "..."] [--work-type <type>]
30
+ planr item route <item-id> [--set <profile>|--clear]
29
31
  planr link add <from-item> <to-item> --type blocks
30
32
  planr pick
31
33
  planr pick release <item-id> [--force]
@@ -44,7 +46,7 @@ planr artifact show <artifact-id>
44
46
  planr artifact list [--item <item-id>]
45
47
  planr event list [--item <item-id>] [--limit 50]
46
48
  planr debug bundle [--item <item-id>] --preview
47
- planr log add --item <item-id> --summary "..." [--files a --files b | --files a,b] [--cmd "..."] [--kind completion|progress|verification]
49
+ planr log add --item <item-id> --summary "..." [--files a --files b | --files a,b] [--cmd "..."] [--kind completion|progress|verification] [--profile <id>]
48
50
  planr review request <item-id>
49
51
  planr review annotate <item-id> --message "..." [--severity info|warning|blocking] [--file path] [--line N] [--author "..."]
50
52
  planr review ingest <item-id> (--from feedback.json|--stdin)
@@ -52,12 +54,18 @@ planr review artifact <review-item-id> [--out .planr/reviews/custom.review.md]
52
54
  planr review evidence <item-id> [--pr-url https://...]
53
55
  planr review close <review-item-id> --verdict complete|not-complete|unclear [--close-target]
54
56
  planr close [item-id] --summary "..." [--next]
55
- planr done [item-id] --summary "..." [--files a --files b] [--cmd "..."] [--tests "..."] [--review] [--next]
57
+ planr done [item-id] --summary "..." [--files a --files b] [--cmd "..."] [--tests "..."] [--review] [--next] [--profile <id>]
56
58
  planr context add "text" [--item <item-id>] [--tag discovery]
59
+ planr context list [--item <item-id>] [--tag <tag>]
57
60
  planr search "query"
61
+ planr agents init [--force]
62
+ planr agents init --profile|--skill|--route|--default-route|--interactive
63
+ planr agents list [--json]
64
+ planr agents check
58
65
  planr doctor [--client codex|claude|cursor|all]
59
- planr install codex|claude|cursor [--dry-run]
66
+ planr install codex|claude|cursor [--dry-run] [--no-mcp] [--force]
60
67
  planr prompt cli|mcp|http [--client codex|claude|cursor|all]
68
+ planr prompt routing [--client codex|claude|cursor|all]
61
69
  planr mcp
62
70
  planr serve --port 7526
63
71
  planr import <file> [--preview] [--confirm]
@@ -79,7 +87,11 @@ With `--json`, responses follow one convention so agents never guess where data
79
87
 
80
88
  `plan check` validates path, YAML frontmatter, and that required sections have content: build plans need `## Scope Decision`, `## Verification`, and `## Acceptance Criteria` filled; product plans need `## Problem`, `## Requirements`, and `## Success Criteria` filled in `PRODUCT_SPEC.md`. It also flags a task list that still contains only the scaffold placeholder (or no work specs at all) — `map build` would turn that into a single coarse item, so the fix names the granularity contract: one `### TASK-00n:` heading (or `- [ ]` line) per verifiable slice, typically 4-8, in execution order. Each warning is structured — `{"file", "section", "message", "fix"}` — and names the exact file to edit plus the re-run command, so a failed check is a repair instruction, not a riddle.
81
89
 
82
- `plan audit <plan-id>` is the one-call contract verdict for a plan's map scope. It evaluates four clauses with evidence: `items_settled` (open items listed), `reviews_complete` (open review items listed), `approvals_clear` (requested/denied approvals listed), and `verification_logged` (logs with `--kind verification` on scope items). The stored goal contract (`planr context --tag goal-contract` mentioning the plan id) is included; the verification clause is binding only when such a contract exists. `holds: true` means the contract is satisfied — loop agents use this as their stop condition instead of stitching the verdict together from `map status`, `log list`, and `approval list`. Also available as MCP `planr_plan_audit`.
90
+ `plan audit <plan-id>` is the one-call contract verdict for a plan's map scope. It evaluates four clauses with evidence: `items_settled` (open items listed), `reviews_complete` (open review items listed), `approvals_clear` (requested/denied approvals listed), and `verification_logged` (logs with `--kind verification` on scope items). The stored goal contract (`planr context --tag goal-contract` mentioning the plan id) is included; the verification clause is binding only when such a contract exists. `holds: true` means the contract is satisfied — loop agents use this as their stop condition instead of stitching the verdict together from `map status`, `log list`, and `approval list`. When the contract is open, `next` carries the exact next command derived from the first actionable gap: build the map, pick the ready review or work item (plan-scoped), resolve the blocking approval, inspect stalled leases, or log the missing verification. Also available as MCP `planr_plan_audit`.
91
+
92
+ `map show --plan <plan-id>` narrows the map to one plan's items and the links among them, with plan-scoped counts — plan-scoped goal runs on shared boards audit their slice, not the whole board. An unknown plan id is an error, never a silent unscoped view. Also available on MCP `planr_map_show` (`plan`) and HTTP `GET /v1/projects/{id}/map?plan=<plan-id>`.
93
+
94
+ `context list --tag <tag>` filters notes by the tag they were stored with (`context add --tag`), so e.g. the goal contract is recoverable with `planr context list --tag goal-contract` instead of scanning all notes.
83
95
 
84
96
  `map build` chains the created items in plan order with `blocks` links — build plan steps are ordered, so the map inherits that order instead of leaving everything flat. The output lists every created item with its status, the created links, and the next command; adjust order with `planr link add` before picking if execution order differs from document order.
85
97
 
@@ -107,7 +119,9 @@ With `--json`, responses follow one convention so agents never guess where data
107
119
 
108
120
  `review close` writes `.planr/reviews/<review-item-id>.review.md` and registers it as a review artifact. A `not-complete` or `unclear` verdict creates fix and follow-up review work; the follow-up review gates the same target item, so the chain keeps working with `--close-target`. With `--close-target` (complete verdicts only) the reviewed item is closed in the same command, provided it already has a completion log; the artifact is rendered after the target transition, so it snapshots the final target status. `--close-target` is also available through MCP `planr_review_close` and HTTP `POST /v1/reviews/{id}/close` (`"close_target": true`). `review close` responses include the same `remaining` progress snapshot as `done` and `close`. `--reviewer <id>` records the checker's identity on the review log, artifact, and event (defaults to the worker id), keeping maker and checker distinguishable in the audit trail. Closing an already-settled review fails with error code `already_closed` instead of silently duplicating evidence logs. The maker/checker split is derived, not declared: `review_mode` compares the closing reviewer identity against the target item's lease holder and reports `single_agent`, `independent`, or `unattributed` in the response, review log, artifact, and event — no ceremony note required. An `unattributed` close explains itself in the output: it means the target has no recorded lease (work was never picked or its lease was released), not that the reviewer's identity was missing.
109
121
 
110
- `trace item` on a review item inlines the target item and its evidence logs under `target`, so a reviewer's first trace already contains what is being audited. The human (non-JSON) mode renders the packet: status, owner, links, logs.
122
+ `trace item` on a review item inlines the target item and its evidence logs under `target`, so a reviewer's first trace already contains what is being audited. The human (non-JSON) mode renders the packet: status, owner, links, logs. When the item has a declared route or a run recorded a profile, the trace gains a `routing` section — the declared route next to every run's actual client/profile with an advisory `mismatch` marker and a mismatch count; items without either keep the exact pre-routing trace shape.
123
+
124
+ `doctor` also reports the agent registry in all states without ever failing: absent (informational hint), degraded (parse error with line context), or loaded with profile/route counts, validation warnings, and per-artifact drift — a rendered role file whose content no longer matches what the current registry would render is flagged `drifted` with a `planr install <client> --force` hint, while files without the generated-from header are the user's (`manual`) and never flagged.
111
125
 
112
126
  `done` is the compound worker command: it writes a completion log, then requests a review (`--review`) or closes the item, and optionally picks the next ready item (`--next`). Without `--next`, the response's `next` field carries the exact follow-up command instead (`planr pick --work-type review --json` after a review request, `planr pick --json` after a close), so every settlement output ends in an action. It chains the same single-owner operations as `log add`, `review request`, `close`, and `pick` — identical evidence, fewer commands. `done`, `close`, and `review close` report what the settlement `unlocked` (id, title, work type of every item that became ready), `done` and `close` echo the item's `post_condition` at completion time, and a `hint` asks for `--cmd`/`--tests` evidence when downstream items depend on an item that closed without any. `done`, `close`, `review close`, and the pick packet include a `remaining` progress snapshot so loop agents can evaluate their stop condition without an extra `map status` call. `remaining.counts` always carries the full status vocabulary (`pending`, `ready`, `picked`, `running`, `in_review`, `blocked`, `failed`, `cancelled`, `closed`, `closed_partial`) with explicit zeros — a missing count never has to be inferred.
113
127
 
@@ -115,6 +129,10 @@ With `--json`, responses follow one convention so agents never guess where data
115
129
 
116
130
  `pick --work-type <type>` restricts the lease to one work type, so checker agents pick only `review` items and makers only work items. `pick --plan <plan-id>` restricts the lease to one plan's items, so plan-scoped goal runs never pick work outside their contract even when other plans share the board; an unknown plan id is an error, never a silent unscoped pick. Both filters are available on MCP `planr_pick_item` and HTTP `POST /v1/pick` (`work_type`, `plan`). A null pick is never blind: `{"item": null}` carries a `reason` (`empty_map`, `all_settled`, `nothing_ready`, `ready_items_excluded_by_filter`) and the `remaining` snapshot. When ready work exists but the active filters rejected all of it, `excluded` lists each ready item with the cause (`work_type` mismatch, outside the `--plan` scope, or just requested by this worker) and `repair` carries the exact pick commands that would lease that work — across CLI, MCP, and HTTP. On a review item, `close_effect` previews the full `--close-target` cascade: it lists the work that closing the review (and with it the reviewed item) would unlock.
117
131
 
132
+ `agents init` writes a commented starter registry with the cost-tiering defaults (premium driver that keeps the verdicts, standard steerable implementer, budget helper for token-hungry side work, plus code/fix/review/default routes) and names the follow-up commands; an existing `.planr/agents.toml` is never overwritten without `--force`. Individual pools generate from repeatable spec flags — `--profile designer=claude-code/opus@high#premium` declares a profile, `--skill designer=frontend-design` pairs it with a skill, `--route frontend=designer,driver` routes a use-case work type with fallbacks, `--default-route` catches the rest; validation is fail-closed (unknown profile references and malformed specs error, naming the grammar, before anything is written), and consistent specs generate a zero-warning registry. `--interactive` walks the same questions as guided prompts (requires a terminal; conflicts with spec flags) and can render the host role files at the end. `agents list` and `agents check` inspect the agent profile registry (`.planr/agents.toml`): named profiles (host client, model, effort, cost tier) and advisory routes from work selectors to profiles. When a registry resolves for a picked item, the pick packet carries a `routing` block — profile, client, model, effort, cost tier, fallback chain, and the matched selector — resolved with precedence per-item override > `work_type` > `plan` > default route. `item route` shows an item's resolved route and its source (`override` or `policy`), pins a registry profile with `--set <profile>` (emits `route_overridden`), and unpins with `--clear` (emits `route_override_cleared`); a pinned profile that later disappears from the registry falls back to policy routing with a repair hint. The same JSON shapes are exposed over MCP: `planr_agents_list` and `planr_item_route` read, `planr_item_route_set` and `planr_item_route_clear` mutate. Routing is advisory: Planr never dispatches models, a missing registry just omits the block, a malformed one degrades picking to no-routing (only `agents check` fails, with the parser's line context), and validation warnings (unknown profile references, duplicate selectors, review work on a budget tier, secret-like values) never affect exit codes. When a registry is present, `install codex|claude|cursor` renders the subagent role files with model pins from it — the `work_type=code` route pins the worker, the `work_type=review` route pins the reviewer, and a role only pins profiles whose `client` matches the install target (a Cursor-profile review route never writes a Cursor model into a Codex TOML). Rendered files carry a `# generated from .planr/agents.toml` header; without a registry (or when no matching route resolves) the shipped static role files are written byte-identically, and existing files are never overwritten without `install --force`. Full guide: [Model Routing](MODEL_ROUTING.md).
133
+
134
+ `log add` and `done` accept `--profile <id>` — the registry profile the run actually executed on (`PLANR_PROFILE` env is the fallback, so rendered role files can export it). The profile is stored on the recorded run; when it differs from the item's declared route, Planr emits an advisory `route_mismatch_observed` event (declared, actual, run id) visible in `event list --item`. Runs without a profile, logs without commands/tests, and projects without a registry produce no comparison and no event, and mismatches never block logging, review, or closure. The MCP `planr_log_add` tool and `POST .../log` accept the same optional `profile`.
135
+
118
136
  `artifact add` infers the mime type from the file extension when `--path` is given without `--mime` (PNG screenshots land as `image/png`, not `text/plain`); inline `--content` defaults to `text/plain`. The same inference applies on MCP `planr_artifact_add` and HTTP `POST /v1/artifacts`.
119
137
 
120
138
  `review evidence` reports Git worktree status scoped to files named by item logs or artifacts. Dirty files without item provenance are listed as unrelated and are not treated as agent-owned evidence. `--pr-url` records an item-scoped PR reference before returning the evidence package.
@@ -123,6 +141,6 @@ With `--json`, responses follow one convention so agents never guess where data
123
141
 
124
142
  `serve` exposes the local review workspace at `/review` and its JSON projection at `/v1/review-workspace`.
125
143
 
126
- `prompt` prints ready-to-use agent instructions without editing global config. Use `prompt cli` for shell agents, `prompt mcp` for MCP setup text, and `prompt http` for localhost automation/review workspace usage.
144
+ `prompt` prints ready-to-use agent instructions without editing global config. Use `prompt cli` for shell agents, `prompt mcp` for MCP setup text, and `prompt http` for localhost automation/review workspace usage. `prompt routing` emits a paste-ready model-prioritization block for the driver session: the route table from `.planr/agents.toml` (every route, profile, and fallback), per-host dispatch guidance with the known traps (Codex `fork_turns: "none"` and session-restart requirement, the Claude `CLAUDE_CODE_SUBAGENT_MODEL` env preemption, Cursor's silent plan/policy/Max-Mode overrides), and process-dispatch snippets (`codex exec`, `pi`, `opencode run`) for hosts without role files; `--json` carries the same content structured, and a missing or unreadable registry still prints the host guidance with a pointer instead of failing.
127
145
 
128
- `export` writes a reusable Planr JSON package with package requirements metadata, graph state, contexts, optional logs, optional plan file snapshots, and review artifact snapshots. `import` previews JSON packages by default and mutates only with `--confirm`.
146
+ `export` writes a reusable Planr JSON package with package requirements metadata, graph state, contexts, optional logs, optional plan file snapshots, review artifact snapshots, and — when present — the agent registry (`.planr/agents.toml`) as a raw snapshot. `import` previews JSON packages by default and mutates only with `--confirm`; the preview names the registry with its exact action (`create`, `identical`, or `conflict`), and an existing registry that differs is never overwritten — the conflict is reported with a hint to remove the local file first. Packages without a registry import unchanged.
package/docs/CODEX.md CHANGED
@@ -17,10 +17,20 @@ Codex `/goal` is the recommended orchestrator for autonomous Planr runs: `/goal`
17
17
 
18
18
  ```text
19
19
  $planr-goal <your goal>
20
- /goal Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract). Continue until the contract holds or the iteration budget is exhausted.
20
+ /goal Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract). Continue until the contract holds or the iteration budget is exhausted. You are operating autonomously: the user is not watching, so never end a turn on a plan, a question, or a promise — proceed until the contract holds or you are blocked on input only the user can provide.
21
21
  ```
22
22
 
23
- The stop condition lives in Planr (`--tag goal-contract`), so a dead session resumes with the same starter line from zero chat context. Full workflow, recovery, and per-host variants: [Long-Running Goals](GOALS.md).
23
+ The stop condition lives in Planr (`--tag goal-contract`), so a dead session resumes with the same starter line from zero chat context.
24
+
25
+ Run the driver session on your strongest tier (e.g. `gpt-5.5` at `model_reasoning_effort = "high"` in `~/.codex/config.toml`). The provisioned worker role pins a cheaper tier; the reviewer deliberately inherits the session model:
26
+
27
+ ```toml
28
+ # .codex/agents/planr-worker.toml
29
+ model = "gpt-5.5"
30
+ model_reasoning_effort = "medium"
31
+ ```
32
+
33
+ Verify the pin once: some Codex versions ignore custom agent files on spawn ([openai/codex#26868](https://github.com/openai/codex/issues/26868)) and the child silently inherits the parent model. Spawn `planr_worker` on a trivial item and confirm the child metadata shows the pinned model and effort with a non-null `agent_path`. Full workflow, recovery, per-host variants, and the tiering rationale: [Long-Running Goals](GOALS.md).
24
34
 
25
35
  ## MCP
26
36
 
package/docs/CURSOR.md CHANGED
@@ -1,18 +1,102 @@
1
1
  # Cursor Integration
2
2
 
3
- ## Plugin
3
+ Cursor is a first-class Planr client. One command wires a project completely — MCP tools, the worker/reviewer subagents, and the full skill set:
4
+
5
+ ```bash
6
+ planr install cursor
7
+ ```
8
+
9
+ This writes only repository-local files (never global Cursor config):
4
10
 
5
- The repository carries a Cursor plugin manifest (`.cursor-plugin/plugin.json`) bundling the Planr skills. Marketplace listing is pending review; until it is listed, use MCP plus the CLI prompt below. See [Skills](SKILLS.md) for the skill workflow and [Long-Running Goals](GOALS.md) for running goal loops without a native `/goal` primitive.
11
+ | Path | Purpose |
12
+ | --- | --- |
13
+ | `.cursor/mcp.json` | project-scoped stdio MCP server (`planr mcp`) with the 44 Planr tools |
14
+ | `.cursor/agents/planr-worker.md` | worker subagent: implements exactly one picked item, then requests review and stops |
15
+ | `.cursor/agents/planr-reviewer.md` | reviewer subagent: audits evidence and closes the review with a verdict |
16
+ | `.cursor/skills/planr*/SKILL.md` | all ten Planr skills (`planr`, `planr-goal`, `planr-loop`, stage and capability skills) |
6
17
 
7
- ## MCP
18
+ Re-running the command refreshes `.cursor/mcp.json` but never overwrites edited agent or skill files. `planr project init "My Product" --client cursor` (or `--client all`) provisions the same subagent roles at init time. Verify with `planr doctor --client cursor`.
19
+
20
+ ## Skills And Agents Only (No MCP)
21
+
22
+ The skills are CLI-first — they drive the `planr` binary directly through the terminal — so MCP is optional. For a plugin-style install that writes only the subagents and skills:
23
+
24
+ ```bash
25
+ planr install cursor --no-mcp
26
+ ```
27
+
28
+ This writes `.cursor/agents/` and `.cursor/skills/` and nothing else: no `.cursor/mcp.json`, no deeplink. Everything below (subagent dispatch, parallel work, goal loops) works identically in this mode because the skills call `planr pick`, `planr done`, `planr review ...` as shell commands. `--no-mcp --dry-run` lists the files that would be written. The flag works for `claude` and `codex` too (roles only; their skills ship via each host's plugin system).
29
+
30
+ ## One-Click MCP Install
31
+
32
+ For user-level setup (all projects, no repo files), the dry-run prints a Cursor deeplink:
8
33
 
9
34
  ```bash
10
35
  planr install cursor --dry-run
11
- planr install cursor
12
- planr doctor --client cursor
13
36
  ```
14
37
 
15
- Dry-run prints `.cursor/mcp.json` content. The non-dry command writes the project-scoped config.
38
+ ```text
39
+ cursor://anysphere.cursor-deeplink/mcp/install?name=planr&config=eyJhcmdzIjpbIm1jcCJdLCJjb21tYW5kIjoicGxhbnIifQ==
40
+ ```
41
+
42
+ Open the link (or paste it into a browser) and Cursor prompts to install the server. The embedded config is `{"command": "planr", "args": ["mcp"]}` with no `--db` path on purpose: Cursor starts the server in the workspace directory, so every project resolves its own `.planr/planr.sqlite`.
43
+
44
+ ## Plugin
45
+
46
+ The repository carries a Cursor plugin manifest (`.cursor-plugin/plugin.json`) bundling the skills and both subagents. Marketplace listing is pending review; until it is listed:
47
+
48
+ - `planr install cursor` (above) provides the identical component set per project, or
49
+ - install the plugin locally: copy the repository to `~/.cursor/plugins/local/planr` and reload Cursor.
50
+
51
+ ## Multitasking With Cursor's Built-In Features
52
+
53
+ Cursor's subagents, background execution, and parallel agents map directly onto Planr's maker/checker loop. The Planr map is the shared state, so concurrent Cursor agents coordinate through `planr pick` leases instead of stepping on each other.
54
+
55
+ ### Subagent dispatch (maker/checker)
56
+
57
+ The installed subagents are dispatched from any Agent chat with `/name` or by mention:
58
+
59
+ ```text
60
+ /planr-worker implement item <item-id>
61
+ /planr-reviewer review item <item-id>
62
+ ```
63
+
64
+ The worker preloads the `planr-work` protocol (implement one item, log evidence, request review, stop); the reviewer preloads `planr-review` (audit the diff, rerun logged commands, close with a verdict). Because each subagent runs in its own context window, the driving chat stays focused on `plan audit`, dispatch decisions, and synthesis — the same division of labor as Codex `/goal` and Claude Code (see [Long-Running Goals](GOALS.md)).
65
+
66
+ Cost tiering: the worker file ships with `model: inherit`; edit its frontmatter to pin a cheaper Cursor model id when dispatch cost matters. Leave the reviewer on `inherit` — make workers cheap, not the verdict.
67
+
68
+ ### Parallel and background work
69
+
70
+ - **Parallel subagents:** ask the driver to dispatch several workers at once ("implement items A, B, and C in parallel with planr-worker subagents"). Each worker calls `planr pick` (or is handed its item id); the map's single-owner lease guarantees no two agents hold the same item, and `planr recover sweep` reclaims work from any that die.
71
+ - **Background subagents:** long items can run as background subagents; evidence logging doubles as the liveness heartbeat, so `planr pick stale` shows honestly stuck work.
72
+ - **Cloud agents (`/in-cloud`):** cloud VMs do not share your local `.planr` database or local MCP config. Give cloud agents the CLI workflow instead (`planr prompt cli --client cursor`) and let them commit evidence through normal Planr CLI calls in their own checkout.
73
+
74
+ ### Parallel agents in worktrees
75
+
76
+ Cursor's parallel agents run in separate git worktrees, and each worktree would otherwise get its own copy of `.planr/planr.sqlite` — forking the map. Keep one authoritative map by pointing every worktree at a shared absolute database path:
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "planr": {"command": "planr", "args": ["--db", "/absolute/path/to/main-checkout/.planr/planr.sqlite", "mcp"]}
82
+ }
83
+ }
84
+ ```
85
+
86
+ `planr install cursor` already writes the absolute path of the current checkout, so worktrees created from an installed project inherit the right value — verify with `planr project show --json` from each worktree. One picked item per agent instance stays the rule (`plugins/planr/skills/planr-loop/SKILL.md`, Hard Rules).
87
+
88
+ ### Goal loops
89
+
90
+ Cursor has no `/goal` primitive; the human (or an automation) is the re-dispatcher:
91
+
92
+ ```text
93
+ Use $planr-goal: <your goal>
94
+ Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract).
95
+ ```
96
+
97
+ `$planr-loop` iterates inside the session, dispatching `/planr-worker` and `/planr-reviewer` per item. If the session ends before `planr plan audit <plan-id>` holds, send the same starter line in a fresh session — the map, the stored contract, and open reviews carry the run, not chat history.
98
+
99
+ ## HTTP And Review Feedback
16
100
 
17
101
  Planr V1 defaults to MCP stdio. Local HTTP/SSE is available through:
18
102
 
@@ -27,4 +111,4 @@ planr review annotate <item-id> --message "Cursor review note" --severity warnin
27
111
  planr review ingest <item-id> --from .planr/tmp/cursor-review.json
28
112
  ```
29
113
 
30
- The project-scoped `.cursor/mcp.json` is the only file written by `planr install cursor`. Review ingestion does not auto-close or auto-approve work.
114
+ Review ingestion does not auto-close or auto-approve work.
@@ -0,0 +1,138 @@
1
+ # Worked Example: Routing a Small Web App
2
+
3
+ A complete, replayable walkthrough of [model routing](MODEL_ROUTING.md) on a real shape of work: a todo web app with a frontend and a backend, implemented by different models. Every output below is from an actual run — copy the commands into an empty directory and you get the same results.
4
+
5
+ The pool we want:
6
+
7
+ | Use case | Who runs it | Paired skill |
8
+ | --- | --- | --- |
9
+ | planning + review | Fable on Cursor (the driver session) | — |
10
+ | frontend, design | Opus on Claude Code | `frontend-design` |
11
+ | backend | GPT-5.5 on Codex | `planr-work` |
12
+
13
+ ## Step 1: Project and pool — two commands, once
14
+
15
+ ```bash
16
+ planr project init "Todo Webapp"
17
+
18
+ planr agents init \
19
+ --profile driver=cursor/fable-5@high#premium \
20
+ --profile frontender=claude-code/opus@high#premium \
21
+ --profile backender=codex/gpt-5.5@xhigh#standard \
22
+ --skill frontender=frontend-design \
23
+ --skill backender=planr-work \
24
+ --route frontend=frontender,driver \
25
+ --route backend=backender,driver \
26
+ --route review=driver \
27
+ --default-route backender,driver
28
+
29
+ planr agents check
30
+ ```
31
+
32
+ ```text
33
+ wrote .planr/agents.toml (generated from the flag specs)
34
+ agent registry check passed
35
+ ```
36
+
37
+ Prefer questions over flags? `planr agents init --interactive` walks the same inputs as guided prompts and can render the host role files at the end. Either way, validation is fail-closed: a typo in a profile reference errors before anything is written.
38
+
39
+ Note what the routes encode: review work is pinned to the premium driver (verdicts stay strong), everything else runs on the cheaper tier its use case calls for, and every route falls back to the driver when the primary hits a rate limit.
40
+
41
+ ## Step 2: Items carry the use case as their work type
42
+
43
+ Work types are free-form, so the use case is just `--work-type`:
44
+
45
+ ```bash
46
+ planr item create "API: task CRUD endpoints" \
47
+ --description "Express routes GET/POST/PATCH/DELETE /api/tasks with sqlite store" \
48
+ --work-type backend
49
+
50
+ planr item create "UI: task list and add form" \
51
+ --description "React list view + optimistic add form against /api/tasks" \
52
+ --work-type frontend
53
+
54
+ planr item create "UI: design pass on empty and error states" \
55
+ --description "Empty state, loading skeleton, error toast" \
56
+ --work-type frontend
57
+ ```
58
+
59
+ ## Step 3: The pick decides who works
60
+
61
+ Same board, two different answers. The backend pull:
62
+
63
+ ```bash
64
+ planr pick --work-type backend --json
65
+ ```
66
+
67
+ ```json
68
+ "routing": {
69
+ "profile": "backender",
70
+ "client": "codex",
71
+ "model": "gpt-5.5",
72
+ "effort": "xhigh",
73
+ "cost_tier": "standard",
74
+ "skill": "planr-work",
75
+ "fallbacks": ["driver"],
76
+ "matched_selector": "work_type=backend"
77
+ }
78
+ ```
79
+
80
+ And the frontend pull:
81
+
82
+ ```bash
83
+ planr pick --work-type frontend --json
84
+ ```
85
+
86
+ ```json
87
+ "routing": {
88
+ "profile": "frontender",
89
+ "client": "claude-code",
90
+ "model": "opus",
91
+ "skill": "frontend-design",
92
+ "fallbacks": ["driver"],
93
+ "matched_selector": "work_type=frontend"
94
+ }
95
+ ```
96
+
97
+ The driver session dispatches from the packet alone: the backend item goes to Codex (`codex exec --model gpt-5.5 -c model_reasoning_effort="xhigh" ...` — `planr prompt routing` prints this snippet pre-filled), the frontend item to a Claude Code subagent dispatched with its paired skill (`Use $frontend-design on item <id>`). Two workers can pull in parallel — each `pick --work-type <use-case>` takes its own lane, and the pick lease keeps one owner per item.
98
+
99
+ ## Step 4: Workers close with evidence and their profile
100
+
101
+ ```bash
102
+ planr done <item-id> \
103
+ --summary "CRUD endpoints implemented; 8 supertest cases green" \
104
+ --files server/routes/tasks.ts \
105
+ --tests "vitest --run: 8 passed" \
106
+ --profile backender
107
+ ```
108
+
109
+ `--profile` (or the `PLANR_PROFILE` env var) records which registry profile the run actually executed on. It is part of the evidence, not a formality — the next step is why.
110
+
111
+ ## Step 5: The trace proves the plan was followed
112
+
113
+ Every host has a silent override path (env clamps, admin policies, fork semantics — see the [host matrix](MODEL_ROUTING.md#host-matrix)), so a pin alone is not proof. In this run, the backend item was closed on the declared profile and the frontend item deliberately on the wrong one:
114
+
115
+ ```bash
116
+ planr trace item <backend-item>
117
+ planr trace item <frontend-item>
118
+ ```
119
+
120
+ ```text
121
+ routing declared: backender (work_type=backend)
122
+ run run-5552fad6 profile backender
123
+
124
+ routing declared: frontender (work_type=frontend)
125
+ run run-bc0994cb profile driver (differs from declared route; advisory)
126
+ ```
127
+
128
+ The mismatch also lands as a `route_mismatch_observed` event (`planr event list`). Advisory by design: nothing blocked, but the drift is on record instead of invisible.
129
+
130
+ ## The whole model in one line each
131
+
132
+ 1. **Declare** the pool once: `planr agents init` (flags, wizard, or the plain scaffold).
133
+ 2. **Tag** items with their use case: `--work-type frontend|backend|...` — free-form.
134
+ 3. **Pick** routes: every packet carries profile, model, skill, and fallbacks.
135
+ 4. **Deliver** with `--profile` as part of the evidence.
136
+ 5. **Trace** proves declared vs. actual — silent overrides get caught.
137
+
138
+ One-off exceptions never need a registry edit: `planr item route <id> --set driver` pins a single gnarly item to the premium tier and `--clear` restores policy. Details and failure behavior: [Model Routing](MODEL_ROUTING.md); the cost logic behind the tiers: [GOALS.md Cost Tiering](GOALS.md#cost-tiering).
package/docs/GOALS.md CHANGED
@@ -39,9 +39,11 @@ planr context add "GOAL CONTRACT pl-csv-export: DONE when every in-scope map ite
39
39
  ### 2. Execute — the loop driver runs `$planr-loop`
40
40
 
41
41
  ```text
42
- /goal Use $planr-loop on plan pl-csv-export. The loop contract is stored in planr context (tag: goal-contract). Continue until the contract holds or the iteration budget is exhausted.
42
+ /goal Use $planr-loop on plan pl-csv-export. The loop contract is stored in planr context (tag: goal-contract). Continue until the contract holds or the iteration budget is exhausted. You are operating autonomously: the user is not watching, so never end a turn on a plan, a question, or a promise — proceed until the contract holds or you are blocked on input only the user can provide.
43
43
  ```
44
44
 
45
+ The autonomy clause matters on long runs: deep into a session, frontier models occasionally end a turn with a statement of intent instead of the corresponding action, or pause to ask permission they already have. Stating the operating mode up front prevents both.
46
+
45
47
  Each iteration follows the `$planr-loop` protocol:
46
48
 
47
49
  ```text
@@ -100,7 +102,7 @@ $planr-goal <your goal> # prep: plan, map, contract, starter command
100
102
  /goal Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract).
101
103
  ```
102
104
 
103
- The `/goal` PM dispatches `spawn the planr_worker agent for item <id>` and `spawn the planr_reviewer agent for item <id>` — the role files preload `$planr-work` and `$planr-review`, so dispatches stay one line. Codex Automations work the same way: set the automation prompt to the starter line.
105
+ The `/goal` PM dispatches `spawn the planr_worker agent for item <id>` and `spawn the planr_reviewer agent for item <id>` — the role files preload `$planr-work` and `$planr-review`, so dispatches stay one line. Codex Automations work the same way: set the automation prompt to the starter line. The provisioned worker role pins a cheaper effort tier; see [Cost Tiering](#cost-tiering).
104
106
 
105
107
  ### Claude Code
106
108
 
@@ -111,23 +113,59 @@ Same shape via the plugin (`/plugin install planr@planr`), which registers the `
111
113
  /goal Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract).
112
114
  ```
113
115
 
114
- `/loop` works for fixed-cadence runs instead of goal-conditioned ones.
116
+ `/loop` works for fixed-cadence runs instead of goal-conditioned ones. The registered worker subagent pins a cheaper model tier; see [Cost Tiering](#cost-tiering).
117
+
118
+ ### Cursor
115
119
 
116
- ### Cursor and hosts without a loop primitive
120
+ No `/goal` primitive, but full subagent support. Install once:
121
+
122
+ ```bash
123
+ planr install cursor # writes .cursor/mcp.json, .cursor/agents/planr-worker.md + planr-reviewer.md, and the skills
124
+ ```
117
125
 
118
- Identical protocol; the human (or a background agent) is the re-dispatcher:
126
+ Then run the identical protocol with the human (or an automation) as the re-dispatcher:
119
127
 
120
128
  ```text
121
129
  Use $planr-goal: <your goal>
122
130
  Use $planr-loop on plan <plan-id>. The loop contract is stored in planr context (tag: goal-contract).
123
131
  ```
124
132
 
125
- `$planr-loop` iterates within the session under its own budget. If the session ends before the contract holds, dispatch the same line again — recovery is identical to the `/goal` case.
133
+ `$planr-loop` iterates within the session under its own budget, dispatching `/planr-worker` and `/planr-reviewer` per item — the provisioned subagents preload the work and review protocols, so dispatches stay one line. If the session ends before the contract holds, dispatch the same line again — recovery is identical to the `/goal` case. Parallelism, background subagents, and worktree caveats: [Cursor](CURSOR.md).
134
+
135
+ ### Hosts without a loop primitive
136
+
137
+ Identical protocol; the human (or a background agent) is the re-dispatcher, and worker/reviewer run as separate sequential dispatches when the host has no subagents.
126
138
 
127
139
  ### Plain MCP clients
128
140
 
129
141
  Any MCP-capable agent uses the same flow over `planr mcp`. Every session starts with map state, so the loop is resumable by construction.
130
142
 
143
+ ## Cost Tiering
144
+
145
+ A goal run has three roles with different intelligence needs, so they should not all run on the same model tier:
146
+
147
+ - **Driver** (the `/goal` session): decomposition, dispatch decisions, conflict resolution, final synthesis. Run it on the strongest model you have — this is never configured in Planr files, it is simply the model of the main session.
148
+ - **Worker**: bounded implementation. `planr pick --json` is a complete handoff packet (one item, scope, evidence format, stop after review request), so the worker runs safely on a cheaper tier.
149
+ - **Reviewer**: the truth gate. It inherits the driver's model on purpose — make workers cheap, not the verdict.
150
+
151
+ Where each host configures the worker tier (the shipped role files carry these defaults):
152
+
153
+ | Host | Driver | Worker | Configured in |
154
+ | --- | --- | --- | --- |
155
+ | Codex | session default (e.g. `gpt-5.5` at `high`) | `model = "gpt-5.5"`, `model_reasoning_effort = "medium"` | `.codex/agents/planr-worker.toml` |
156
+ | Claude Code | session model (e.g. `fable` at `high` via `/model` + `/effort`) | `model: opus`, `effort: medium` | `planr-worker.md` frontmatter |
157
+ | Cursor | chat model of the driving session | `model: inherit` by default; pin a cheaper Cursor model id | `.cursor/agents/planr-worker.md` frontmatter |
158
+
159
+ The defaults use aliases and generic names so they track model generations; pin a full model id (e.g. `claude-opus-4-8`) only if you need determinism, and use `model: sonnet` as the budget alternative. The role files are user-owned copies — `planr project init` provisions them once and never overwrites local edits — so changing the tier is editing one line.
160
+
161
+ To declare the tiering itself — which model handles which work type, with fallbacks for rate limits — use the agent profile registry (`.planr/agents.toml`): the routing recommendation then travels inside every `planr pick --json` packet, so the driver dispatches the right tier without consulting this table mid-run. `planr agents init` writes a working starter registry with these defaults; see [Model Routing](MODEL_ROUTING.md). The role files above still carry the host-native pins (`planr install <client> --force` re-renders them from the registry); the registry is the declared source of truth for the routing decision.
162
+
163
+ Traps to verify once per setup — every one of them is silent (the run still works, just at driver prices), which is why the smoke test is worth the two minutes:
164
+
165
+ - **Claude Code:** the `CLAUDE_CODE_SUBAGENT_MODEL` environment variable clamps every subagent's `model:` frontmatter and per-invocation model with no signal in the `tool_result` ([anthropics/claude-code#57718](https://github.com/anthropics/claude-code/issues/57718)); since v2.1.196, setting it to `inherit` behaves like unset, so that is the safe pin for "driver decides". Org-managed `availableModels` allowlists are equally quiet: a frontmatter model outside the allowlist falls back to inherit without warning. Make sure the env var is unset (or `inherit`), then dispatch the worker on a trivial item and confirm the subagent's messages in the session log (`~/.claude/projects/<project>/*.jsonl`) carry the worker model, not the driver's.
166
+ - **Codex:** the spawn regressions that made children ignore custom agent files ([openai/codex#26868](https://github.com/openai/codex/issues/26868), [#26363](https://github.com/openai/codex/issues/26363)) are fixed in v0.138+, but two traps remain. First, `fork_turns = "all"` (the multi-agent v2 default) intentionally drops the child's `agent_type` and `model` so the fork replays the parent exactly — dispatch that should honor the worker pin needs `fork_turns = "none"` or a partial fork. Second, the role registry is loaded once at session start ([#26408](https://github.com/openai/codex/issues/26408)): after editing or re-rendering `.codex/agents/*.toml`, restart the session, or the child spawns from the stale definitions. Spawn `planr_worker` on a trivial item and confirm the child metadata shows the pinned model and effort with a non-null `agent_path`.
167
+ - **Cursor:** `model: <id>` in `.cursor/agents/planr-worker.md` frontmatter can be overridden without an error by team-admin model policies, plan availability (a model your plan lacks resolves to a fallback), and Max-Mode-only models. On legacy request-based plans, subagents are forced onto Composer regardless of the pin. Dispatch the worker once and check which model the subagent transcript reports before trusting the pin.
168
+
131
169
  ## Coming From Other Goal Tools
132
170
 
133
171
  If you already run goal workflows with other tools, the concepts map directly:
@@ -151,5 +189,6 @@ Using such tools for intake or visualization alongside Planr is fine — keep on
151
189
  - The maker never closes its own review; single-agent hosts record `review-mode` honestly.
152
190
  - Two iterations without map-state movement -> stop and report instead of grinding.
153
191
  - Destructive or out-of-repo side effects always go behind `planr approval request`.
192
+ - Lessons that should outlive the iteration (a confirmed approach, a correction, a dead end) go into `planr context add "..." --tag lesson` — the next iteration or a fresh session recovers them with `planr context list --tag lesson`, not from chat history.
154
193
 
155
194
  See also: [Skills](SKILLS.md), [Operating Model](OPERATING_MODEL.md), [Task Graph Model](TASK_GRAPH_MODEL.md), [Codex](CODEX.md), [Claude Code](CLAUDE_CODE.md), [Cursor](CURSOR.md).
package/docs/INSTALL.md CHANGED
@@ -72,7 +72,9 @@ planr prompt cli --client codex
72
72
  planr prompt http
73
73
  ```
74
74
 
75
- `planr install claude` writes a project `.mcp.json`; `planr install cursor` writes `.cursor/mcp.json`; `planr install codex` writes a project MCP snippet. All install commands also provision the `planr-worker` and `planr-reviewer` subagent role files (`.codex/agents/`, `.claude/agents/`) without overwriting existing edits; `planr project init --client <client|all>` does the same at init time. Dry-runs print the exact config and scope notes first.
75
+ `planr install claude` writes a project `.mcp.json`; `planr install cursor` writes `.cursor/mcp.json` plus the Planr skills under `.cursor/skills/` and prints a one-click user-level MCP deeplink; `planr install codex` writes a project MCP snippet. All install commands also provision the `planr-worker` and `planr-reviewer` subagent role files (`.codex/agents/`, `.claude/agents/`, `.cursor/agents/`) without overwriting existing edits; `planr project init --client <client|all>` does the same at init time. Dry-runs print the exact config and scope notes first.
76
+
77
+ Skills-and-agents-only setups (no MCP) use `--no-mcp`: `planr install cursor --no-mcp` writes the subagents and skills but no MCP config — the skills drive the `planr` CLI directly, so nothing is lost except MCP tool access.
76
78
 
77
79
  Runtime surfaces:
78
80