diff --git a/AGENTS.md b/AGENTS.md index 7500da4..0dbc253 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,6 +68,10 @@ macOS note: the vendored binary is unsigned — if Gatekeeper blocks it: - Run artifacts land in `~/.amico/runs/default//` (contract: `run.toml`, `AMICODE_ITER` lines, `iter_*.png`, `result.toml`, `pulse.jld2`, `FINISHED`). Validate files with `packages/schema/launcher/amico-validate `. +- **New sessions open on opencode's read-only `plan` agent** (plan-first posture for all + users): `buildOpencodeConfigContent` injects `default_agent: "plan"`. The composer + agent-picker (or an explicit per-message `agent`, as in the e2e tests) switches to + pulse-designer/build to execute. - Never commit to `main`; branch + PR. ## Changing opencode (the vendored fork) diff --git a/packages/extension/src/opencode_config.ts b/packages/extension/src/opencode_config.ts index 5eace34..6175130 100644 --- a/packages/extension/src/opencode_config.ts +++ b/packages/extension/src/opencode_config.ts @@ -115,6 +115,8 @@ export function resolveJuliaProject(configValue: string): string { * - `agent: {"pulse-designer": …}` — the interview agent; its prompt defers * to the "Pulse-designer interview" section of the injected AGENTS.md so * the interview script lives in ONE place. + * - `default_agent: "plan"` — plan-first posture: new sessions open on + * opencode's built-in read-only plan agent, not straight into execution. * - an `external_directory` grant for the Problem-workspaces root, so the * AGENT's file tools can read back system/formulation/run/event TOML the * plugin wrote (the plugin's own fs writes are host-process calls and need @@ -411,6 +413,13 @@ export function buildOpencodeConfigContent( const skills = skillsStageDir ? { paths: [skillsStageDir] } : undefined; return JSON.stringify({ $schema: "https://opencode.ai/config.json", + // Plan-first posture (product default for ALL users): every new Amicode + // session opens on opencode's built-in, read-only `plan` agent; execution + // (the pulse-designer interview, solves) starts only when the user switches + // agents in the composer. Like everything in this blob, it deep-merges OVER + // the user's global config — an explicit per-message `agent` (the e2e tests, + // the distiller's --agent) is unaffected. + default_agent: "plan", ...(modelPin ? { model: modelPin } : {}), instructions: [agentsPath], plugin: [pluginPath], diff --git a/packages/extension/test/opencode_config.test.ts b/packages/extension/test/opencode_config.test.ts index 0e1c1fe..39d9366 100644 --- a/packages/extension/test/opencode_config.test.ts +++ b/packages/extension/test/opencode_config.test.ts @@ -98,6 +98,10 @@ describe("buildOpencodeConfigContent", () => { expect(pd.prompt).toContain("amicode_"); // record stages via the tool pack expect(pd.prompt).toContain("solve workflow"); // launches stay on the bash workflow }); + it("pins default_agent to plan (plan-first posture for new sessions)", () => { + const cfg = JSON.parse(buildOpencodeConfigContent("/abs/AGENTS.md", TPL, "/home/u/.amico/runs/default")); + expect(cfg.default_agent).toBe("plan"); // read-only open; the user switches to pulse-designer/build to execute + }); it("grants external_directory on the problems root (default + $AMICODE_PROBLEMS_DIR override)", () => { const defGrant = join(homedir(), ".amico", "problems") + "/**"; const cfg = JSON.parse(buildOpencodeConfigContent("/abs/AGENTS.md", TPL, "/home/u/.amico/runs/default"));