# Repository Access Tokens

> Canonical path: `specs/automation/repository-access-tokens.md`
> Status: living product and architecture spec
> Scope: MeshX-issued repository access tokens, AgentTeam gateway data-plane authentication, AGS repository enforcement, agent token lifecycle, and development-only repository access.

## Summary

Repository Access Tokens are scoped credentials for AGS repository access. They
are not AgentTeam login credentials, PingCAP/OIDC tokens, KB grants, automation secrets,
or generic AGS OAuth tokens.

MeshX is the issuer, verifier, metadata source of truth, and owner of repository
token scope and capability policy. AGS remains the repository execution plane:
MeshX verifies the credential against the exact repository operation before AGS
receives a trusted embedded identity. AgentTeam gateway owns public routing and must
not turn AgentTeam account passwords into Git credentials.

## Ownership

AGS owns:

- Git Smart HTTP and GitHub-compatible repository APIs;
- repository identity and permission primitives;
- accepting only a request-scoped trusted embedded identity after MeshX has
  verified a Repository Access Token for that repository operation.

MeshX owns:

- token plaintext generation and one-time reveal;
- irreversible token verifier storage;
- token metadata, status, last-used tracking, and audit events;
- repository scope and capability enforcement before entering AGS;
- human token revoke and agent token reconcile/revoke contracts;
- workspace/product authorization for token management APIs;
- the public management API under `/api/v1/workspaces/:workspaceId/repository-access-tokens`;
- agent repository access desired state derived from agent lifecycle and runtime
  permission mode;
- token metadata and event projection for UI;
- stable product errors when token persistence or repository enforcement is
  unavailable.

`internal/store/repotokens` owns the persistence models and store
operations for repository-scoped AGS and sync credential metadata, irreversible
verifiers, audit facts, and agent-recreation suppression records. It is not the
owner of personal access tokens, session authentication, generic authorization,
resource-repository bindings, or API DTOs. Repository token policy, plaintext
generation and one-time reveal, scope enforcement, and lifecycle orchestration
remain in the MeshX service and API owners.

AgentTeam gateway owns:

- authenticating management-plane requests with AgentTeam/PingCAP/OIDC session
  credentials;
- forwarding management requests to MeshX with trusted identity;
- routing AGS Git/API data-plane requests without accepting AgentTeam passwords as
  repository credentials;
- stripping client-supplied internal identity headers before forwarding.

KB owns KB grants and retrieval policy. AGS repository readability is necessary
for repository content access, but it is not sufficient to read through KB
product APIs.

## Token Types

### Human Tokens

Human tokens are created by an authenticated principal through the MeshX public
management API. They are owned by the current principal inside a workspace and
are listed only for that principal unless a later admin-audit spec defines a
separate read surface.

The create response returns plaintext exactly once. Later list, get, event, and
revoke responses must never include plaintext or reversible verifier material.

### Agent Tokens

Agent tokens are system-managed. Users cannot manually create them, they do not
appear in the human token list, and plaintext is never returned to the browser.

MeshX derives agent token desired state from:

- workspace id;
- agent id;
- provider host;
- explicit repository scope;
- agent runtime permission mode.

`agent_workspace_write` maps to `repo:read` and `repo:clone`. `full_access`
maps to `repo:read`, `repo:clone`, and `repo:write`. Empty, unknown, disabled,
or removed repository access must converge to revoked or absent MeshX token
state.

### Sync Lease Tokens

Sync lease tokens are short-lived MeshX Repository Access Tokens issued for
Desktop-managed Memory and Skill repository sync. MeshX creates them when
`/api/v1/workspaces/:workspaceId/memory/agents/access:batch` or
`/api/v1/workspaces/:workspaceId/skills/agents/access:batch` returns bound repositories.

Rules:

- type is `sync_lease`;
- plaintext is returned only in the access-batch response that requested it;
- scope is the exact repository set returned by that batch response;
- capabilities are `repo:read` and `repo:clone` for Skill, and `repo:read`,
  `repo:clone`, and `repo:write` for Memory sync/push;
- default TTL is 30 minutes and maximum TTL is 2 hours unless AGS changes the
  repository-token contract;
- Desktop refreshes by calling the management-plane access-batch endpoint again,
  not by extending a lease locally;
- sync lease plaintext must never be stored in MeshX projection state, Desktop
  profile YAML, browser storage, or logs.

## Credential Planes

### Management Plane

Browser and API clients use AgentTeam/PingCAP/OIDC session credentials to create,
list, inspect, and revoke Repository Access Tokens:

```http
GET /api/v1/workspaces/<workspace-id>/repository-access-tokens
Authorization: Bearer <AgentTeam access token>
X-Workspace-Id: <workspace id>
X-AgentTeam-Route-Workspace-Id: <workspace id>
```

The canonical path segment is the routing authority. Both workspace headers
must match that path when present; neither header can select a different
workspace or authorize an unscoped native MeshX URL.

The OIDC or AgentTeam token is a management credential only. It is never a Git
credential and must not be accepted by AGS as a repository access token.

MeshX public endpoints require:

- authenticated AgentTeam principal;
- verified identity where deployment policy requires it;
- current workspace context;
- MeshX enabled;
- workspace management authority for token management.

### Data Plane

Production Git and GitHub-compatible AGS data-plane access uses an AGS
Repository Access Token as the credential.

For user-managed Git HTTPS flows, Git client compatibility allows HTTP Basic:
username is any non-empty value and password is the token plaintext:

```text
https://<agentteam-gateway>/<owner>/<repo>.git
username: <any non-empty value>
password: ags_rat_...
```

For Desktop-managed Memory and Skill sync, the same Repository Access Token is
sent as a Bearer credential by the go-git auth method:

```http
Authorization: Bearer ags_rat_...
```

The Desktop access-batch call that obtains the lease still uses the AgentTeam user
token on the management plane. The subsequent Git clone/fetch/push request must
use the AGS sync lease, not the AgentTeam user token.

AgentTeam account passwords must not be accepted for AGS Git access. The gateway must
not keep a product path where failed or successful AgentTeam password authentication
is translated into trusted AGS identity for Git Smart HTTP. This rule applies to
production behavior even if local development keeps a separate debug shortcut.

Embedded MeshX/AGS deployments also have a protected internal credential plane:
server-owned materialization workers may use trusted embedded identity to create
or update AgentTeam-managed AGS repositories through Git Smart HTTP. This internal
identity is not a Repository Access Token, is not exposed to browsers or Git
clients, and must not be documented as a user credential. AGS Git HTTP routing
must keep this trusted embedded identity path alongside Repository Access Token
auth: embedded identity is for first-party in-process work, Repository Access
Tokens are for external clients and external applications. Tightening external
Git authentication must not remove the embedded path unless managed repository
materialization no longer uses Git Smart HTTP.

Client-supplied `X-AgentTeam-Verified-JWT` or equivalent internal identity headers
must be removed before forwarding. Trusted identity headers are issued only by
AgentTeam gateway for management/product surfaces that are explicitly allowed to use
them.

## Development-Only Access

Local development may provide an explicit AGS admin/debug token, such as
`MESHX_AGS_ADMIN_TOKEN`, for fast clone, push, and API smoke testing. This token
is not a Repository Access Token:

- it is enabled only outside production and only by explicit development
  configuration;
- it is not listed in Repository Access Token APIs;
- it is not tied to human or agent lifecycle;
- it is not returned to UI;
- it must not be documented as a user credential.

`ALLOW_ANY_TOKEN`-style behavior is an AGS-local development escape hatch only.
Production startup must reject it, and AgentTeam gateway must not expose it as a
product capability.

## Repository Scope

The first supported scope mode is explicit repositories:

```json
{
  "mode": "repositories",
  "repositories": ["owner/repo"],
  "policyRef": ""
}
```

Rules:

- `repositories` is required, non-empty, de-duplicated, and normalized to AGS
  `owner/repo` names.
- In the current single-provider AGS deployment, Git/REST data-plane requests
  target that AGS provider namespace implicitly and must match the token's
  normalized repository full name at access time.
- Before an AGS deployment supports multiple provider hosts on the same
  data-plane surface, routing must carry the requested provider host and AGS
  must fail closed when it does not match token `providerHost`.
- `all`, workspace-wide wildcard, owner-wide wildcard, and org-wide wildcard
  scopes are unsupported.
- `policyRef` is reserved. Until AGS has a resolver for the referenced policy,
  non-empty `policyRef` values fail closed.

## Capabilities

The supported capability vocabulary is:

| Capability | Meaning |
| --- | --- |
| `repo:clone` | Allows Git Smart HTTP clone/fetch: `info/refs?service=git-upload-pack` and `git-upload-pack`. |
| `repo:read` | Allows AGS REST repository metadata/content reads and may satisfy Git read operations. |
| `repo:write` | Allows Git push through `git-receive-pack` and AGS REST writes to content, refs, automation, wiki, and similar repository data. |

Capabilities are scoped by repository and by current authorization facts. They
do not grant KB product access, workspace admin, repository settings admin, token
management, automation secret management, or any repository outside the token
scope. Write-capable tokens should include `repo:read` and `repo:clone` when the
caller also needs read or clone behavior.

MeshX must enforce capabilities before both Git Smart HTTP and repository REST
handlers. Git push discovery through
`info/refs?service=git-receive-pack` requires `repo:write`, not read.

## Authorization Convergence

Repository Access Tokens are scoped credentials, not permanent independent
grants. MeshX allows a request to enter the AGS repository plane only when all
relevant checks pass:

1. token exists, verifier matches, status is active, and token is not expired;
2. requested repository matches token scope, and requested provider host matches
   token `providerHost` when the data-plane surface carries a provider-host
   dimension;
3. requested operation is covered by token capabilities;
4. the bound human principal still has the required current repository
   permission, or the bound agent token is still allowed by current MeshX
   lifecycle state.

If workspace membership, repository permission, agent status, repository scope,
or runtime permission mode is reduced, existing tokens must fail closed
immediately through current authorization checks or be revoked/rotated by
lifecycle reconciliation.

## Token Contract

Repository Access Token management exists only on the MeshX `/api/v1` surface.
AGS does not expose a second token-management API and does not persist MeshX
token lifecycle state. The AGS legacy `/api/v3/user/tokens` API remains a
separate GitHub-compatible personal-token feature and must not be treated as the
Repository Access Token management plane.

### Token Reference

Public token metadata uses this shape:

```json
{
  "id": "rat_...",
  "agsTokenId": "ags_tok_...",
  "type": "human",
  "displayName": "Docs read token",
  "ownerPrincipalId": "usr_...",
  "workspaceId": "wsp_...",
  "agentId": null,
  "providerHost": "github.com",
  "repositoryScope": {
    "mode": "repositories",
    "repositories": ["owner/repo"]
  },
  "capabilities": ["repo:read", "repo:clone"],
  "status": "active",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "lastUsedAt": null,
  "expiresAt": null,
  "revokedAt": null
}
```

Supported statuses are `active`, `revoked`, `expired`,
`pending_reconcile`, and `error`.

### Create Human Token

`POST /api/v1/workspaces/:workspaceId/repository-access-tokens` creates a human token and returns:

```json
{
  "token": { "id": "rat_..." },
  "plaintext": "ags_rat_..."
}
```

Rules:

- `displayName`, `providerHost`, `repositoryScope`, and `capabilities` are
  required.
- `expiresAt` is optional unless deployment policy requires an expiration.
- plaintext is returned only in the create response;
- create must not persist plaintext or reversible token material;
- if AGS cannot return one-time plaintext safely, create must fail rather than
  create an unrecoverable credential silently.

### Agent Reconcile

The MeshX internal reconcile endpoint converges one agent token to desired
state. If desired scope or capabilities are empty, MeshX revokes existing agent
repository tokens instead of creating a broad token.

`force=true` revoke records a suppression state so later lifecycle reconciliation
does not recreate a token after a security response without an explicit
unsuppress action.

## MeshX Wrapper Contract

AgentTeam exposes the public product-facing API under
`/api/v1/workspaces/:workspaceId/repository-access-tokens`:

- `GET /api/v1/workspaces/:workspaceId/repository-access-tokens`
- `POST /api/v1/workspaces/:workspaceId/repository-access-tokens`
- `GET /api/v1/workspaces/:workspaceId/repository-access-tokens/{id}`
- `GET /api/v1/workspaces/:workspaceId/repository-access-tokens/{id}/events`
- `POST /api/v1/workspaces/:workspaceId/repository-access-tokens/{id}/revoke`
- `POST /api/v1/workspaces/:workspaceId/internal/repository-access-tokens/agents/{agent_id}/reconcile`
- `POST /api/v1/workspaces/:workspaceId/internal/repository-access-tokens/agents/{agent_id}/revoke`

The public path is forwarded only after AgentTeam validates the workspace. After
canonical authorization and prefix stripping, embedded MeshX may receive the
corresponding private in-process target `/api/v1/repository-access-tokens...`,
not a public URL.

The public list/get/revoke/event endpoints expose only the current human
principal's human tokens. Internal agent endpoints require workspace-scoped
internal authority such as `automation:runner:manage` or
`repository_access_tokens:agent:manage`.

Memory and Skill access-batch endpoints are a separate MeshX product surface.
When they return bound repositories they also return a short-lived
`syncToken`/`syncTokenExpires` pair. That token is a MeshX `sync_lease` scoped
to the repositories in the response and is intended only for Desktop Git sync.

When the MeshX token store or AGS request-scoped authentication bridge is not
available, production fails closed and must not fall back to fake tokens,
generic AGS tokens, AgentTeam passwords, or dev admin tokens.

Stable product error codes:

| HTTP | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_request` | Request shape, scope, capability, or expiration is invalid. |
| 403 | `permission_denied` | Caller lacks product or token authority. |
| 404 | `token_not_found` | Token is unknown or not visible to caller. |
| 409 | `token_state_conflict` | Token state changed or lifecycle suppression blocks reconcile. |
| 503 | `token_store_unavailable` | MeshX token persistence or verifier is unavailable. |

## Persistence Requirements

MeshX must use a repository-token-specific persistence model. It must not reuse
the generic `tokens.value` plaintext column as the authoritative verifier.

Minimum MeshX state:

- token id and public lookup id;
- irreversible verifier hash or keyed digest;
- short non-secret fingerprint for logs and audit correlation;
- token type;
- display name;
- owner principal or AGS user id;
- workspace id;
- optional agent id;
- provider host;
- repository scope;
- capabilities;
- status;
- created, updated, last-used, expiration, and revoked timestamps.

Event state records bounded audit facts:

- token id;
- event type;
- actor principal id or `system`;
- created timestamp;
- non-secret metadata.

Forbidden persistence:

- plaintext token;
- reversible encrypted token;
- upstream provider token;
- local proxy lease plaintext;
- client-supplied AgentTeam/PingCAP/OIDC access token.

Data-layer model structs represent persistence projections and must not carry
JSON tags. HTTP request/response DTOs belong in API packages.

Token lookup must be indexed by a request-derived public id or fingerprint and
must not scan all tokens. List and event queries must be bounded by workspace,
owner/type/status filters, pagination, or token id. Last-used updates must be
throttled or coalesced so successful Git operations do not write on every packet
or request fragment.

## Secret Handling And Audit

Plaintext token values must be absent from:

- logs;
- metrics;
- traces;
- audit metadata;
- browser local storage;
- test snapshots;
- MeshX projection tables;
- AgentTeam gateway request logs.

Events include `created`, `plaintext_revealed`, `scope_updated`,
`capabilities_updated`, `lease_created`, `lease_expired`, `revoked`, and
`reconcile_failed`. Event metadata may include reason, actor, repository scope
summary, and capability summary, but never plaintext or verifier material.

## UI Requirements

The UI is a developer/settings surface behind the MeshX gate. It must:

- list safe human token metadata;
- create human tokens with explicit repository scope and capabilities;
- in the current single-provider embedded MeshX/AGS deployment, derive
  `providerHost` from the public AGS/AgentTeam gateway host used for Git/API access
  instead of asking the user to enter a provider host;
- show plaintext only once after creation;
- keep plaintext only in transient component state;
- require confirmation before revoke;
- explain that Git uses Repository Access Tokens, not AgentTeam account passwords;
- avoid showing agent tokens in the human token list;
- provide complete i18n in supported workspace locales.

UI copy must not instruct users to use AgentTeam account passwords for Git remotes.
If a later deployment supports multiple repository providers, the UI should use
a configured provider selector rather than a free-text host field.

## Non-Goals

- Reusing `/api/v3/user/tokens` as Repository Access Tokens.
- Supporting AgentTeam account password Basic auth for production Git access.
- Supporting wildcard repository scopes before a policy resolver exists.
- Making AGS repository readability a KB grant.
- Exposing agent token plaintext to users or agents.
- Storing real AGS/provider credentials in MeshX projection tables.
