Forge native integration: PRD + forge library layer #318
Reference in New Issue
Block a user
Delete Branch "forge-native-integration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #317.
PRD
Design
Forge-native runs are driven by a forge sidecar (option 3): the agent
calls the sidecar, which holds the forge token and makes the actual Gitea
API calls. The agent never sees the credential or a forge-specific
endpoint. Completion is an unambiguous
signal_done(status, summary)sidecar call relayed to the orchestrator over a queue dir — no
comment-parsing. Scope is read-anywhere / write-scoped: reads for
context are unrestricted; writes are limited to the assigned issue and its
PRs.
The orchestration loop + webhook listener live in a separate binary
(
bot-bottle-orchestrator, a PRD non-goal). This PR covers bot-bottle'sside of that contract.
What this PR implements
The self-contained forge library layer both the sidecar and orchestrator
build on (PRD chunks 1–3, 5):
contrib/forge/base.py—ForgeABC +ScopedForge, enforcingread-anywhere / write-scoped (
ForgeScopeErroron out-of-scope writes).contrib/gitea/client.py—GiteaClient(stdlib-only HTTP, mirrorsthe deploy-key provisioner) +
GiteaForge. Token held by the caller(the sidecar), not injected by cred-proxy.
contrib/gitea/forge_state.py—ForgeState+ atomicread/write/delete/all under
~/.bot-bottle/forge/<owner>/<repo>/.contrib/gitea/provenance.py—build_provenance_footer, thecollapsed markdown audit footer (watchdog / gitleaks / egress rows).
cli/resume.py—resume --headless --prompt, reusing the shippedassume_yes+headless_promptlaunch core (the new half of chunk 1).47 new unit tests; pylint 9.98/10, pyright clean.
Deferred (correctly out of scope here)
orchestratecommand (chunk 6):their only consumer is the separate orchestrator; untestable as
standalone shells in this repo.
forge_envplumbing: no in-repo consumer until the sidecar exists.Merge rule(s)
Requires human review and merge — no auto-merge.
PRD: Forge native integrationto Forge native integration: PRD + forge library layer@@ -0,0 +27,4 @@@dataclass(frozen=True)class Issue:"""A forge issue or PR (forges model PRs as issues with the samenumber)."""There should also be a “PullRequest” dataclass/issues and PullRequests should not use the same object
@@ -0,0 +53,4 @@@abc.abstractmethoddef read_issue(self, number: int) -> Issue:"""Read an issue or PR body (read-anywhere)."""Should be a separate “read_pr” method
@@ -0,0 +5,4 @@freeze / rehydrate loop, and run the watchdog. State lives on disk andsurvives orchestrator restarts:~/.bot-bottle/forge/<owner>/<repo>/issue-<n>.jsonWe should introduce sqlite and start writing state in a local db now. We should do it the following way:
@@ -0,0 +1,103 @@"""Provenance footer (PRD forge-native-integration, chunk 5).Every orchestrator-posted comment ends with this footer — non-optionaland not configurable off. It renders the run's audit trail (agent,Get rid of the provenance footer
@@ -0,0 +447,4 @@alongside the agent for forge-targeted runs. Tests: arg parsing, `start`delegates to `start --headless`, `resume` delegates to `resume --headless`.## Provenance as the productReword this: we will have a provenance api, but we won’t surface it in the pr
Addressed the review in commit
42004d3:PullRequestdataclass +read_pr—IssueandPullRequestare now separate frozen dataclasses (a PR carriesmerged), read through separateread_issue/read_prmethods onForge/ScopedForge/GiteaForge.is_pr_opennow derives fromread_pr.ForgeStateStore(upsert/get/delete/all), backed bySqliteForgeStateStoreat~/.bot-bottle/bot-bottle.db. Storage location/engine is swappable behind the interface.provenance.pyand its test.pyright clean (whole repo), pylint 10/10, forge/resume unit tests pass.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.