feat(manifest): trusted agent forge identity and guidance

Implements PRD prd-new-trusted-agent-forge-identity. Moves author identity
and named forge configurations onto the trusted, host-only agent definition,
and lets a bottle repository optionally associate a git-gate repo with one of
the agent's forge aliases.

- Agent-owned identity: new `author` (name/email) and `forge-accounts`
  (alias -> canonical Gitea /api/v1 origin + host `token_secret` ref) on the
  agent manifest. `author` populates the bottle's git user.name/user.email.
- Remove `git-gate.user` from both agents and bottles; fail with a migration
  pointer to `author`. `git-gate` is no longer accepted on an agent.
- Bottle git-gate repos gain optional `forge: <alias>`, resolved against the
  selected agent's forge-accounts at composition (fail-closed on unknown).
- Fail-closed Gitea API URL validation (https, no userinfo/query/fragment,
  /api/v1 base, host lowercased, trailing slash normalized, host dedup).
- Proxy-held credential: synthesize one inspected, token-authenticated egress
  route per referenced forge alias, scoped to the origin + API prefix. The
  token is resolved from the host env at launch into the egress proxy only —
  never the bottle env, prompt, gitconfig, or workspace.
- Generated, non-secret forge workflow guidance appended to the agent prompt
  for associated repos (API base, branch-backed PR flow, AGit-ref prohibition,
  mutation verification); omitted when no repo declares a forge.
- Agents become home-only: cwd `.bot-bottle/agents` no longer contributes,
  overrides, or is selectable; warned-and-ignored like cwd bottles.
- Docs: README examples, PRD 0011 supersession note, manifest schema docstring.
- Tests: new test_forge_identity suite; legacy git-gate.user/cwd tests updated
  to the agent-owned identity model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 00:20:14 +00:00
committed by didericis
parent 5cb1c190f4
commit cf15500fb8
26 changed files with 1261 additions and 439 deletions
+10 -5
View File
@@ -71,11 +71,14 @@ class _LazyCase(unittest.TestCase):
class TestAllAgentNamesLazy(_LazyCase):
def test_merges_home_and_cwd_agents(self) -> None:
def test_cwd_agents_ignored_home_only(self) -> None:
# Agents are home-only (PRD prd-new-trusted-agent-forge-identity):
# a cwd agents/ dir is warned-and-ignored, so only the home agent
# appears in all_agent_names.
_write(self.home_cb / "bottles" / "dev.md", _BOTTLE_DEV)
_write(self.home_cb / "agents" / "alpha.md", _AGENT)
_write(self.cwd_cb / "agents" / "beta.md", _AGENT)
self.assertEqual(["alpha", "beta"], self.resolve().all_agent_names)
self.assertEqual(["alpha"], self.resolve().all_agent_names)
class TestLoadForAgentLazy(_LazyCase):
@@ -96,11 +99,13 @@ class TestRequireAgentLazy(_LazyCase):
_write(self.home_cb / "agents" / "alpha.md", _AGENT)
self.resolve().require_agent("alpha") # no raise
def test_existing_cwd_agent_ok(self) -> None:
# File only under cwd -> require_agent's cwd_path branch.
def test_cwd_only_agent_not_selectable(self) -> None:
# Agents are home-only (PRD prd-new-trusted-agent-forge-identity):
# a cwd-only agent file is never selectable, so require_agent raises.
_write(self.home_cb / "agents" / "alpha.md", _AGENT)
_write(self.cwd_cb / "agents" / "beta.md", _AGENT)
self.resolve().require_agent("beta") # no raise
with self.assertRaises(ManifestError):
self.resolve().require_agent("beta")
def test_unknown_agent_raises(self) -> None:
_write(self.home_cb / "agents" / "alpha.md", _AGENT)