Skip to Content
Design DecisionsNative Octokit Agent Tools

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 in src/lib/solutions/naming.ts. Seeding solution.yaml uses 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-only Read/Grep/Glob. Bash/Write/Edit/WebFetch are disallowed; Skill is not allowed and settingSources is omitted on purpose so the gh-based create-solution skill can never load.
  • The confirmation gate is conversational, not an interactive button: the agent previews, asks, and only calls create_solution with confirm:true after the user types “confirm”. canUseTool is a hard guard that denies the call unless confirm===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.yaml seeded.

Evidence

  • implementation/aurora-webapp/codebase/src/lib/solutions/create-solution.ts and naming.ts — the native service
  • implementation/aurora-webapp/codebase/src/lib/agent/tools.ts, run.ts, config.ts and src/app/api/agent/route.ts — toolset, guard, transport
  • implementation/aurora-webapp/codebase/scripts/spike-cross-org-fork.mjs and scripts/test-create-solution.mjs — the fork spike and live test
  • memory/agent-chat.md (decision record incl. the cross-org fork proof)