Files
bot-bottle/docs/prds/prd-new-trusted-agent-forge-identity.md
T

17 KiB

PRD prd-new: Trusted agent forge identity and guidance

  • Status: Draft
  • Author: didericis-claude
  • Created: 2026-07-25
  • Issue: #423

Summary

Move author identity and named forge configurations into host-trusted agent definitions. A bottle may optionally associate a git-gate repository with one of the selected agent's forge aliases. When associated, bot-bottle gives the agent non-secret, provider-specific system guidance for that repository and routes authenticated forge API calls through the egress proxy without exposing the forge token to the bottle. The authenticated account is inferred from the identity that owns that token; it is not separately declared in the manifest.

Repository-local agent and bottle definitions are no longer discovered. Once agent definitions can select a host forge credential, allowing checked-out repository content to define or override an agent would let untrusted workspace content select host identities and secrets.

This PRD is deliberately limited to identity ownership, manifest trust, forge API access, and generated guidance. Per-activation signing, signature enforcement, commit attribution, and the commit audit model move to a follow-up PRD.

Successor to:

  • PRD 0011 (per-file manifests) — allowed repository-local agent files to override home agents. This PRD removes that trust path: agents and bottles are loaded only from the host-owned ~/.bot-bottle tree.
  • PRD 0027 (agent git identity, #94) / ADR 0002 — put name/email in git-gate.user while keeping them claimed rather than vouched. This PRD moves those agent properties out of git-gate and into the trusted agent definition.
  • PRD 0048 (deploy-key provisioning, #169) — remains the Git push capability. A forge actor token is a separate API credential and never replaces a deploy key.

Problem

Forge workflow context is missing

The agent prompt does not know which forge backs a git-gate repository, which API base URL to use, or that authenticated requests must go through the egress proxy. Bespoke prompt text has drifted between agents. Missing guidance has already caused incorrect PR behavior, including attempts to use Gitea AGit review refs instead of a normal branch-backed pull request.

Identity is owned by the wrong layer

git-gate.user puts an agent property on a repository transport component. An author identity and set of forge credentials should follow the agent across bottles and repositories. Git-gate should own Git transport policy, not decide who the agent is.

Repository-local agents become a credential-selection path

Today $CWD/.bot-bottle/agents/*.md can define new agents and override home-resident agents. If an agent definition may reference an operator-provided forge token, a malicious repository could select a host credential merely by being the current workspace. Repository-local bottles are already ignored; agents need the same host-only boundary.

Goals / Success Criteria

  • Agent-owned identity. Author name/email and named forge configurations live on the agent definition, not under git-gate.
  • Trusted definitions only. Agent and bottle files are discovered only under ~/.bot-bottle/{agents,bottles}. Repository-local definitions never contribute names, defaults, or overrides.
  • Optional repository association. A bottle repository may name one forge alias from the selected agent. Repositories without forge retain current behavior and generate no forge guidance or credential route.
  • Proxy-held forge credential. The host resolves the selected forge alias's token reference and gives the value only to the egress proxy. The bottle receives neither the token nor a credential file containing it.
  • Forge-aware system guidance. For associated repositories, bot-bottle generates provider-specific instructions describing the API base URL, repository/account association, proxy-authenticated access, and correct PR workflow.
  • No secret prompt material. Neither token values nor token environment-variable names appear in the prompt or bottle environment.
  • Fail closed. Unknown account references, unsupported/non-HTTPS URLs, missing host secrets, and misplaced agent/bottle fields fail before creating the bottle.
  • Push capability unchanged. Git transport remains PRD 0048 deploy keys. The forge actor token is only for API actions such as opening, reviewing, and commenting on pull requests.

Non-goals

  • Commit signing or signature enforcement. No signing key is minted and git-gate does not verify commit signatures in this PRD.
  • Commit attribution or audit tables. There is no trustworthy commit observation event in this slice. A follow-up signing PRD owns activation keys, control-plane verification, and any configured-author-versus-claimed-author audit model.
  • Cryptographically vouched author identity. author configures Git and identifies the agent actor, but commit author/committer fields remain claims under ADR 0002.
  • Forge account or token minting. The operator creates the agent-specific account/token out of band. Bot-bottle references an existing host secret; it does not create, rotate, or revoke that credential.
  • Forge-side commit attribution surfaces. No commit status, signing-key registration, or "Verified" badge.
  • Provider-generic arbitrary prompts. Gitea is the first supported forge. A future provider adds typed validation and generated guidance in code rather than accepting repository-supplied prompt text.

Design

Ownership model

The resolved bottled agent is an agent definition composed with a bottle:

Part Source Role
Author identity agent author configures Git name/email and identifies the agent's claimed author
Forge configurations agent forge-accounts maps forge aliases to API origins and host token references available to this agent; token ownership determines account identity
Git repository bottle git-gate.repos configures Git transport, host verification, and push capability
Repository/forge association bottle repo forge optionally selects an agent forge alias for guidance and API access

This boundary keeps identity on the agent, capability/policy on the bottle, and transport enforcement in git-gate.

Agent manifest

Agent identity and forge accounts live only in ~/.bot-bottle/agents/<name>.md:

---
author:
  name: didericis-claude
  email: eric+claude@dideric.is
forge-accounts:
  didericis-gitea:
    auth:
      type: token
      token_secret: GITEA_CLAUDE_TOKEN
    url: https://gitea.dideric.is/api/v1
---

author contains:

  • name: non-empty string;
  • email: non-empty string passing the existing Git identity validation.

The resolved values populate user.name and user.email. Existing git-gate.user fields fail with migration guidance to move the values into the selected home agent's author block. There is no compatibility period where a bottle identity silently overrides the agent identity.

forge-accounts is a map whose keys are forge aliases and follow the manifest's existing kebab-case identifier grammar ([a-z][a-z0-9-]*). Each forge entry contains:

  • url: a canonical HTTPS Gitea API base URL;
  • auth.type: token in this slice;
  • auth.token_secret: the name of a host environment variable containing the operator-provided, agent-specific API token.

The token's owner determines the authenticated forge account; there is no separate account-name field. The token secret name is host configuration, not bottle configuration. The token value is resolved only if a selected bottle repository references the forge alias.

Bottle manifest

Repository policy remains in ~/.bot-bottle/bottles/<name>.md:

---
git-gate:
  repos:
    bot-bottle:
      url: ssh://git@100.78.141.42:30009/didericis/bot-bottle.git
      provisioned_key:
        provider: gitea
        token_env: GITEA_DEPLOY_TOKEN
      host_key: "ssh-ed25519 AAAA..."
      forge: didericis-gitea
---

git-gate.repos.<name>.forge is optional:

  • When absent, the repository behaves exactly as it does today. Bot-bottle does not resolve a forge actor token and does not add forge-specific instructions for that repository.
  • When present, it must match a forge alias in forge-accounts on the selected agent. The resolved association enables a scoped proxy credential route and adds the repository/forge relationship to generated system guidance.

provisioned_key.token_env remains the deploy-key administration credential from PRD 0048. It is separate from forge-accounts.*.auth.token_secret: the former provisions Git push capability, while the latter performs API actions as the agent.

author and forge-accounts are agent-only. git-gate.repos, including forge, is bottle-only. Validation errors point to the correct file and trust domain rather than ignoring misplaced keys.

Definition trust and discovery

Only the host-owned manifest tree is authoritative:

  • Agents: ~/.bot-bottle/agents/*.md
  • Bottles: ~/.bot-bottle/bottles/*.md

$CWD/.bot-bottle/agents/*.md no longer contributes new agents and no longer overrides a home agent. $CWD/.bot-bottle/bottles/*.md remains unusable. If either repository-local directory contains manifest files, bot-bottle emits a warning that they are ignored and points to the corresponding home path.

Every discovery and resolution surface uses the same home-only index:

  • agent enumeration and selectors;
  • require_agent;
  • lazy load_for_agent;
  • default-agent/default-bottle resolution;
  • dashboard and headless launch paths.

There must be no alternate direct-path load that can still select a workspace definition.

Workspace instructions remain repository content (for example AGENTS.md), but runtime policy, host secret references, and actor identity do not. Programmatic in-memory manifests remain available for tests and trusted internal composition; they are not a filesystem discovery path.

Forge URL validation

The host parses and canonicalizes each referenced forge alias's URL before creating any runtime resources:

  • scheme must be https;
  • userinfo, query, and fragment are forbidden;
  • hostname must be present;
  • the path must be a supported Gitea API base (initially /api/v1, with normalization of a trailing slash);
  • visually different inputs that canonicalize to the same origin/prefix are deduplicated;
  • unsupported providers or path shapes fail closed.

The provider is determined by typed support in bot-bottle, not by prompt text from a repository. Adding another provider requires a validator, auth scheme, and guidance renderer.

Proxy credential provisioning

For each distinct forge alias referenced by at least one selected bottle repository, the host:

  1. Resolves auth.token_secret from the host environment and rejects a missing or empty value.
  2. Copies the token value only into the egress proxy's credential environment.
  3. Adds an inspected route scoped to the canonical forge origin and API prefix.
  4. Configures the provider authentication scheme (token for Gitea) so the proxy injects authentication.

The bottle makes an unauthenticated request to the configured HTTPS API URL. The token is not copied into the bottle, .gitconfig, generated prompt, workspace, or process environment visible to the agent.

If several repositories reference the same forge alias, they share one credential route. Unreferenced forge aliases resolve no secret and create no route.

Generated system guidance

Bot-bottle appends a generated, non-secret section to its existing system prompt file. It is derived from validated typed fields, not copied Markdown from a repository.

For each associated repository, Gitea guidance includes:

  • forge alias (for example didericis-gitea);
  • API base URL (for example https://gitea.dideric.is/api/v1);
  • the git-gate repository name tied to that forge;
  • the instruction to call the configured HTTPS API through the proxy without reading, printing, or manually attaching an authorization token;
  • the distinction that Git pushes still use the git-gate remote;
  • the requirement to create/update a normal refs/heads/<branch> and open a branch-backed pull request through the API;
  • the prohibition on pushing refs/for/*, refs/draft/*, or refs/for-review/*;
  • the instruction to use the API for reviews/comments and verify returned object state before claiming completion.

The prompt contains neither the token value nor its token_secret name. Repositories without forge are omitted from this section. If no selected repository has a forge association, no forge guidance section is generated.

Failure and lifecycle behavior

Forge configuration is validated before bottle creation. A bad association or credential must not leave a partially-created bottle or proxy.

The operator-owned token is not minted, rotated, or revoked by bot-bottle. On teardown, stopping the egress proxy discards the activation's in-memory/runtime copy. Later activations resolve the current host secret again.

Logs may include the forge alias, canonical API origin, and repository name. They must never contain the token value. Errors for missing secrets name the configuration field and host environment variable, but do not print any value.

Migration

This change is intentionally breaking at the manifest trust boundary:

  1. Move each home bottle/agent git-gate.user.name and .email into the corresponding home agent's author.
  2. Add agent-specific forge-accounts only to home agent definitions.
  3. Add optional forge associations to home bottle repository entries.
  4. Move any $CWD/.bot-bottle/agents/*.md that should remain selectable into ~/.bot-bottle/agents/. Repository copies are ignored thereafter.
  5. Keep repository-specific behavioral instructions in AGENTS.md or another workspace instruction file; do not put runtime identity or secret references there.

Errors and warnings link to this migration rather than silently changing which identity or definition is active.

Follow-up: signed commits and attribution

A separate PRD will consume the trusted agent author introduced here and own:

  • per-activation signing key minting and sidecar isolation;
  • commit-time signing through a forwarded signing capability;
  • git-gate rejection of unsigned/wrong-key new commits;
  • independent control-plane object-ID recomputation and signature verification;
  • activation and attributed-commit audit tables;
  • storage of configured agent author separately from each commit's unenforced claimed author/committer;
  • post-teardown verification and key-retention policy.

That PRD must not reintroduce identity under git-gate or expand repository-local manifest trust.

Implementation chunks

  1. This PRD. Establish the identity, forge, and filesystem trust boundary.
  2. Home-only definitions. Remove cwd agents from discovery, override, enumeration, lazy loading, defaults, and selectors. Warn on ignored cwd agent/bottle files and provide migration guidance.
  3. Manifest schema. Add agent-only author and forge-accounts; remove git-gate.user; add optional bottle-only git-gate.repos.<name>.forge. Validate account names, composition references, field placement, and Gitea API URLs.
  4. Proxy provisioning. Lazily resolve only referenced token secrets and create scoped authenticated Gitea API routes without putting credentials in the bottle.
  5. Prompt generation. Render typed Gitea/repository workflow guidance into the existing bot-bottle prompt path for associated repositories only.
  6. Docs and migration. Update README examples, PRD 0011-facing discovery documentation, agent/bottle schema docs, and error guidance.

Testing strategy

  • Trust boundary: cwd agent files are ignored with a warning, cannot override a home agent, are absent from enumeration/selectors/defaults, and cannot be loaded by name. Cwd bottle behavior remains home-only.
  • Agent schema: author and forge-accounts parse; malformed identities, non-kebab account names, unknown fields, invalid auth types, and misplaced git-gate fields fail clearly.
  • Bottle schema: forge is optional; absent associations preserve current behavior; present associations resolve against the selected agent; unknown or misplaced associations fail before launch.
  • URL validation: HTTPS Gitea API bases pass and canonicalize; HTTP, userinfo, query, fragment, missing host, unsupported paths, and unsupported providers fail closed.
  • Secret handling: only referenced accounts resolve environment secrets; missing/empty secrets fail before runtime creation; token values are absent from bottle env, prompt, generated config, logs, and workspace; token secret names are absent from the bottle and prompt.
  • Proxy behavior: associated API requests receive proxy-injected Gitea authentication scoped to the configured origin/prefix; unrelated hosts and paths receive no credential.
  • Prompt behavior: guidance names account/API/repository associations, branch-backed PR workflow, prohibited AGit refs, and mutation verification; repositories without forge are omitted; no associations means no section.
  • Migration: legacy git-gate.user fails with an author migration pointer; ignored cwd definitions warn with the target home path.

Open questions

  • None.