Native octokit solution tools, gated by conversational confirmation
Status: Accepted · Date: not dated in the memory record (built on the
feature/agent-chat-panel branch; live end-to-end verification recorded) ·
Area: Agents
Context
Aurora gained an in-product chat panel backed by the Claude Agent SDK that
can create Trajectory solutions. The existing create-solution capability
was a bash worker driving gh/git/python
(ADR-013) — fine on a developer machine,
but the webapp container ships no CLI tooling (originally a constraint of the
retired Vercel target, still a good property on ACA). Separately, letting an
LLM invoke a repo-creating action needs a consent mechanism that works in a
stateless, multi-replica web deployment, where a true mid-stream
Approve/Deny cannot be resolved.
Decision
- Execution is native octokit, not the agent shelling out. The bash
worker was ported to a server service
(
src/lib/solutions/create-solution.ts:previewSolution+createSolution), reusing the portfolio layer’s GitHub App octokit clients; the naming rules are a faithful port insrc/lib/solutions/naming.ts. Seedingsolution.yamluses the Contents API (get → line-replace the four identity keys, preserving comments → update), not clone/commit/push. - The agent gets a deliberately locked-down toolset: two in-process MCP
tools (
preview_solution,create_solution) plus read-onlyRead/Grep/Glob. Bash/Write/Edit/WebFetch are disallowed;Skillis not allowed andsettingSourcesis omitted on purpose so the gh-basedcreate-solutionskill can never load. - The confirmation gate is conversational, not an interactive button: the
agent previews, asks, and only calls
create_solutionwithconfirm:trueafter the user types “confirm”.canUseToolis a hard guard that denies the call unlessconfirm===true— defense in depth. This deliberately deviates from the original approval-card plan, which a stateless multi-replica transport cannot support. - The cross-org fork uses a classic PAT (
GH_PROVISION_TOKEN), because GitHub App installation tokens cannot fork a private repo across orgs — proven three ways with a spike script; per-org installation tokens only read/create within their own org even when the App is installed on both. Making the template public was rejected (forks of a public repo are public, so customer solutions would be public). The PAT is used only for the customer fork; App tokens still handle uniqueness checks, the internal fork, and seeding.
Consequences
- The feature needs no CLI tooling in the container and no filesystem git state; the same service backs both the chat tool and the API path, and auto-deploy plus registry integration hook in after it.
- Transport is stateless (the client sends full history each turn over SSE), which is exactly what made the conversational-confirm design necessary and sufficient.
- Fine-grained PATs are single-org, so the provisioning credential must be classic — an accepted, documented weak point (a bot-account PAT in production); the recorded cleaner long-term path is per-org GitHub App installation tokens per clone, deferred.
- Verified live end-to-end against real GitHub: both forks created, upstream
links intact,
solution.yamlseeded.
Evidence
implementation/aurora-webapp/codebase/src/lib/solutions/create-solution.tsandnaming.ts— the native serviceimplementation/aurora-webapp/codebase/src/lib/agent/tools.ts,run.ts,config.tsandsrc/app/api/agent/route.ts— toolset, guard, transportimplementation/aurora-webapp/codebase/scripts/spike-cross-org-fork.mjsandscripts/test-create-solution.mjs— the fork spike and live testmemory/agent-chat.md(decision record incl. the cross-org fork proof)