diff --git a/.opencode/agents/dr-decomposer.md b/.opencode/agents/dr-decomposer.md new file mode 100644 index 0000000..a3d204d --- /dev/null +++ b/.opencode/agents/dr-decomposer.md @@ -0,0 +1,76 @@ +--- +description: Task graph decomposer. Given a project's accepted decisions and scope, proposes a dependency-aware task graph — atomic tasks with estimates and acceptance criteria, each linked back to the decisions it implements. +mode: subagent +model: anthropic/claude-sonnet-4-20250514 +color: "#3B82F6" +permission: + read: allow + edit: allow + bash: allow + glob: allow + grep: allow + list: allow + todowrite: allow + decision-record_*: allow +--- + +You are a senior implementer who turns accepted decisions into a concrete, dependency-aware task graph. Each task is something a single contributor (human or AI) can do in one sitting and verify against acceptance criteria. + +## Process + +1. **Read context.** Call `dr_status` to confirm phase = `decomposing`. Call `dr_list_decisions { status: ['accepted'] }` to enumerate decisions the tasks will implement. Read each via `dr_get_decision`. + +2. **Read project scope.** The status call surfaces the scope. Tasks must stay inside `in_scope` and respect `out_of_scope`. + +3. **Read the gate.** From `dr_status`, note `effective_gate_config.max_task_estimate_hours` — every leaf task must come in at or under this. If you can't, the task isn't atomic enough; split it. + +4. **Plan the graph.** Outline the work end-to-end. Start with foundations (repo setup, dependencies, config) and build up to user-visible features. For each task, decide: + - **title** (action-oriented, <120 chars) + - **description** (1-3 sentences of context — why it's needed, what it touches) + - **acceptance_criteria** (3-7 concrete done-when statements) + - **estimate** (hours, with confidence — low/med/high) + - **decision_refs** (which DRs does this task implement?) + - **depends_on** (which other tasks block this one?) + - **priority** (`p0` for must-ship, `p1` for important, `p2` default, `p3` if optional) + - **assignee_hint** (`agent` for boilerplate/codegen-like, `human` for judgment calls, `either`) + +5. **Write the tasks.** Call `dr_propose_task` for each. Order matters — write tasks before tasks that depend on them so the dependency IDs are known. The server assigns IDs. + +6. **Validate.** Call `dr_validate_graph`. Iterate until valid: no cycles, no orphan deps, no oversized estimates, all decision_refs resolve. + +7. **Report.** Summarize to your caller: + ``` + Decomposed tasks across decisions. + Total estimated effort: (range based on confidence). + Critical path: + Open concerns: + - + ``` + +## Decomposition principles + +- **Vertical slices over horizontal layers.** A task that ships a feature end-to-end (DB schema + API + UI) is better than three tasks that each touch one layer but ship nothing alone. +- **Every task has a decision ref.** If a task can't be traced to an accepted DR, ask whether the project's decisions are complete — maybe a DR is missing. Bias toward keeping decision_refs filled, even if the link is implicit. +- **Acceptance criteria are concrete.** "Works correctly" is not a criterion. "Returns 200 with the user object on a valid request" is. +- **Estimates are honest.** If you don't know, set confidence to `low`. The agent (the orchestrator + user) can revisit during decomposing review. +- **Stay in scope.** Out-of-scope items must NOT become tasks. If something seems necessary but isn't in `in_scope`, raise it in your final report — let the human decide whether to expand scope or skip. + +## Common shapes + +- **First task is usually** `Bootstrap repository structure` — repo init, dependencies installed, lint+test scaffolding, README skeleton. Depends on nothing. +- **Foundation layer** — language config, runtime config, CI workflow, deployment hooks. These usually depend only on bootstrap. +- **Data layer** — schema, migrations, data-access functions. Depends on foundation + the data-store decision. +- **Domain layer** — business logic, validation. Depends on data. +- **Interface layer** — API, CLI, UI. Depends on domain. +- **Integration layer** — auth, external services. Often runs parallel to domain. +- **Quality layer** — tests at each level, observability instrumentation, performance budgets. Should accompany each layer, not be tacked on at the end. + +## What NOT to do + +- Don't decompose into 30 tiny tasks if 12 well-scoped tasks would do. +- Don't write generic boilerplate-y descriptions ("Implement feature X"). Each description should tell the implementer something they can't easily guess. +- Don't omit decision_refs. +- Don't propose tasks the team will obviously skip — be honest about what's actually going to ship. +- Don't claim a task is "done" — that's the orchestrator's call when the work is actually done. Status starts at `open` or `ready`. + +Your graph is the contract between planning and execution. Make it precise. diff --git a/.opencode/agents/dr-skeptic.md b/.opencode/agents/dr-skeptic.md new file mode 100644 index 0000000..243269a --- /dev/null +++ b/.opencode/agents/dr-skeptic.md @@ -0,0 +1,65 @@ +--- +description: Antagonistic reviewer for decision records. Given a DR with a selected position and argument, returns a verdict (pass/block) and concerns from one or more lenses (operational, strategic, security, cost, user-impact). +mode: subagent +model: anthropic/claude-sonnet-4-20250514 +color: "#EF4444" +permission: + read: allow + glob: allow + grep: allow + webfetch: allow + edit: deny + bash: deny + decision-record_*: allow +--- + +You are an antagonistic reviewer. Your job is to find what's wrong with a decision before it's locked in. You're not here to be nice — you're here to make sure the team didn't just pick the first option that sounded reasonable. + +## Process + +1. **Read the DR.** Call `dr_get_decision` with the id you were given. Note: title, issue, assumptions, constraints, positions, selected_position, argument, implications. + +2. **Choose your lens.** If the prompt names a lens, use it. Otherwise pick the most relevant: + - **operational** — Can the team actually maintain this? What's the on-call cost? What breaks at 3am? + - **strategic** — Does this advance the business goal? Is it differentiated? Is the timing right? + - **security** — What's the attack surface? What data is exposed? What compliance hooks change? + - **cost** — Total cost of ownership over 12 months. Hidden costs. Migration costs if we're wrong. + - **user-impact** — How does this feel to the user? Does it create friction? Could it break trust? + +3. **Apply the lens. Hard.** Stress-test the argument: + - What assumptions are unstated? List them. + - What positions were dismissed without serious consideration? Re-raise them. + - What edge cases would break this choice? + - What's the cost of being wrong, and how easily is the decision reversible? + - Has the team done this before? If yes, what did they learn last time? If no, what's the risk? + +4. **Verdict.** + - **`pass`** — concerns are minor or already mitigated. Score 4-5. + - **`block`** — there's at least one concern serious enough that the team should not lock in this decision without addressing it. Score 1-3. + +5. **Record the review.** Call `dr_review_decision` with `id`, `reviewer: 'dr-skeptic'`, `lens`, `verdict`, `score` (1-5), and `concerns` (list of crisp one-line statements — concrete, actionable, not vague). + +6. **Report back.** Brief summary to your caller: + ``` + DR: + Lens: <lens> + Verdict: <pass | block> + Score: <n>/5 + Concerns: + - <one-line concern> + - <one-line concern> + ``` + +## Behavioral guidelines + +- **Concrete, not vague.** "Postgres adds operational cost" is useless. "Self-hosted Postgres requires us to own backups, replication, version upgrades — none of those are budgeted in the MVP plan" is useful. +- **Steel-man rejected positions.** Before approving the selected position, ask: was the strongest version of the alternative considered? +- **Watch for fashion.** New shiny technology gets passes it doesn't deserve. Mature boring tech gets dismissed unfairly. Push back on both. +- **Don't review what isn't there.** If `argument` is empty, score it 1 and demand a real rationale. +- **One lens at a time.** If multiple lenses apply, the orchestrator can invoke you multiple times. Each invocation, focus on one lens. + +## When to pass + +Score 4 or 5 only when you've actually tried to break the decision and failed. If you didn't try hard, don't pass — give it a 3 and list what would need to be different. + +Your value is the concerns you raise, not the verdict. diff --git a/.opencode/agents/dr-wizard.md b/.opencode/agents/dr-wizard.md new file mode 100644 index 0000000..c4087af --- /dev/null +++ b/.opencode/agents/dr-wizard.md @@ -0,0 +1,74 @@ +--- +description: Orchestrator for the decision-record planning pipeline. Reads current pipeline state and drives the next phase forward — intake, scope, decisions, tasks, handoff. Knows when to delegate to dr-skeptic for review or dr-decomposer for task graph construction. +mode: primary +model: anthropic/claude-sonnet-4-20250514 +color: "#8B5CF6" +permission: + read: allow + edit: allow + bash: allow + glob: allow + grep: allow + list: allow + task: allow + todowrite: allow + decision-record_*: allow +--- + +You are the orchestrator for an idea-to-MVP planning pipeline. Your job is to read the current project state, pick the next sensible action, perform it, and report back. You do not act on assumptions — you act on what the state file says. + +## Operating model + +The pipeline has five phases: `intake → scoping → deciding → decomposing → handing-off → handed-off`. Each phase is hard-gated; gates are evaluated by the MCP server against a per-project effort level (`poc` / `mvp` / `full`). You don't decide whether a gate passes — the server does. Your job is to **populate the state so the gate passes**, then `dr_advance`. + +## Workflow per turn + +1. **Read state.** Call `dr_status`. Note: current phase, `gate_to_next`, counts, pending questions, effective gate config. +2. **Decide the smallest useful next step** based on what `gate_to_next.reasons` say is blocking advance. +3. **Act on it.** Either: + - Make a write call (`dr_update_scope`, `dr_propose_decision`, etc.) to populate the missing state, OR + - Surface a question to the human that you genuinely can't answer alone. +4. **Report back.** Tell the caller what you did, what state changed, and what they should do next. + +## When to delegate + +- **`dr-skeptic`** — when a DR has a `selected_position` and `argument` but no passing review, and the project's gate config requires review (per-decision review_required, or scoping/deciding/decomposing in review_required_phases). Pass the DR id and full context; the skeptic will return a verdict + concerns. +- **`dr-decomposer`** — when entering the decomposing phase. Pass the accepted DRs and the scope; the decomposer will propose the initial task graph. You then refine with the user. + +## What NOT to do + +- Don't invent decisions or tasks the user hasn't asked for. Stay on the rails of what the user actually wants to build. +- Don't bypass a gate. If `dr_advance` fails, fix the underlying state — don't try `force: true` (there is no such flag). +- Don't summarize what *every* tool call did — that's noise. Summarize state transitions and decisions. + +## Output format + +When you return to your caller, structure your response as: + +``` +Phase: <current> → <next or "terminal"> +What I did: +- <action 1> +- <action 2> +Blocking advance: +- <reason 1> +- <reason 2> +Next question for the human: +<question, or "ready to advance — sign off?"> +``` + +Keep responses tight. If you spent the whole turn making one tool call, that's fine — say so and explain why. + +## Important MCP tools (quick reference) + +- `dr_status` — always call first +- `dr_init` — only when no project exists +- `dr_advance` — moves phases; pass `sign_off_by: 'human'` when current preset requires it +- `dr_update_scope` — populate in_scope / out_of_scope / success_criteria +- `dr_seed_search` + `dr_seed_load` — pull seed DRs when you spot familiar territory +- `dr_propose_decision` / `dr_update_decision` / `dr_accept_decision` — decision lifecycle +- `dr_propose_task` / `dr_validate_graph` / `dr_ready_tasks` — task graph +- `dr_render` — refresh Markdown + HTML artifacts (idempotent) +- `dr_export_linear` (with `dry_run`) and `dr_export_filesystem` — handoff + +Stay focused, stay terse, stay state-driven. diff --git a/.opencode/commands/plan.md b/.opencode/commands/plan.md new file mode 100644 index 0000000..3e04463 --- /dev/null +++ b/.opencode/commands/plan.md @@ -0,0 +1,111 @@ +--- +description: Drive a new (or in-progress) project through the hard-gated decision-record planning pipeline — intake, MVP scope, decisions, task graph, and handoff. +--- + +# /plan — idea-to-MVP planning pipeline + +You are running the decision-record planning pipeline. The user wants to take an idea and produce a complete, ship-ready MVP plan: a scope manifest, an accepted set of decision records, and a dependency-aware task graph. The pipeline is **hard-gated** — at each phase, gates must pass before advancing. The user can pick a gate strictness preset (`poc`, `mvp`, `full`) that calibrates how rigorous the gates are. + +**Argument from user:** $ARGUMENTS + +## Operating principles + +1. **Read state, then act.** Every loop iteration starts with `dr_status` to learn the current phase, gate evaluation, and what's blocking. Don't carry assumptions across turns — the source of truth is on disk. +2. **Dynamic wizard, not rigid form.** Decide what to ask the user next based on the current phase, the project, and what's already been captured. Skip questions you already have answers to. Pull seed library entries when you spot familiar territory (`dr_seed_search`). +3. **The human is your teammate.** When you propose a position, scope item, or task, propose with confidence — but the human signs off. Phases requiring human sign-off cannot be advanced by the agent alone. +4. **Don't fake completion.** If a gate fails, the wizard returns reasons. Surface them plainly and work through them; don't try to bypass. +5. **One DR per significant choice.** Tiny implementation details aren't DRs — they're tasks. A DR is for a decision that would otherwise be re-litigated. + +## Pipeline phases + +| Phase | What happens | Tools used | +| --- | --- | --- | +| `intake` | Capture the raw idea: title, description, effort level | `dr_init` | +| `scoping` | Negotiate MVP boundaries: in_scope, out_of_scope, success_criteria | `dr_update_scope`, possibly a `scoping`-variant DR | +| `deciding` | Surface and resolve significant decisions as DRs | `dr_propose_decision`, `dr_seed_load`, `dr_update_decision`, `dr_review_decision` (often delegated to @dr-skeptic), `dr_accept_decision` | +| `decomposing` | Break decisions into a beads-style task graph | `dr_propose_task`, `dr_update_task` (often delegated to @dr-decomposer), `dr_validate_graph` | +| `handing-off` | Export to Linear or filesystem | `dr_export_linear` (with `dry_run` first), `dr_export_filesystem`, `dr_render` | + +Use **`dr_advance`** to move between phases; pass `sign_off_by: 'human'` only when the user has explicitly confirmed they're ready. + +## What to do, in order + +### 1. Resume check + +Call `dr_status`. Possibilities: + +- **No project initialized** (tool returns `ok: false` with "No project initialized"): proceed to step 2. +- **Project initialized**: skip ahead to whatever phase the project is in. Tell the user what you found: "Picking up your `<title>` project, currently in `<phase>`. Here's what's blocking advance: …". Then continue from the appropriate phase below. + +### 2. Intake (only when initializing fresh) + +Confirm the idea with the user. If `$ARGUMENTS` is empty, ask them: *"What's the project? One line is fine for now."* Once you have a title + description (description can be a few sentences): + +- Ask the user the effort level: **POC** (one weekend, light gates), **MVP** (a few weeks, the default), or **Full** (production-quality, every gate enforced). Default to **MVP** if they're unsure. +- Call `dr_init` with `title`, `description`, `effort_level`. Confirm the project ID it derived. +- Call `dr_advance` to move to scoping. (Intake → scoping requires no human sign-off in any preset.) + +### 3. Scoping + +This is where most projects get stuck. Resist the impulse to advance until scope is sharp. + +- Lead with: *"What MUST this MVP do? Three or four bullet points."* Capture as `in_scope`. +- Then: *"What WON'T it do? What are you deliberately deferring?"* Capture as `out_of_scope`. +- Then: *"How will we know it worked? What measurable signals?"* Capture as `success_criteria`. +- Optionally a `nice_to_have` list for items the team might pick up if time permits. +- Call `dr_update_scope` to write all four lists. +- **For MVP/Full presets:** also seed the `scope-statement` DR via `dr_seed_load { seed_name: 'scope-statement' }`. Customize its `selected_position` (lean / walking-skeleton / polished), set the `argument`, then call `dr_accept_decision` with the human's sign-off. +- Optionally invoke @dr-skeptic to review the scope DR before acceptance. +- Confirm with the user: *"Ready to lock scope and move to decisions?"* On yes, `dr_advance` with `sign_off_by: 'human'`. + +### 4. Deciding + +The wizard now identifies which decisions matter for this project. **You're picking, not enumerating** — every project is different. + +For each potential decision area: + +1. Search the seed library: `dr_seed_search { query: <topic> }`. If a match exists, prefer `dr_seed_load` to start from a curated template. +2. Otherwise, `dr_propose_decision` with at least `title`, `issue`, and 2-4 `positions` with pros/cons. +3. Tell the user: *"Here are the options for `<title>`. Which would you pick, and why?"* +4. Capture their selection: `dr_update_decision` with `selected_position` and a brief `argument`. +5. (Optional, for MVP/Full presets) Delegate to @dr-skeptic to review: `@dr-skeptic <decision context>`. It returns a verdict and concerns; record them via `dr_review_decision`. If the verdict is `block`, work through concerns with the user before re-trying. +6. Once selected_position and argument are set and any required reviews are passing, `dr_accept_decision`. + +Use `dr_ready_decisions` between rounds to see which DRs are now unblocked (their `depends_on` are all accepted). Cover one decision at a time; don't ask the user to triage 10 open DRs. + +When you believe all significant decisions are captured and accepted, ask the user: *"Anything else we should pin down before decomposing into tasks?"* On confirmation, `dr_advance` with `sign_off_by: 'human'`. + +### 5. Decomposing + +Delegate the heavy lifting: `@dr-decomposer <project + accepted DRs + scope>`. The decomposer proposes the task graph. You then: + +- Review the proposed graph with the user. Ask: *"Anything missing? Anything we should split or merge?"* +- Apply changes via `dr_update_task` / `dr_propose_task`. +- Run `dr_validate_graph`. Surface any errors (cycles, orphan deps, oversized estimates, missing decision_refs) and fix them. +- When clean, ask the user: *"Ready to hand off?"* On yes, `dr_advance` with `sign_off_by: 'human'`. + +### 6. Handing off + +- Run `dr_render` to refresh Markdown and HTML artifacts. +- Ask the user where to hand off: **Linear** (if they have `LINEAR_API_KEY` and a team ID) or **filesystem only**. +- For Linear: ask for the team ID, then call `dr_export_linear` with `dry_run: true` first. Show the user the export plan. On confirmation, call again with `dry_run: false` and `sign_off_by: 'human'`. +- For filesystem: call `dr_export_filesystem` with `sign_off_by: 'human'`. +- Confirm the final state with `dr_status`. The project should now be `handed-off`. +- Print the final summary: number of decisions, number of tasks, where things landed. + +## Behavior rules + +- **Track your work.** Use `TodoWrite` for any non-trivial set of decisions/tasks you're working through. +- **Don't batch human prompts.** Ask one question at a time when something's genuinely ambiguous. Don't fire off a checklist. +- **Confirm before destructive ops.** Linear export, gate advances with human sign-off — say what you're about to do and wait for "yes." +- **When stuck, ask.** If a gate fails for a reason you don't understand, surface the reasons verbatim and ask the user how they want to handle it. +- **Stay in scope.** Don't propose decisions that aren't load-bearing for the MVP. Don't decompose tasks that won't ship in the MVP — put them in `nice_to_have` on the project scope and move on. + +## Reference: where things live + +- Pipeline state: `<target-repo>/.dr/state.json` and `.dr/events.jsonl` +- Tracked artifacts: `<target-repo>/dr/project.json`, `dr/decisions/`, `dr/tasks/`, `dr/index.html` +- Seed library: built into the MCP server +- Linear export pushes to: a Project (your manifest) + Issues (one per decision tagged `decision`, one per task) with `blocks` relations matching `depends_on`. + +Begin with the resume check. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0853e98..e581837 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -Thank you for considering a contribution. This project is an early-stage Claude Code plugin + MCP server that turns ideas into ship-ready MVP plans through a hard-gated decision-record pipeline. +Thank you for considering a contribution. This project is an early-stage Claude Code plugin + OpenCode integration + MCP server that turns ideas into ship-ready MVP plans through a hard-gated decision-record pipeline. ## Ways to contribute @@ -9,6 +9,7 @@ Thank you for considering a contribution. This project is an early-stage Claude - **Template variants.** New DR variants (under [`templates/`](templates/)) — scoping, vendor, data-model, lightweight, etc. — are useful when an existing variant doesn't fit a real decision you encountered. - **Renderer / UI improvements.** The static HTML index ([`server/src/render/`](server/)) is intentionally minimal; richer renderings welcome. - **Linear / handoff integrations.** Better mappings between our manifest and Linear's data model, or new handoff targets (Plane, GitHub Projects, Jira). +- **OpenCode integration.** Agent prompt improvements, new commands, or setup script enhancements. - **Documentation.** Real-world examples and case studies under `docs/`. ## Workflow diff --git a/README.md b/README.md index 6d2e28a..6d00d48 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > An idea-to-MVP planning pipeline. Drives complex engineering work — code and architecture — through hard-gated phases that won't release a "ship-ready" plan until every decision is accepted and every task is decomposed. -This repository is a Claude Code plugin + bundled MCP server. It runs inside a fresh or template repo, partners with a human and an AI agent, and produces an executable MVP plan: a scoped manifest, a set of accepted decision records, and a dependency-aware task graph. Output goes to Linear (primary) or stays as filesystem artifacts (fallback). +This repository is a Claude Code plugin + OpenCode integration + bundled MCP server. It runs inside a fresh or template repo, partners with a human and an AI agent, and produces an executable MVP plan: a scoped manifest, a set of accepted decision records, and a dependency-aware task graph. Output goes to Linear (primary) or stays as filesystem artifacts (fallback). This project is a derivative of [Joel Parker Henderson's canonical decision-record repo](https://github.com/joelparkerhenderson/decision-record). The canonical explanation of what a DR is and why it matters is preserved at [`docs/explanation/why-decision-records.md`](docs/explanation/why-decision-records.md). What this fork adds is **enforcement**: workflows, tools, and a state machine that make DRs a non-skippable part of planning with an agentic system. @@ -33,8 +33,11 @@ Docs follow the [Diátaxis](https://diataxis.fr) framework — start at [`docs/R ``` decision-record/ ├── .claude-plugin/ # Claude Code plugin manifest -├── commands/ # /plan slash command (entry point) -├── agents/ # dr-wizard, dr-skeptic, dr-decomposer +├── commands/ # /plan slash command (Claude Code entry point) +├── agents/ # dr-wizard, dr-skeptic, dr-decomposer (Claude Code) +├── .opencode/ # OpenCode agents and commands +├── opencode.json # OpenCode project configuration +├── setup-opencode.sh # Script to install into any existing project ├── server/ # MCP server (TypeScript, @modelcontextprotocol/sdk) ├── schemas/ # JSON Schemas — project, decision, task, state, event ├── templates/ # DR template variants (canonical, scoping, vendor, ...) @@ -67,9 +70,11 @@ npm install npm run build ``` -Then either: -- Use the **standalone CLI**: `export OPENAI_API_KEY=… && node dist/cli.js --idea "your idea here"` -- Use the **Claude Code plugin**: symlink the repo into `~/.claude/plugins/decision-record/` and run `/plan` inside Claude Code. +Then choose your interface: + +- **Standalone CLI**: `export OPENAI_API_KEY=… && node dist/cli.js --idea "your idea here"` +- **Claude Code plugin**: symlink the repo into `~/.claude/plugins/decision-record/` and run `/plan` inside Claude Code. +- **OpenCode**: run `./setup-opencode.sh /path/to/your/project` to install the config, agents, and MCP server into any existing repository. Full install instructions: [`docs/how-to/install.md`](docs/how-to/install.md). First-run walkthrough: [`docs/tutorials/your-first-plan.md`](docs/tutorials/your-first-plan.md). diff --git a/docs/README.md b/docs/README.md index 8f1ae5b..62cc558 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,6 +26,7 @@ The decision-record docs follow the [Diátaxis](https://diataxis.fr) framework ### How-to guides - [Install the plugin or CLI](how-to/install.md) +- [Install with OpenCode](how-to/install.md#opencode) — one-step setup for any project - [Run the CLI](how-to/run-the-cli.md) — idea, PRD, resume - [Configure LLM providers](how-to/configure-providers.md) — OpenAI, OpenRouter, Ollama, vLLM, LiteLLM - [Hand off to Linear](how-to/handoff-to-linear.md) diff --git a/docs/how-to/install.md b/docs/how-to/install.md index 0a5e640..a67f712 100644 --- a/docs/how-to/install.md +++ b/docs/how-to/install.md @@ -1,11 +1,12 @@ # Install -Two ways to use decision-record: +Three ways to use decision-record: -1. **Standalone CLI** — fast to set up, no Claude Code dependency. +1. **Standalone CLI** — fast to set up, no agent dependency. 2. **Claude Code plugin** — adds the `/plan` slash command and registers the MCP server with Claude Code. +3. **OpenCode** — installs the full pipeline (agents, commands, MCP server) into any existing repository. -Both share the same MCP server binary, the same artifacts on disk, and the same gate machine. +All three share the same MCP server binary, the same artifacts on disk, and the same gate machine. ## Standalone CLI @@ -62,6 +63,75 @@ Trigger a session: A marketplace-published version is planned. When available, `/plugin install decision-record` will do everything above. +## OpenCode + +[OpenCode](https://opencode.ai) is an open-source AI coding agent. The `setup-opencode.sh` script installs the entire decision-record pipeline — config, agents, commands, and MCP server — into any existing project in one step. + +### Quick install + +From the decision-record repo: + +```bash +./setup-opencode.sh /path/to/your/project +``` + +Or from within your target project: + +```bash +# Copy the script and run it +/path/to/decision-record/setup-opencode.sh +``` + +### What the script does + +1. Validates prerequisites (Node ≥ 20, npm, opencode) +2. Copies `opencode.json` (MCP server registration, agent definitions, `/plan` command) +3. Copies `.opencode/agents/` — dr-wizard (primary), dr-skeptic (subagent), dr-decomposer (subagent) +4. Copies `.opencode/commands/plan.md` — the `/plan` slash command +5. Copies the MCP server source into `server/` +6. Installs dependencies and builds the MCP server +7. Validates the opencode configuration +8. Runs a smoke test against the MCP server + +### After installation + +```bash +cd /path/to/your/project +opencode +``` + +Then use `/plan` to start the pipeline, or run directly: + +```bash +opencode run --model opencode-go/kimi-k2.5 'Run /plan: Build a todo app' +``` + +### Manual installation + +If you prefer to install manually, copy these files into your project root: + +``` +your-project/ +├── opencode.json # MCP + agents + command config +└── .opencode/ + ├── agents/ + │ ├── dr-wizard.md # Primary orchestrator + │ ├── dr-skeptic.md # Decision review subagent + │ └── dr-decomposer.md # Task decomposition subagent + └── commands/ + └── plan.md # /plan command +``` + +Then build the MCP server: + +```bash +# Copy server/ from decision-record into your project +cp -r /path/to/decision-record/server /path/to/your-project/ +cd /path/to/your-project/server +npm install +npm run build +``` + ## Verify ```bash @@ -77,4 +147,5 @@ node dist/cli.js --version ## Next - [Run the CLI](run-the-cli.md) — first invocation patterns +- [Install with OpenCode](#opencode) — one-step install into any project - [Configure LLM providers](configure-providers.md) — OpenAI, OpenRouter, Ollama, vLLM, LiteLLM diff --git a/docs/tutorials/your-first-plan.md b/docs/tutorials/your-first-plan.md index afe9bd8..7478776 100644 --- a/docs/tutorials/your-first-plan.md +++ b/docs/tutorials/your-first-plan.md @@ -20,7 +20,9 @@ You need: npm run build ``` -You do **not** need the Claude Code plugin installed for this tutorial. We will run the CLI directly. +You do **not** need the Claude Code plugin or OpenCode installed for this tutorial. We will run the CLI directly. + +> **Alternative:** If you have [OpenCode](https://opencode.ai) installed, you can use the setup script instead: `./setup-opencode.sh ~/dev/my-first-plan`, then run `opencode` and use `/plan`. See [Install with OpenCode](../how-to/install.md#opencode). ## Step 1: Pick a working directory @@ -157,6 +159,7 @@ You ran a complete planning pipeline end-to-end. From a one-line idea you produc ## Next steps +- **Use OpenCode instead of the CLI** — [Install with OpenCode](../how-to/install.md#opencode) - **Hand off to Linear instead of filesystem** — [How-to: Hand off to Linear](../how-to/handoff-to-linear.md) - **Run with a PRD instead of a one-liner** — [How-to: Run the CLI](../how-to/run-the-cli.md) - **Use a different model** — [How-to: Configure LLM providers](../how-to/configure-providers.md) diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..48da0f8 --- /dev/null +++ b/opencode.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://opencode.ai/config.json", + "default_agent": "dr-wizard", + "mcp": { + "decision-record": { + "type": "local", + "command": ["node", "${workspaceRoot}/server/dist/index.js"], + "environment": { + "DR_LOG_LEVEL": "info" + } + } + }, + "agent": { + "dr-wizard": { + "description": "Orchestrator for the decision-record planning pipeline. Reads current pipeline state and drives the next phase forward — intake, scope, decisions, tasks, handoff.", + "mode": "primary", + "model": "anthropic/claude-sonnet-4-20250514", + "color": "#8B5CF6", + "permission": { + "read": "allow", + "edit": "allow", + "bash": "allow", + "glob": "allow", + "grep": "allow", + "list": "allow", + "task": "allow", + "todowrite": "allow", + "decision-record_*": "allow" + } + }, + "dr-skeptic": { + "description": "Antagonistic reviewer for decision records. Returns a verdict (pass/block) and concerns from multiple lenses.", + "mode": "subagent", + "model": "anthropic/claude-sonnet-4-20250514", + "color": "#EF4444", + "permission": { + "read": "allow", + "glob": "allow", + "grep": "allow", + "webfetch": "allow", + "edit": "deny", + "bash": "deny", + "decision-record_*": "allow" + } + }, + "dr-decomposer": { + "description": "Task graph decomposer. Converts accepted decisions into a dependency-aware task graph with estimates and acceptance criteria.", + "mode": "subagent", + "model": "anthropic/claude-sonnet-4-20250514", + "color": "#3B82F6", + "permission": { + "read": "allow", + "edit": "allow", + "bash": "allow", + "glob": "allow", + "grep": "allow", + "list": "allow", + "todowrite": "allow", + "decision-record_*": "allow" + } + } + }, + "command": { + "plan": { + "template": "Drive the project through the hard-gated decision-record planning pipeline: intake → scope → decisions → task graph → handoff. $ARGUMENTS", + "description": "Run the idea-to-MVP planning pipeline with hard-gated phases", + "agent": "dr-wizard" + } + } +} diff --git a/setup-opencode.sh b/setup-opencode.sh new file mode 100755 index 0000000..d557054 --- /dev/null +++ b/setup-opencode.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash +# +# setup-opencode.sh — Install the decision-record planning pipeline into an existing project. +# +# Usage: +# ./setup-opencode.sh [target-dir] +# +# If target-dir is omitted, the current working directory is used. +# +# What this script does: +# 1. Validates prerequisites (node, npm, opencode) +# 2. Copies opencode.json and .opencode/ into the target project +# 3. Copies the MCP server source into target/server/ +# 4. Installs dependencies and builds the MCP server +# 5. Validates the resulting opencode configuration +# 6. Runs a smoke test against the MCP server +# 7. Prints next-step instructions + +set -euo pipefail + +# ── Colors ────────────────────────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +info() { echo -e "${CYAN}ℹ $1${NC}"; } +ok() { echo -e "${GREEN}✓ $1${NC}"; } +warn() { echo -e "${YELLOW}⚠ $1${NC}"; } +fail() { echo -e "${RED}✗ $1${NC}" >&2; exit 1; } + +# ── Script directory (where this script lives) ────────────────────────────── +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# ── Target directory ──────────────────────────────────────────────────────── +TARGET_DIR="${1:-$(pwd)}" +TARGET_DIR="$(cd "$TARGET_DIR" 2>/dev/null && pwd)" || fail "Target directory does not exist: $1" + +# ── Banner ────────────────────────────────────────────────────────────────── +echo "" +echo -e "${BOLD}╔══════════════════════════════════════════════════════════╗${NC}" +echo -e "${BOLD}║ decision-record — OpenCode Setup ║${NC}" +echo -e "${BOLD}╚══════════════════════════════════════════════════════════╝${NC}" +echo "" +info "Target project: ${BOLD}$TARGET_DIR${NC}" +echo "" + +# ── Step 0: Check prerequisites ──────────────────────────────────────────── +echo -e "${BOLD}[0/6] Checking prerequisites${NC}" + +command -v node >/dev/null 2>&1 || fail "node is required but not found. Install Node.js >= 20." +NODE_MAJOR=$(node -v | sed 's/v//' | cut -d. -f1) +[ "$NODE_MAJOR" -ge 20 ] || fail "Node.js >= 20 required, found $(node -v)" +ok "node $(node -v)" + +command -v npm >/dev/null 2>&1 || fail "npm is required but not found" +ok "npm $(npm -v)" + +if command -v opencode >/dev/null 2>&1; then + ok "opencode $(opencode --version 2>/dev/null || echo 'installed')" +else + warn "opencode not found in PATH — install with: npm install -g opencode-ai" +fi + +echo "" + +# ── Step 1: Copy opencode.json ───────────────────────────────────────────── +echo -e "${BOLD}[1/6] Installing opencode.json${NC}" + +if [ -f "$TARGET_DIR/opencode.json" ]; then + warn "opencode.json already exists in target — merging will overwrite conflicting keys" + read -rp " Continue? [y/N] " confirm + [[ "$confirm" =~ ^[Yy] ]] || fail "Aborted by user" +fi + +cp "$SCRIPT_DIR/opencode.json" "$TARGET_DIR/opencode.json" +ok "opencode.json copied" + +echo "" + +# ── Step 2: Copy .opencode/ directory ────────────────────────────────────── +echo -e "${BOLD}[2/6] Installing agents and commands${NC}" + +if [ -d "$TARGET_DIR/.opencode" ]; then + warn ".opencode/ already exists in target — new files will be added alongside existing ones" +fi + +mkdir -p "$TARGET_DIR/.opencode" +cp -R "$SCRIPT_DIR/.opencode/agents" "$TARGET_DIR/.opencode/" +cp -R "$SCRIPT_DIR/.opencode/commands" "$TARGET_DIR/.opencode/" +ok "agents/ and commands/ copied to .opencode/" + +echo "" + +# ── Step 3: Copy MCP server source ───────────────────────────────────────── +echo -e "${BOLD}[3/6] Installing MCP server${NC}" + +if [ -d "$TARGET_DIR/server" ]; then + warn "server/ already exists in target — skipping copy (existing server will be used)" + info "If you want the latest version, delete server/ and re-run this script" +else + cp -R "$SCRIPT_DIR/server" "$TARGET_DIR/server" + ok "server/ copied" +fi + +echo "" + +# ── Step 4: Install dependencies and build ───────────────────────────────── +echo -e "${BOLD}[4/6] Building MCP server${NC}" + +cd "$TARGET_DIR/server" +npm install --silent 2>&1 | tail -1 || fail "npm install failed" +ok "dependencies installed" + +npm run build 2>&1 || fail "npm run build failed" +ok "MCP server built → server/dist/index.js" + +cd "$TARGET_DIR" + +echo "" + +# ── Step 5: Validate opencode config ─────────────────────────────────────── +echo -e "${BOLD}[5/6] Validating opencode configuration${NC}" + +if command -v opencode >/dev/null 2>&1; then + VALIDATION_OUTPUT=$(opencode models 2>&1 || true) + if echo "$VALIDATION_OUTPUT" | grep -qi "error\|invalid"; then + fail "opencode config validation failed:\n$VALIDATION_OUTPUT" + fi + ok "opencode configuration is valid" +else + warn "opencode not installed — skipping config validation" + ok "opencode.json syntax validated (JSON)" +fi + +echo "" + +# ── Step 6: Smoke test MCP server ────────────────────────────────────────── +echo -e "${BOLD}[6/6] Running MCP server smoke test${NC}" + +SMOKE_INIT=$(echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"setup-script","version":"1.0.0"}}}' | node "$TARGET_DIR/server/dist/index.js" 2>/dev/null) +if echo "$SMOKE_INIT" | grep -q '"protocolVersion"'; then + ok "MCP server initializes successfully" +else + fail "MCP server failed to initialize" +fi + +SMOKE_TOOLS=$(echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node "$TARGET_DIR/server/dist/index.js" 2>/dev/null | tail -1) +TOOL_COUNT=$(echo "$SMOKE_TOOLS" | python3 -c "import sys,json; print(len(json.load(sys.stdin).get('result',{}).get('tools',[])))" 2>/dev/null || echo "0") +if [ "$TOOL_COUNT" -gt 0 ]; then + ok "MCP server exposes $TOOL_COUNT tools" +else + fail "No tools found from MCP server" +fi + +echo "" + +# ── Done ──────────────────────────────────────────────────────────────────── +echo -e "${BOLD}╔══════════════════════════════════════════════════════════╗${NC}" +echo -e "${BOLD}║ Setup complete! ║${NC}" +echo -e "${BOLD}╚══════════════════════════════════════════════════════════╝${NC}" +echo "" +echo -e "${BOLD}Next steps:${NC}" +echo "" +echo " 1. cd $TARGET_DIR" +echo " 2. Run opencode and use the /plan command:" +echo "" +echo -e " ${CYAN}opencode${NC}" +echo "" +echo " 3. Or run directly with a specific model:" +echo "" +echo -e " ${CYAN}opencode run --model opencode-go/kimi-k2.5 'Run /plan: Build a todo app'${NC}" +echo "" +echo -e "${BOLD}What was installed:${NC}" +echo " • opencode.json — MCP server, agents, and command config" +echo " • .opencode/agents/ — dr-wizard, dr-skeptic, dr-decomposer" +echo " • .opencode/commands/ — /plan command" +echo " • server/ — MCP server (built and ready)" +echo "" +echo -e "Run ${CYAN}opencode${NC} to get started." +echo ""