LearnNewsExamplesServices
Frontmatter
id10858
titlePer-agent credential namespacing: replace shared GH_TOKEN with identity-scoped variables
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-4-7
createdAtMay 7, 2026, 1:08 AM
updatedAtMay 9, 2026, 11:30 PM
githubUrlhttps://github.com/neomjs/neo/issues/10858
authorneo-opus-4-7
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 7, 2026, 1:11 AM

Per-agent credential namespacing: replace shared GH_TOKEN with identity-scoped variables

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

Context

Multi-agent swarm operation requires GitHub-authenticated tooling (issue creation, PR operations, repo metadata reads). Currently a single GH_TOKEN env var is loaded from .env and used by any agent's tooling. The token is bound to one GitHub user identity; any agent that loads it appears as that GitHub user in commit/PR/issue authorship metadata.

This ticket is preventive operational substrate / MX hardening — it makes per-agent identity attribution structurally enforceable for GitHub-authenticated actions.

The Problem

A single shared GH_TOKEN produces three downstream concerns:

  1. False author attribution — any agent's GH-authenticated action shows the same GitHub user, even if a different agent identity authored the underlying work.
  2. Cross-agent credential scope — any agent that can read .env has full GitHub-write capability tied to that user.
  3. Audit difficulty — post-hoc forensics can't distinguish which agent identity actually performed an action; only the shared GitHub user identity is recorded.

The Architectural Reality

  • .env is loaded at process start by tooling that reads it directly (or via a config helper).
  • The github-workflow MCP server reads credentials at startup; no per-call credential selection.
  • The agent's identity (e.g., @neo-opus-4-7) is bound at MCP-session level and surfaced via RequestContextService.getAgentIdentityNodeId().
  • Each named agent identity could have its own GitHub user account + PAT, with the env var following a naming convention like GH_TOKEN_<NORMALIZED_AGENT_ID>.

The Fix

  1. Naming convention: GH_TOKEN_NEO_OPUS_4_7, GH_TOKEN_NEO_GEMINI_3_1_PRO, GH_TOKEN_NEO_GPT (uppercase, underscore-separated, derived from agent identity by stripping @neo- prefix and replacing dashes with underscores).
  2. Token lookup helper in github-workflow MCP server: at every authenticated call, derive the env var name from RequestContextService.getAgentIdentityNodeId(); use that token; fall back to legacy GH_TOKEN if per-agent variant is absent (with WARN log). Hard-cut the legacy fallback in a follow-up after migration window.
  3. Per-agent PAT setup runbook in learn/agentos/: documents how operator generates a PAT per agent identity + sets the corresponding env var.
  4. Audit log: every github-workflow MCP call logs { agentIdentity, githubUser } pair so post-hoc forensics can verify expected attribution.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
GH_TOKEN_<NORMALIZED_AGENT_ID> env var Per-agent .env or process env Used by github-workflow MCP for that agent's authenticated calls Falls through to legacy GH_TOKEN with WARN (deprecation window) Per-agent PAT setup runbook (new doc) Unit test: bound-identity-uses-correct-token
RequestContextService.getAgentIdentityNodeId() → token resolution github-workflow MCP server helper Maps agent ID to env-var name + reads token Returns null if neither per-agent nor legacy token available; tools refuse with structured error Same Unit test: identity-without-token-refuses-cleanly

Acceptance Criteria

  • Token lookup helper added to github-workflow MCP server; reads per-agent env var first, falls back to legacy GH_TOKEN with WARN
  • All github-workflow MCP tool entry points use the helper (not direct process.env.GH_TOKEN reads)
  • Audit log emits { agentIdentity, githubUser } per authenticated call
  • learn/agentos/per-agent-credentials.md documenting setup + naming convention
  • Unit tests covering: (a) bound-identity-uses-correct-token, (b) bound-identity-with-only-legacy-token-warns, (c) bound-identity-with-no-token-refuses-cleanly
  • Migration: ensure each named swarm agent (@neo-opus-4-7, @neo-gemini-3-1-pro, @neo-gpt) has its own PAT + env var set in operator's environment (operator-side action; doc only)

Out of Scope

  • Multi-tenancy / external-user PAT management — internal swarm only
  • Token rotation primitive — orthogonal; can land as follow-up
  • OAuth instead of PAT — out of scope; current substrate uses PAT

Avoided Traps / Gold Standards Rejected

  • Single shared service-account PAT with custom commit author signing — doesn't fix attribution at the GH-API level (GH author = the PAT's user); only changes commit author email which is a different surface.
  • Hard-cut without deprecation window — risks immediate breakage if any tool still reads GH_TOKEN directly. Soft-cut with WARN allows migration; follow-up ticket hard-cuts later.

Related

  • #10845 (block destructive AI substrate ops on production paths) — pairs as preventive isolation primitive
  • Substrate-mining note: a .env GH_TOKEN accidentally synchronized across two clones in this session caused PR author attribution to mismatch the underlying-work author; per-agent variable naming would have made the cross-clone copy structurally impossible (different variable names → no overlap on accidental copy).

Origin Session ID: 8b31fd62-6a53-40b5-aae2-c5288f8ced09 Retrieval Hint: "per-agent GH_TOKEN credential namespacing identity-scoped GitHub PAT attribution"