You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Amicode's GitHub actions (issue/PR creation via gh, the handoff verb, repo-sync) all run under the researcher's personal gh login, so automation is indistinguishable from the human in the audit log, PRs attribute to a person, and there is no scoped revocable credential for agent activity.
Approach
Give Amicode its own GitHub identity via an org-level GitHub App ("Amico", installed on all harmoniqs repos): a pure token-minting core in amico-run plus PATH-shim launchers (amico-gh, amico-git-credential) in the extension's launcher bin dir, so every gh/git push in an agent session authenticates as amico[bot] with zero prompt changes. Commit authorship stays the researcher's — only PR/issue creation and pushes carry the bot identity (the Claude Code split).
Machine user account + PAT — zero code to start, but expiring tokens, seat cost, reads as human in audit log.
github-actions bot token — free but repo-scoped, ephemeral, only exists inside Actions runs.
Scope
In: credential-file contract (~/.amico/github.json + token cache), JWT mint + installation-token fetch + cache-with-skew (pure core), amico-gh PATH shim with transparent fallback to real gh, git credential helper injected via spawn-env git config when configured, hermetic unit tests, draft PR. Out: Connection-panel UI (Phase 2, separate issue) — this lands headless; PEM upload UX follows the existing credential-file patterns. Out: fleet propagation (Phase 3). Out: webhook/event handling — the App is credential-only, no callbacks.
Assumptions / Open Qs
Org owner creates the App and grants contents-RW, pull-requests-RW, issues-RW, members-R, administration-RW; installation covers all repos including the private opencode fork. Node crypto RS256 signing is acceptable (no new deps).
Acceptance Criteria
~/.amico/github.json absent → amico-gh execs the real gh with no env changes (byte-identical passthrough; today's behavior).
Config present → shim mints an installation token (RS256 JWT → access-token endpoint), exports GH_TOKEN, execs real gh; token cached in ~/.amico/github-token.json (0600) and reused until 5 minutes of life remain.
Malformed config / unreadable PEM / mint failure → distinct, token-free, actionable errors on stderr with nonzero exit; never prints the PEM, JWT, or token.
JWT payload: iss = app id, iat/exp inside GitHub's 10-minute window with 60s negative clock skew; header alg RS256, typ JWT.
Git credential helper answers get for github.com over https with x-access-token + the minted token; silent exit (git falls through) when unconfigured or for other hosts.
Spawn env gains the credential-helper git config ONLY when the connection file exists; absent file → no GIT_CONFIG vars added (regression-safe).
All logic unit-tested hermetically (no network): fetch and child-process seams injectable, matching the pasqal_launch/handoff test style.
Test suite + lint pass with no regressions.
Key Decisions
Bot PRs, human-authored commits: no commit-identity changes anywhere; only transport auth changes.
PATH-shim interception (not rewriting call sites): every current and future gh call — agent sessions, handoff verb, repo-sync — becomes the bot with no code changes at call sites.
The shim must resolve the real gh by scanning PATH minus its own directory (a bare exec would recurse into itself).
Env overrides follow house style: AMICO_GITHUB_FILE, AMICO_GITHUB_TOKEN_FILE (mirroring AMICO_PASQAL_FILE).
ssh remotes are untouched: the credential helper only serves https github.com; pushes over ssh keep working as the user (authorship is commit metadata either way).
Pure core in amico-run (no I/O in the logic module; file/exec/fetch seams injected), launchers as thin executables.
Constraints & Invariants
Never log or embed secrets (PEM, JWT, token) in errors, stdout metadata, or test fixtures — errors are token-free by construction.
Credential file must never be committed; tests point env overrides at temp dirs.
No new npm dependencies: JWT signing via node:crypto.
Prior Art / Patterns
packages/amico-run/src/pasqal_launch.ts — credential-file shape-check style: distinct ConfigError classes, token-free actionable messages, env override for the file path.
packages/extension/src/server_auth.tsbuildServerSpawnEnv — the spawn-env seam that already prepends the launcher bin dir to PATH; GIT_CONFIG injection goes here, gated on config-file existence (sync stat, telemetry-resolver precedent).
packages/amico-run/test/pasqal_launch.test.ts — recording-spawn stub pattern for exec seams.
Source
Resolved in session (plan of record): GitHub App route, all-harmoniqs-repos install, bot-PRs/human-commits — user-confirmed 2026-08-17.
Claude Code's /install-github-app as the external pattern being adapted.
Notes
Phase 0 (manual, org owner): create the org App, set permissions, install on all repos, record App ID + Installation ID, place PEM. Phase 2 (Connection panel) and Phase 3 (fleet) follow as separate issues. Revoking the PEM is the kill switch.
Important
Problem
Amicode's GitHub actions (issue/PR creation via
gh, the handoff verb, repo-sync) all run under the researcher's personalghlogin, so automation is indistinguishable from the human in the audit log, PRs attribute to a person, and there is no scoped revocable credential for agent activity.Approach
Give Amicode its own GitHub identity via an org-level GitHub App ("Amico", installed on all harmoniqs repos): a pure token-minting core in amico-run plus PATH-shim launchers (
amico-gh,amico-git-credential) in the extension's launcher bin dir, so everygh/git pushin an agent session authenticates asamico[bot]with zero prompt changes. Commit authorship stays the researcher's — only PR/issue creation and pushes carry the bot identity (the Claude Code split).Approaches Considered
Scope
In: credential-file contract (
~/.amico/github.json+ token cache), JWT mint + installation-token fetch + cache-with-skew (pure core),amico-ghPATH shim with transparent fallback to realgh, git credential helper injected via spawn-env git config when configured, hermetic unit tests, draft PR.Out: Connection-panel UI (Phase 2, separate issue) — this lands headless; PEM upload UX follows the existing credential-file patterns. Out: fleet propagation (Phase 3). Out: webhook/event handling — the App is credential-only, no callbacks.
Assumptions / Open Qs
Org owner creates the App and grants contents-RW, pull-requests-RW, issues-RW, members-R, administration-RW; installation covers all repos including the private opencode fork. Node
cryptoRS256 signing is acceptable (no new deps).Acceptance Criteria
~/.amico/github.jsonabsent →amico-ghexecs the realghwith no env changes (byte-identical passthrough; today's behavior).GH_TOKEN, execs realgh; token cached in~/.amico/github-token.json(0600) and reused until 5 minutes of life remain.iss= app id,iat/expinside GitHub's 10-minute window with 60s negative clock skew; headeralgRS256,typJWT.getforgithub.comover https withx-access-token+ the minted token; silent exit (git falls through) when unconfigured or for other hosts.Key Decisions
ghcall — agent sessions, handoff verb, repo-sync — becomes the bot with no code changes at call sites.ghby scanning PATH minus its own directory (a bare exec would recurse into itself).AMICO_GITHUB_FILE,AMICO_GITHUB_TOKEN_FILE(mirroringAMICO_PASQAL_FILE).Constraints & Invariants
node:crypto.Prior Art / Patterns
packages/amico-run/src/pasqal_launch.ts— credential-file shape-check style: distinct ConfigError classes, token-free actionable messages, env override for the file path.packages/amico-run/src/handoff.ts— pure-core + injectedgh apiexec seam, hermetic tests (handoff_verb.test.ts).packages/extension/src/server_auth.tsbuildServerSpawnEnv— the spawn-env seam that already prepends the launcher bin dir to PATH; GIT_CONFIG injection goes here, gated on config-file existence (sync stat, telemetry-resolver precedent).packages/amico-run/src/pasqal_devices.ts—~/.amico/*.json+ env-override config resolution.packages/amico-run/test/pasqal_launch.test.ts— recording-spawn stub pattern for exec seams.Source
/install-github-appas the external pattern being adapted.Notes
Phase 0 (manual, org owner): create the org App, set permissions, install on all repos, record App ID + Installation ID, place PEM. Phase 2 (Connection panel) and Phase 3 (fleet) follow as separate issues. Revoking the PEM is the kill switch.