PRD 0027: Agent-level git user identity #95

Merged
didericis merged 3 commits from feat/agent-git-user-identity into main 2026-05-28 21:32:38 -04:00
Owner

Closes #94.

Tracking PR for PRD 0027.

Summary

Let an agent file declare git.user (name/email). At launch it overlays the referenced bottle's git.user per-field (agent wins on non-empty), mirroring the PRD 0025 extends: merge. git.remotes stays bottle-only — it carries credentials and host trust. Solves the coupling where varying a commit identity meant authoring a whole separate bottle.

Git authorship is not a credential (push auth is the bottle's remote key/token) and is already forgeable from inside the bottle, so a repo-shipped agent setting its own identity grants no access; an agent identity is claimed, not vouched.

Schema

---
bottle: claude-dev
git:
  user:
    name: claude-implementer
    email: eric+claude-implementer@dideric.is
---
  • git.user accepts name and/or email (string-or-die; at least one non-empty), validated by the existing GitUser parser.
  • Any agent git key other than user — notably remotes — dies at parse with a bottle-only pointer.

Merge rule

Field Merge
git_user.name agent's if non-empty, else the bottle's
git_user.email agent's if non-empty, else the bottle's

Same per-field overlay _merge_bottles applies for extends:. Empty string = "not set". All other bottle fields pass through untouched.

Changes (3 commits)

  1. docs(prd) — PRD 0027: design + trust analysis.
  2. feat(manifest)Agent.git_user; parse + reject non-user git keys; per-field overlay at Manifest.bottle_for() (the single chokepoint both backends use, so provisioners are untouched); Manifest.git_identity_summary() with (agent)/(bottle) provenance, printed in both preflights and cli.py info. 17 unit tests in test_manifest_agent_git_user.py.
  3. docs(manifest) — README manifest section; collapses the example so implementer carries its own identity against the shared dev bottle instead of an identity-only bottle.

Full unit suite green (738 tests).

Closes #94. Tracking PR for [PRD 0027](https://gitea.dideric.is/didericis/bot-bottle/src/commit/dcd90cd45e17ef65a862b8f710878db70a61d09c/docs/prds/0027-agent-git-user-identity.md). ## Summary Let an **agent** file declare `git.user` (name/email). At launch it overlays the referenced bottle's `git.user` per-field (agent wins on non-empty), mirroring the [PRD 0025](https://gitea.dideric.is/didericis/bot-bottle/src/commit/dcd90cd45e17ef65a862b8f710878db70a61d09c/docs/prds/0025-bottle-extends.md) `extends:` merge. `git.remotes` stays bottle-only — it carries credentials and host trust. Solves the coupling where varying a commit identity meant authoring a whole separate bottle. Git authorship is not a credential (push auth is the bottle's remote key/token) and is already forgeable from inside the bottle, so a repo-shipped agent setting its own identity grants no access; an agent identity is *claimed, not vouched*. ## Schema ```yaml --- bottle: claude-dev git: user: name: claude-implementer email: eric+claude-implementer@dideric.is --- ``` - `git.user` accepts `name` and/or `email` (string-or-die; at least one non-empty), validated by the existing `GitUser` parser. - Any agent `git` key other than `user` — notably `remotes` — dies at parse with a bottle-only pointer. ## Merge rule | Field | Merge | |-------------------|----------------------------------------------| | `git_user.name` | agent's if non-empty, else the bottle's | | `git_user.email` | agent's if non-empty, else the bottle's | Same per-field overlay `_merge_bottles` applies for `extends:`. Empty string = "not set". All other bottle fields pass through untouched. ## Changes (3 commits) 1. **`docs(prd)`** — PRD 0027: design + trust analysis. 2. **`feat(manifest)`** — `Agent.git_user`; parse + reject non-`user` git keys; per-field overlay at `Manifest.bottle_for()` (the single chokepoint both backends use, so provisioners are untouched); `Manifest.git_identity_summary()` with `(agent)`/`(bottle)` provenance, printed in both preflights and `cli.py info`. 17 unit tests in `test_manifest_agent_git_user.py`. 3. **`docs(manifest)`** — README manifest section; collapses the example so `implementer` carries its own identity against the shared `dev` bottle instead of an identity-only bottle. Full unit suite green (738 tests).
didericis added 1 commit 2026-05-28 20:58:22 -04:00
docs(prd): add PRD 0027 agent-level git user identity
test / unit (pull_request) Successful in 27s
test / integration (pull_request) Successful in 43s
f9e3b6adda
Lift git.user (name/email) to the agent layer with a per-field
overlay onto the referenced bottle, mirroring the extends: merge.
git.remotes stays bottle-only. Includes identity provenance in
preflight/info and an example collapse.

Refs #94

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
didericis added 2 commits 2026-05-28 21:10:58 -04:00
Agents may declare git.user (name/email); it overlays the referenced
bottle's git.user per-field at Manifest.bottle_for (agent wins on
non-empty), mirroring the extends: merge. git.remotes is rejected on
agents — it carries credentials and host trust and stays bottle-only.

The overlay lives at bottle_for, the single chokepoint both backends
use, so the docker/smolmachines git provisioners are unchanged. Adds
Manifest.git_identity_summary with per-field (agent)/(bottle)
provenance, printed in both preflights and `info`.

Refs #94

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(manifest): document + demo agent-level git.user
test / unit (pull_request) Successful in 35s
test / integration (pull_request) Successful in 57s
test / unit (push) Successful in 32s
test / integration (push) Successful in 44s
dcd90cd45e
README manifest section documents the agent git.user overlay, the
bottle-only git.remotes boundary, and the claimed-not-vouched trust
note. Collapses the example: implementer carries its own identity
against the shared dev bottle instead of an identity-only bottle.

Refs #94

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
didericis changed title from feat(manifest): agent-level git user identity to feat(manifest): agent-level git user identity (PRD 0027, issue #94) 2026-05-28 21:27:17 -04:00
didericis changed title from feat(manifest): agent-level git user identity (PRD 0027, issue #94) to PRD 0027: Agent-level git user identity 2026-05-28 21:27:51 -04:00
didericis merged commit dcd90cd45e into main 2026-05-28 21:32:38 -04:00
didericis deleted branch feat/agent-git-user-identity 2026-05-28 21:32:38 -04:00
Sign in to join this conversation.