Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions docs/todos/2026-06-20-issue-346-agent-picker-opencode/todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Issue 346 Agent Picker OpenCode Selection

Task id: `2026-06-20-issue-346-agent-picker-opencode`

## Scope

Handle GitHub issue #346, "Agent picker: selected `OpenCode` becomes `Claude Code`",
on branch `issue/346-agent-picker-opencode-claude-code` in the isolated worktree
`/Users/A1538552/.codex/worktrees/5b56/agentmemory`.

Target remote: `origin` (`https://github.com/wbugitlab1/agentmemory.git`) only.
Do not target `https://github.com/rohitg00/agentmemory/`.

## Sprint Contract

Goal: make first-run agent selection avoid or clearly prevent the reported
OpenCode-vs-Claude-Code confusion while preserving existing connect adapters and
agent wiring behavior.

Scope:
- Read-only validation of issue #346 and local code paths before edits.
- Onboarding agent picker behavior in `src/cli/onboarding.ts`.
- Focused onboarding tests under `test/`.
- Existing OpenCode connect support checks only if needed to prove the issue is
stale in part.

Non-goals:
- Do not change public MCP, REST, schema, persistence, auth, dependency, or
architecture boundaries.
- Do not change OpenCode config schema or adapter install behavior unless arena
evidence proves the issue cannot be fixed in onboarding alone.
- Do not target or reference the upstream remote in branch, push, or PR actions.

Acceptance criteria:
- Issue legitimacy is decided from current GitHub issue evidence and repo
evidence before implementation.
- `$arena` validity/fix-direction synthesis is recorded before implementation.
- If the issue is valid, a failing test demonstrates the confusing onboarding
behavior or the chosen regression seam before production code changes.
- The minimal fix preserves OpenCode in supported agents and keeps
`agentmemory connect opencode` working.
- Focused tests and required verification/security gates pass, or blockers are
recorded with exact evidence.

Intended verification:
- `corepack pnpm exec vitest run --exclude test/integration.test.ts test/onboarding.test.ts test/cli-onboarding.test.ts test/cli-connect.test.ts`
- `git diff --check`
- Required security gates after implementation and staging per repo policy.

Known boundaries:
- This task starts from `origin/main` at
`5ad88c08197c2cb15675a4a974b9e8f37dfd1f00`.
- `node_modules` is not materialized at task start; repo policy says to run
`corepack pnpm install --frozen-lockfile --ignore-scripts` if pnpm commands
are blocked by missing dependencies or pnpm hardening.
- Issue comments show the original `connect opencode` workaround failed in
v0.9.27, but current repo evidence shows OpenCode support exists in
`src/cli/connect/opencode.ts` and `ADAPTERS`.

Stop conditions:
- Stop for a Human Checkpoint before closing the issue as invalid, stale,
duplicate, unreproducible, or already fixed.
- Stop before broadening behavior into public API/tool/schema/persistence,
dependency, architecture, remote, or project-policy changes.
- Stop before accepting skipped, failing, flaky, or incomplete verification.

## Feature / Verification Matrix

| Change | Verification method | Status | Evidence |
| --- | --- | --- | --- |
| Context confirmed | Git commands and instruction reads | Done | `git status -sb --untracked-files=all`, `git remote -v`, `git worktree list --porcelain`; `AGENTS.md` and triage skill read. |
| Branch created | Git ref check | Done | Created `issue/346-agent-picker-opencode-claude-code` from `origin/main` `5ad88c08197c2cb15675a4a974b9e8f37dfd1f00`. |
| Issue evidence collected | GitHub issue read and local code search | Done | `gh issue view 346 ...`; `rg` found onboarding and OpenCode connect surfaces. |
| Arena validation | Candidate reports and synthesis | Done | Candidates converged: #346 is partially actionable; stale `connect opencode` support is already fixed, picker default-selection UX remains valid. Judge selected Candidate 1 as base. |
| Regression test | Targeted Vitest red/green | Done | Red failed as expected: `getInitialAgentValues({})` returned `["claude-code"]` and multiselect received `initialValues: ["claude-code"]`; green focused run passed after implementation. |
| Minimal implementation | Source diff review | Done | Changed `getInitialAgentValues()` generic fallback from `["claude-code"]` to `[]`; Copilot detection remains unchanged. |
| Focused verification | Targeted Vitest, full test, diff checks | Done | Pre-merge: focused run passed 3 files / 50 tests and `corepack pnpm test` passed 220 files / 3006 tests. Post-merge from `origin/main` `257238ab1c318b2e9ae5efcbe72863b99c41ee35`: focused run passed 3 files / 50 tests and `corepack pnpm test` passed 222 files / 3042 tests. `git diff --check` and `git diff --cached --check` passed. |
| Security gates | Required scanners after staging | Done | Pre-merge and post-merge `semgrep scan --config p/default --error --metrics=off .` passed with 0 findings; post-merge scan covered 997 tracked files. `gitleaks protect --staged --redact` passed with no leaks before the first commit and after the final task-note update. |

## Subagent Ledger

| Workstream | Scope | Edits allowed | Expected output | Result | Residual risk |
| --- | --- | --- | --- | --- | --- |
| Arena candidate 1 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: selected base; recommended no generic `claude-code` preselection, preserving Copilot detection | Did not run tests. |
| Arena candidate 2 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: same validity/root cause; added stale-connect guard and optional note-copy concern | Note-copy change rejected as extra surface for this fix. |
| Arena candidate 3 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: same validity/root cause; highlighted that making selection required is broader | Prompt-copy tweak rejected as optional. |
| Arena judge | Candidate scoring | No | Rubric scores and base recommendation | Done: Candidate 1 scored 9/10 and selected as base | No checkpoint needed for onboarding-only fix. |

## Arena Synthesis

Base: Candidate 1.

Decision: issue #346 is valid/actionable for first-run onboarding picker UX.
The `connect opencode` unknown-agent follow-up is stale in current code because
`opencode` is registered in `ADAPTERS`, appears in `knownAgents()`, and has
focused adapter tests. The remaining failure path is `getInitialAgentValues({})`
returning `["claude-code"]`, which is passed as Clack multiselect
`initialValues`; focus can move to OpenCode while the checked value remains
Claude Code.

Grafts:
- From Candidate 2: keep `test/cli-connect.test.ts` as the stale-connect guard;
do not retest adapter internals beyond existing focused coverage unless the
fix touches them.
- From Candidate 3: do not make the multiselect required or add an explicit
skip option; that would be broader than the issue needs because onboarding
intentionally allows users to skip wiring agents.

Rejected:
- Candidate 2's agent-neutral post-selection note change is plausible polish but
not required for the evidence-backed minimal fix.
- Candidate 3's prompt wording tweak is optional copy work and not needed for
the regression seam.
- Adapter/schema/MCP/REST/persistence/dependency changes are out of scope.

## Evidence Notes

- Issue #346 is open. The imported report says selecting `OpenCode` in the
first-run agent picker leads to a later `Claude Code` message, and the user
expected `OpenCode`.
- Imported maintainer comment explains the picker is a multi-select: arrow keys
move focus, Space toggles, Enter confirms checked rows. Claude Code was
pre-checked while OpenCode was focused.
- Imported follow-up says `agentmemory connect opencode` was unknown in v0.9.27.
Current repo evidence shows `opencode` is now present in `ADAPTERS`, listed in
`knownAgents()`, and tested in `test/cli-connect.test.ts`.
- Local code currently defaults `getInitialAgentValues({})` to
`["claude-code"]`, so a user can focus `OpenCode` while still confirming
preselected `Claude Code`.

## Progress Notes

- 2026-06-20: Read active repo instructions, triage workflow, arena workflow,
systematic debugging, and TDD guidance.
- 2026-06-20: Confirmed worktree, branch, remotes, and start ref. Created
branch `issue/346-agent-picker-opencode-claude-code`.
- 2026-06-20: Read issue #346 and local onboarding/connect code. Current
hypothesis: the actionable bug is onboarding default-selection UX, while the
OpenCode connect alias part is stale/fixed by existing `opencode` adapter
support.
- 2026-06-20: Completed `$arena`. Candidates and judge converged on an
onboarding-only fix: remove generic `claude-code` preselection while
preserving confident Copilot CLI detection. No Human Checkpoint is needed for
this implementation path; checkpoint remains required before stale/invalid
closure or boundary changes.
- 2026-06-20: Added red tests in `test/onboarding.test.ts` and
`test/cli-onboarding.test.ts`. Initial `corepack pnpm exec vitest ...` was
blocked by pnpm ignored-build hardening, so ran
`corepack pnpm install --frozen-lockfile --ignore-scripts` per repo
instructions, then reran the focused tests. Red failure matched the expected
onboarding default-selection behavior.
- 2026-06-20: Implemented the one-line onboarding fix. Focused green
verification passed for onboarding/connect tests. Full `corepack pnpm test`
passed 220 files / 3006 tests. Removed the generated pnpm `allowBuilds`
placeholder that pnpm had added during dependency setup; no package metadata
or lockfile changes remain.
- 2026-06-20: Repo-wide Semgrep default scan passed with 0 findings across
tracked files.
- 2026-06-20: Staged Gitleaks scan passed with no leaks.
- 2026-06-20: Committed `fix(onboarding): avoid default Claude Code
preselection` at `4f2e2b09480e619ced578390b8290075ae9da8f8`.
- 2026-06-20: Fetched `origin` and merged `origin/main`
`257238ab1c318b2e9ae5efcbe72863b99c41ee35` into the branch. The merge
required sandbox escalation because the worktree Git metadata directory
rejected sandbox writes to `ORIG_HEAD.lock`. PR diff remains limited to this
task's onboarding source, tests, and task record.
- 2026-06-20: Post-merge focused tests passed 3 files / 50 tests; full
`corepack pnpm test` passed 222 files / 3042 tests; post-merge Semgrep
default scan passed with 0 findings across 997 tracked files.
- 2026-06-20: Final staged Gitleaks scan after the task-note update passed with
no leaks.
2 changes: 1 addition & 1 deletion src/cli/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function getInitialAgentValues(
if (env["COPILOT_CLI"] === "1" || env["COPILOT_AGENT_SESSION_ID"]) {
return ["copilot-cli"];
}
return ["claude-code"];
return [];
}

// Mirror src/cli.ts findEnvExample so onboarding ships the same .env
Expand Down
33 changes: 33 additions & 0 deletions test/cli-onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,37 @@ describe("cli onboarding", () => {
"Also set AZURE_OPENAI_ENDPOINT= and AZURE_OPENAI_DEPLOYMENT=",
);
});

it("does not preselect Claude Code before an OpenCode-only onboarding choice", async () => {
setTTY(true);
prompts.multiselect.mockResolvedValueOnce(["opencode"]);
prompts.select.mockResolvedValueOnce("skip");
prompts.confirm
.mockResolvedValueOnce(false)
.mockResolvedValueOnce(false);
const { runOnboarding } = await freshOnboarding();

const result = await runOnboarding();

expect(prompts.multiselect).toHaveBeenCalledWith(
expect.objectContaining({
initialValues: [],
}),
);
expect(result).toEqual({ agents: ["opencode"], provider: null });

const preferencesPath = join(sandboxHome, ".agentmemory", "preferences.json");
const preferences = JSON.parse(readFileSync(preferencesPath, "utf-8"));
expect(preferences).toMatchObject({
lastAgent: "opencode",
lastAgents: ["opencode"],
lastProvider: null,
skipSplash: true,
});

const noteText = prompts.note.mock.calls
.map(([body]) => String(body))
.join("\n");
expect(noteText).toContain("agentmemory connect opencode");
});
});
4 changes: 2 additions & 2 deletions test/onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe("first-run onboarding", () => {
expect(getInitialAgentValues({ COPILOT_AGENT_SESSION_ID: "session" })).toEqual(["copilot-cli"]);
});

it("keeps Claude Code as the default outside known agent environments", () => {
expect(getInitialAgentValues({})).toEqual(["claude-code"]);
it("does not preselect an agent outside known agent environments", () => {
expect(getInitialAgentValues({})).toEqual([]);
});
});
Loading