LearnNewsExamplesServices
Frontmatter
id10860
titleOptional per-agent GitHub credentials: operator-supplied identity→token mapping
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-4-7
createdAtMay 7, 2026, 1:12 AM
updatedAtMay 9, 2026, 11:30 PM
githubUrlhttps://github.com/neomjs/neo/issues/10860
authorneo-opus-4-7
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 7, 2026, 1:25 AM

Optional per-agent GitHub credentials: operator-supplied identity→token mapping

Closedenhancementaiarchitecturemodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 7, 2026, 1:12 AM

Context

The github-workflow MCP server currently authenticates all calls via a single GH_TOKEN env var loaded at startup. For deployments where multiple agents share one GitHub user (typical single-operator deployments), this is correct. For deployments where the operator wants per-agent GitHub-attribution (e.g., multiple agents authoring distinct PRs / commits / comments under separate GitHub users), the current substrate provides no enabling primitive.

This ticket is preventive operational substrate / MX hardening. It introduces an OPTIONAL primitive that lets operators configure per-agent token resolution — without mandating per-agent credentials and without baking specific identities into the substrate.

This ticket supersedes #10858, which baked specific agent identities into env-var naming (an anti-pattern for external operators with their own agent identities).

The Problem

For multi-agent deployments where per-agent GitHub-attribution matters:

  • All agents currently appear as the same GitHub user in PR/commit/issue authorship.
  • Audit logs cannot distinguish which agent identity actually performed an action.
  • Operators have no substrate-level mechanism to map agent identities to distinct PATs.

The Architectural Reality

  • RequestContextService.getAgentIdentityNodeId() exposes the calling agent's identity at MCP boundary.
  • The github-workflow MCP server reads credentials at startup; no per-call token selection.
  • An operator-supplied mapping (file or env-set) keyed by agent identity is the simplest enabling primitive — operators define their own naming conventions, identities, and granularity.

The Fix

  1. Optional config file at operator-defined path:
    • Env var NEO_GH_CREDENTIALS_FILE (default unset → falls through to legacy single-token behavior)
    • File format: JSON object mapping agent identity → PAT
       {
      "@neo-opus-4-7": "ghp_xxx",
      "@neo-gemini-3-1-pro": "ghp_yyy",
      "@external-deployment-agent-1": "ghp_zzz"
    }
    • Gitignored; operator-managed; permission 0600 recommended.
  2. Token resolution helper in github-workflow MCP server:
    • At each authenticated call, get RequestContextService.getAgentIdentityNodeId().
    • If credentials file is configured AND has an entry for this identity → use that token.
    • Else fall through to legacy GH_TOKEN env var (backward-compat for single-operator deployments).
    • Audit log emits { agentIdentity, githubUser, tokenSource: 'mapping' | 'legacy' } per call.
  3. Documentation in learn/agentos/per-agent-credentials.md:
    • When per-agent credentials matter (which deployments benefit)
    • How to set up the credentials file
    • Operator-side PAT scope recommendations
    • Mapping file is OPTIONAL; default behavior unchanged

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
NEO_GH_CREDENTIALS_FILE env var Operator Path to JSON mapping file; unset → legacy behavior Unset / file-missing → legacy GH_TOKEN used; logged once at startup learn/agentos/per-agent-credentials.md (new) Unit test: unset-uses-legacy, set-uses-mapping, missing-identity-falls-back
Mapping file format Operator-supplied JSON object: { agentIdentityNodeId: pat } Malformed JSON → ERROR + refuse to start github-workflow MCP (fail-fast) Same Unit test: malformed-rejected
RequestContextService.getAgentIdentityNodeId() → token resolution github-workflow MCP server helper Maps agent ID via mapping file; falls through to legacy Returns null if no source available; tools refuse with structured error Same Unit test: identity-without-token-refuses-cleanly
Audit log per call github-workflow MCP server Logs { agentIdentity, githubUser, tokenSource } Standard log level Same Verify in integration test

Acceptance Criteria

  • NEO_GH_CREDENTIALS_FILE env var honored by github-workflow MCP at startup
  • Token resolution helper looks up per-agent mapping; falls through to legacy GH_TOKEN
  • Audit log emits { agentIdentity, githubUser, tokenSource } per authenticated call
  • Malformed credentials file → fail-fast with clear error message at startup
  • learn/agentos/per-agent-credentials.md documenting setup + when-to-use
  • Unit tests: (a) no mapping → legacy used, (b) mapping with match → mapping used, (c) mapping without match → legacy used, (d) malformed file → fail-fast, (e) audit log content
  • No regression for existing single-GH_TOKEN deployments

Out of Scope

  • Per-agent PAT generation/rotation tooling (operator-side concern)
  • Encrypted credentials file (separate hardening primitive)
  • Cross-machine credentials replication
  • Mandating per-agent credentials (this is an OPTIONAL enabling primitive; default behavior unchanged)

Avoided Traps / Gold Standards Rejected

  • Per-agent env-var naming convention (e.g., GH_TOKEN_<NORMALIZED_AGENT_ID>) — superseded #10858; bakes specific identities into substrate, breaks for external operators with arbitrary agent identities. The operator-supplied mapping file supports arbitrary identities by design.
  • Per-MCP-session credential negotiation — would require MCP transport changes; operator-supplied file is simpler + sufficient for v1.
  • Single shared service-account PAT with custom commit author signing — doesn't fix attribution at GitHub-API level; only changes commit author email which is a different surface.
  • OAuth flows replacing PAT — out of scope; current substrate uses PAT.

Related

  • Supersedes #10858 (closed as design-flawed)
  • Pairs conceptually with #10859 (per-domain env-file split) — both improve operator credential hygiene without mandating any single deployment shape

Origin Session ID: 8b31fd62-6a53-40b5-aae2-c5288f8ced09 Retrieval Hint: "optional per-agent GitHub credentials operator-supplied mapping file github-workflow MCP token resolution"