autoforge-cli 0.1.0a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autoforge_cli-0.1.0a0/LICENSE +21 -0
- autoforge_cli-0.1.0a0/MANIFEST.in +7 -0
- autoforge_cli-0.1.0a0/PKG-INFO +525 -0
- autoforge_cli-0.1.0a0/README.md +496 -0
- autoforge_cli-0.1.0a0/pyproject.toml +90 -0
- autoforge_cli-0.1.0a0/setup.cfg +4 -0
- autoforge_cli-0.1.0a0/src/autoforge/__init__.py +5 -0
- autoforge_cli-0.1.0a0/src/autoforge/agent_worktree.py +653 -0
- autoforge_cli-0.1.0a0/src/autoforge/certificate.py +495 -0
- autoforge_cli-0.1.0a0/src/autoforge/child_env.py +871 -0
- autoforge_cli-0.1.0a0/src/autoforge/claims.py +726 -0
- autoforge_cli-0.1.0a0/src/autoforge/claude_stream.py +501 -0
- autoforge_cli-0.1.0a0/src/autoforge/cli.py +2884 -0
- autoforge_cli-0.1.0a0/src/autoforge/config.py +2178 -0
- autoforge_cli-0.1.0a0/src/autoforge/config_fingerprint.py +374 -0
- autoforge_cli-0.1.0a0/src/autoforge/doctor.py +1551 -0
- autoforge_cli-0.1.0a0/src/autoforge/doctor_sandbox.py +691 -0
- autoforge_cli-0.1.0a0/src/autoforge/effect_ops.py +1272 -0
- autoforge_cli-0.1.0a0/src/autoforge/effects.py +3210 -0
- autoforge_cli-0.1.0a0/src/autoforge/engine.py +16637 -0
- autoforge_cli-0.1.0a0/src/autoforge/epic_commands.py +1486 -0
- autoforge_cli-0.1.0a0/src/autoforge/epic_graph.py +852 -0
- autoforge_cli-0.1.0a0/src/autoforge/errors.py +536 -0
- autoforge_cli-0.1.0a0/src/autoforge/evidence.py +1722 -0
- autoforge_cli-0.1.0a0/src/autoforge/executor.py +1601 -0
- autoforge_cli-0.1.0a0/src/autoforge/executor_duplex.py +985 -0
- autoforge_cli-0.1.0a0/src/autoforge/executor_supervised.py +144 -0
- autoforge_cli-0.1.0a0/src/autoforge/git_transport.py +970 -0
- autoforge_cli-0.1.0a0/src/autoforge/github.py +3402 -0
- autoforge_cli-0.1.0a0/src/autoforge/interaction.py +1027 -0
- autoforge_cli-0.1.0a0/src/autoforge/local_workspace.py +1253 -0
- autoforge_cli-0.1.0a0/src/autoforge/locking.py +1050 -0
- autoforge_cli-0.1.0a0/src/autoforge/loop_detect.py +660 -0
- autoforge_cli-0.1.0a0/src/autoforge/loop_guard.py +404 -0
- autoforge_cli-0.1.0a0/src/autoforge/materialize.py +722 -0
- autoforge_cli-0.1.0a0/src/autoforge/ownership.py +240 -0
- autoforge_cli-0.1.0a0/src/autoforge/pi_rpc.py +713 -0
- autoforge_cli-0.1.0a0/src/autoforge/premerge.py +181 -0
- autoforge_cli-0.1.0a0/src/autoforge/profiles.py +106 -0
- autoforge_cli-0.1.0a0/src/autoforge/progress.py +392 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/__init__.py +173 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/acceptance_actions.md +39 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/analyze_execute.md +128 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/common.md +132 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/correction.md +12 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/fix.md +252 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/local_analyze_execute.md +69 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/local_common.md +149 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/local_fix.md +96 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/local_review.md +103 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/operator_acceptance.md +61 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/replan_reexecute.md +991 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/review.md +312 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/update_epic.md +120 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/update_epic_rerequest.md +85 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/validation_evidence.md +26 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/validation_failure.md +22 -0
- autoforge_cli-0.1.0a0/src/autoforge/prompts/worktree_state.md +45 -0
- autoforge_cli-0.1.0a0/src/autoforge/providers.py +2893 -0
- autoforge_cli-0.1.0a0/src/autoforge/read_context.py +389 -0
- autoforge_cli-0.1.0a0/src/autoforge/redaction.py +408 -0
- autoforge_cli-0.1.0a0/src/autoforge/replan.py +208 -0
- autoforge_cli-0.1.0a0/src/autoforge/replan_txn.py +1930 -0
- autoforge_cli-0.1.0a0/src/autoforge/result_parser.py +2234 -0
- autoforge_cli-0.1.0a0/src/autoforge/roadmap.py +151 -0
- autoforge_cli-0.1.0a0/src/autoforge/run_contract.py +408 -0
- autoforge_cli-0.1.0a0/src/autoforge/run_namespace.py +839 -0
- autoforge_cli-0.1.0a0/src/autoforge/runlog.py +764 -0
- autoforge_cli-0.1.0a0/src/autoforge/safefs.py +1717 -0
- autoforge_cli-0.1.0a0/src/autoforge/sandbox.py +1313 -0
- autoforge_cli-0.1.0a0/src/autoforge/sandbox_bwrap.py +815 -0
- autoforge_cli-0.1.0a0/src/autoforge/sandbox_pin.py +170 -0
- autoforge_cli-0.1.0a0/src/autoforge/sandbox_policy.py +1107 -0
- autoforge_cli-0.1.0a0/src/autoforge/scheduler.py +1143 -0
- autoforge_cli-0.1.0a0/src/autoforge/scheduler_state.py +2316 -0
- autoforge_cli-0.1.0a0/src/autoforge/scheduler_stop.py +421 -0
- autoforge_cli-0.1.0a0/src/autoforge/sdk_policy.py +988 -0
- autoforge_cli-0.1.0a0/src/autoforge/state.py +2417 -0
- autoforge_cli-0.1.0a0/src/autoforge/transitions.py +388 -0
- autoforge_cli-0.1.0a0/src/autoforge/validation.py +324 -0
- autoforge_cli-0.1.0a0/src/autoforge/worker.py +568 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/PKG-INFO +525 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/SOURCES.txt +85 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/dependency_links.txt +1 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/entry_points.txt +2 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/requires.txt +3 -0
- autoforge_cli-0.1.0a0/src/autoforge_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ruoshi Li
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# The sdist carries what building the wheel needs: pyproject.toml, README.md,
|
|
2
|
+
# LICENSE and src/, whose resources [tool.setuptools.package-data] declares.
|
|
3
|
+
# setuptools would also add tests/test_*.py by default, but not the fixtures
|
|
4
|
+
# and fakes those need (tests/conftest.py, tests/fixtures/), so that copy
|
|
5
|
+
# could not run; the suite runs from a checkout (docs/development.md).
|
|
6
|
+
# tests/dist_check.py checks the sdist's file list.
|
|
7
|
+
prune tests
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autoforge-cli
|
|
3
|
+
Version: 0.1.0a0
|
|
4
|
+
Summary: Autonomous orchestration for AI-driven software development (deterministic controller over Claude Code / OpenCode / gh).
|
|
5
|
+
Author: Ruoshi Li
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/iceboundrock/AutoForge
|
|
8
|
+
Project-URL: Documentation, https://github.com/iceboundrock/AutoForge/tree/main/docs
|
|
9
|
+
Project-URL: Source, https://github.com/iceboundrock/AutoForge
|
|
10
|
+
Project-URL: Issues, https://github.com/iceboundrock/AutoForge/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/iceboundrock/AutoForge/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: ai,agents,orchestration,code-review,github,claude-code,opencode
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
+
Classifier: Topic :: Software Development
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Provides-Extra: yaml
|
|
27
|
+
Requires-Dist: pyyaml>=6; extra == "yaml"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# AutoForge / 智铸
|
|
31
|
+
|
|
32
|
+
**Autonomous orchestration for AI-driven software development.**
|
|
33
|
+
|
|
34
|
+
智铸:AI 驱动的软件工程自动化控制器。
|
|
35
|
+
|
|
36
|
+
> **Early development (Phase 2).** The first real AI development loop is
|
|
37
|
+
> wired end to end: GitHub issue → Claude Code implementation → controller
|
|
38
|
+
> push and PR → OpenCode review → Claude Code remediation → repeated review
|
|
39
|
+
> → `READY_FOR_MERGE`. Merging is opt-in and controller-owned: by default the
|
|
40
|
+
> loop stops at `READY_FOR_MERGE` for a human; with the merge safety gate
|
|
41
|
+
> open (`safety.allow_merge: true` in config and `--allow-merge` on the CLI)
|
|
42
|
+
> the controller itself verifies the PR on GitHub and merges it. Agents never
|
|
43
|
+
> merge. Nothing here is production ready yet.
|
|
44
|
+
|
|
45
|
+
## What AutoForge is (and is not)
|
|
46
|
+
|
|
47
|
+
AutoForge is not another coding agent. It is a deterministic orchestration
|
|
48
|
+
layer that drives existing agents through the software lifecycle and refuses
|
|
49
|
+
to trust anything they claim without checking it against GitHub:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
Issue → ANALYZE_EXECUTE (Claude Code) → controller pushes, opens PR → REVIEW (OpenCode)
|
|
53
|
+
→ clean ───────────────────────────────▶ READY_FOR_MERGE
|
|
54
|
+
→ findings ────────────────────────────▶ FIX (Claude Code) → REVIEW …
|
|
55
|
+
→ excessive / low-finding stagnation ──▶ REPLAN_REEXECUTE (OpenCode)
|
|
56
|
+
→ controller pushes, opens replacement PR
|
|
57
|
+
→ REVIEW round 1
|
|
58
|
+
├─ merge gate closed (default): stops here; human merges
|
|
59
|
+
└─ gate open: controller verifies on GitHub
|
|
60
|
+
→ MERGE (gh pr merge by the controller, no agent)
|
|
61
|
+
→ UPDATE_EPIC (agent returns the progress text
|
|
62
|
+
and the roadmap section and picks the next
|
|
63
|
+
issue; the controller posts the progress comment,
|
|
64
|
+
splices the section into the EPIC body every N
|
|
65
|
+
merges, reads both back, and verifies the next
|
|
66
|
+
issue on GitHub, or DONE)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
AutoForge itself never writes business code. It holds the workflow state
|
|
70
|
+
machine, selects which provider, model and effort runs each phase, renders
|
|
71
|
+
strictly validated prompts from file templates, invokes `claude` /
|
|
72
|
+
`opencode` through provider adapters and `gh` through a typed client (argv
|
|
73
|
+
lists only, never a shell), parses the machine-readable `CONTROL_RESULT`
|
|
74
|
+
block from agent output, and verifies every claim on GitHub before it
|
|
75
|
+
advances state. Every invocation is logged, redacted, under
|
|
76
|
+
`<state dir>/logs/<run-id>/`; the state directory defaults to `.autoforge/`
|
|
77
|
+
for a remote run and to `<git dir>/autoforge/state` for a
|
|
78
|
+
[local run](docs/local-mode.md#resume-and-recovery).
|
|
79
|
+
|
|
80
|
+
It is a single-machine client tool, not a distributed service: one process
|
|
81
|
+
on your own machine, driving your `git`, `gh`, and agent CLIs under your
|
|
82
|
+
credentials, with local per-checkout state and a single
|
|
83
|
+
OS-level repository lock instead of any coordinator. The expected failure
|
|
84
|
+
modes are a `Ctrl-C`, a killed process, and a reboot, which is why side
|
|
85
|
+
effects are checkpointed before they are performed. What *is* remote and
|
|
86
|
+
concurrent is GitHub and the humans acting on it, which is why nothing
|
|
87
|
+
GitHub-side is believed without being read back. AutoForge never commits to
|
|
88
|
+
the default branch.
|
|
89
|
+
|
|
90
|
+
There is a second, explicit workflow for when there is no GitHub to
|
|
91
|
+
orchestrate: [Local mode](#local-mode-no-github) drives a feature Markdown
|
|
92
|
+
file against your working tree with the same controller and the same
|
|
93
|
+
verification discipline, and the controller makes zero `gh` invocations.
|
|
94
|
+
|
|
95
|
+
## Key properties
|
|
96
|
+
|
|
97
|
+
Each line is a summary; the linked document is the precise statement.
|
|
98
|
+
|
|
99
|
+
- **Read the security boundaries before a first run.** Agents run as you,
|
|
100
|
+
with network access and your model credentials, and are not sandboxed
|
|
101
|
+
by default, so a deliberate read of your credential files by absolute
|
|
102
|
+
path is outside the credential guarantee below. On a public repository
|
|
103
|
+
anyone who can comment on the issue or PR an agent reads can try to
|
|
104
|
+
steer it, and everything an agent reads goes to your model vendor. Run
|
|
105
|
+
AutoForge on issues whose authors you trust, as a dedicated user or in
|
|
106
|
+
a VM or container, or under `sandbox.mode: required`.
|
|
107
|
+
[Security boundaries](docs/security.md) lists what AutoForge protects
|
|
108
|
+
and what it does not, the GitHub token permissions it needs and the
|
|
109
|
+
recommended settings; [SECURITY.md](SECURITY.md) says how to report a
|
|
110
|
+
vulnerability.
|
|
111
|
+
- **Agent output is a claim; the controller decides.** State advances only
|
|
112
|
+
on a strictly validated `CONTROL_RESULT` block plus independent
|
|
113
|
+
verification, never on prose such as "done" or "LGTM". An invalid
|
|
114
|
+
transition fails explicitly, and when recovery cannot determine the safe
|
|
115
|
+
state the run enters `BLOCKED` rather than guess.
|
|
116
|
+
([CONTROL_RESULT protocol](docs/agent-guides/control-result-protocol.md),
|
|
117
|
+
[workflow](docs/agent-guides/workflow.md))
|
|
118
|
+
- **GitHub is read back, not believed.** Each phase re-reads what its agent
|
|
119
|
+
claims to have done, or what the controller did on its behalf: the
|
|
120
|
+
implementation commit is the worktree's own HEAD and descends from the
|
|
121
|
+
default branch, and the PR the controller opened for it is open, at that
|
|
122
|
+
HEAD, on the issue's branch; the review comment the controller rendered
|
|
123
|
+
from the reviewer's result is on that PR, exactly once, for the right
|
|
124
|
+
round and SHA; the fix commit is the fixer's own HEAD, descends from the
|
|
125
|
+
reviewed HEAD and is the PR's head once the controller has pushed it; the
|
|
126
|
+
follow-up issues the controller created or recorded a deferral in are the
|
|
127
|
+
one open issue per finding; the EPIC update and the next issue exist.
|
|
128
|
+
([GitHub safety](docs/agent-guides/github-safety.md))
|
|
129
|
+
- **Agents never merge.** Every agent prompt carries the rule "never merge a
|
|
130
|
+
pull request" (LOCAL prompts forbid `git merge` and have no PR to merge).
|
|
131
|
+
The merge is performed by the controller itself
|
|
132
|
+
(`gh pr merge --<method> --match-head-commit <reviewed HEAD>`), with no
|
|
133
|
+
agent invocation.
|
|
134
|
+
- **Merging is off by default and opt-in.** `MERGE` is reachable only when
|
|
135
|
+
both `safety.allow_merge: true` is set in config *and* `--allow-merge` is
|
|
136
|
+
passed on the CLI; otherwise the run stops at `READY_FOR_MERGE` and a
|
|
137
|
+
human merges. Before merging, the controller re-verifies the PR on GitHub
|
|
138
|
+
and fails closed: a conclusive negative is `BLOCKED`, inconclusive data
|
|
139
|
+
keeps the phase for a bounded number of `resume --allow-merge` re-checks
|
|
140
|
+
and then is `BLOCKED`, and nothing is merged in either case. By default a PR that
|
|
141
|
+
changes a protected path (`.github/workflows/`) is never merged
|
|
142
|
+
unattended, and a required check is trusted only if it ran the
|
|
143
|
+
base branch's job and step structure. `doctor` checks that the default
|
|
144
|
+
branch still requires the CI check; the merge gate itself does not yet
|
|
145
|
+
consult branch rules. The merge is counted only after GitHub reports
|
|
146
|
+
`MERGED` at the reviewed HEAD into the reviewed base.
|
|
147
|
+
([Merge safety](docs/agent-guides/github-safety.md#merge-safety))
|
|
148
|
+
- **Reviews are bound to a revision.** A clean review is bound to the PR it
|
|
149
|
+
was posted on (by repository and number), its HEAD SHA, its base branch
|
|
150
|
+
and its merge base. If the HEAD, the base branch or the merge base moves
|
|
151
|
+
after the review, the run goes back to `REVIEW` instead of merging, and a
|
|
152
|
+
different PR than the reviewed one is `BLOCKED`; a local review is bound
|
|
153
|
+
to a workspace fingerprint in the same way.
|
|
154
|
+
([Review binding](docs/agent-guides/workflow.md#bind-reviews-to-pr-head-sha-and-to-the-pr-identity))
|
|
155
|
+
- **State is durable and runs are resumable.** State is written atomically
|
|
156
|
+
and side effects are checkpointed before they are performed. `resume`
|
|
157
|
+
re-enters the interrupted phase and reconciles with GitHub first; a
|
|
158
|
+
corrupt state file fails loudly instead of being reset. One controller
|
|
159
|
+
runs per checkout under an OS file lock keyed by the git common dir
|
|
160
|
+
(linked worktrees share it; independent clones are not coordinated). Review rounds, stagnation and a
|
|
161
|
+
cumulative step budget bound every run, so it cannot loop forever.
|
|
162
|
+
([State and recovery](docs/agent-guides/state-and-recovery.md))
|
|
163
|
+
- **Agents are separated from your checkout and shell; sandboxing is
|
|
164
|
+
opt-in.** A remote agent runs in a per-issue `git worktree` the
|
|
165
|
+
controller creates, with an allow-listed environment rather than the
|
|
166
|
+
operator's whole shell, and the controller blocks if its own checkout's
|
|
167
|
+
HEAD or branch moved while the agent ran. Whatever an agent leaves running is killed when its
|
|
168
|
+
invocation ends, and what the kill could not remove is reported rather
|
|
169
|
+
than hidden; the orphans of a process that makes itself a subreaper, and
|
|
170
|
+
anything handed to a service manager (`systemd-run`, `at`), escape this
|
|
171
|
+
unseen
|
|
172
|
+
([ADR 0002](docs/adr/0002-executor-nothing-outlives-the-invocation.md),
|
|
173
|
+
[Security boundaries](docs/security.md#other-limits)).
|
|
174
|
+
By default the agent is not sandboxed: it runs as the operator, with
|
|
175
|
+
network access and the allow-listed provider credentials.
|
|
176
|
+
([Usage](docs/usage.md#how-agents-are-separated-from-your-checkout))
|
|
177
|
+
`sandbox.mode: required` (Linux, `bwrap`) runs every agent, LOCAL
|
|
178
|
+
validation command and pre-merge command inside an outer sandbox, or
|
|
179
|
+
refuses it: an empty root with only the system runtime, the workspace,
|
|
180
|
+
read-only git metadata, a private home and what the provider declares, so
|
|
181
|
+
controller state, other worktrees and your credential files are out of
|
|
182
|
+
reach. It still runs as your UID, and agents keep the host network. A
|
|
183
|
+
host that cannot enforce one is refused before the step, with nothing
|
|
184
|
+
saved, charged or launched; `preferred` falls back to logical isolation
|
|
185
|
+
only in LOCAL, visibly, and refuses like `required` in REMOTE; `doctor`
|
|
186
|
+
shows which this host gets
|
|
187
|
+
([ADR 0005](docs/adr/0005-outer-sandbox-and-host-resource-capability-model.md),
|
|
188
|
+
[Usage](docs/usage.md#outer-sandbox),
|
|
189
|
+
[Configuration](docs/configuration.md#outer-sandbox)).
|
|
190
|
+
- **Agents hold no GitHub credential.** The controller makes every GitHub
|
|
191
|
+
write itself; agents, validation commands and pre-merge commands get no
|
|
192
|
+
GitHub or git credential through anything AutoForge controls: no token
|
|
193
|
+
variable `gh` or git reads can be allow-listed (a token you forward under
|
|
194
|
+
another name is yours to keep out), `gh` finds no login, credential helpers,
|
|
195
|
+
askpass and the SSH agent and keys are switched off where repository
|
|
196
|
+
configuration cannot switch them back on, curl and wget read no
|
|
197
|
+
configured header, a launch's shells read none of your zsh startup
|
|
198
|
+
files, the provider CLIs load no MCP server, plugin or hook, and a
|
|
199
|
+
launch is refused (by `doctor` too) while a repository setting,
|
|
200
|
+
`~/.netrc`, a login shell's startup file or an organization connected
|
|
201
|
+
to OpenCode would still hand one over. The agent reads the GitHub data its
|
|
202
|
+
phase needs from files the controller wrote, redacted and bounded. A
|
|
203
|
+
deliberate same-user read of a credential file by absolute path is
|
|
204
|
+
outside this guarantee.
|
|
205
|
+
([GitHub safety](docs/agent-guides/github-safety.md#agents-hold-no-github-credential))
|
|
206
|
+
- **The controller's local run is GitHub-free by construction, not by
|
|
207
|
+
convention.** Local mode needs no GitHub: a local run never constructs the
|
|
208
|
+
GitHub client, so no authentication is needed and none is consulted. The
|
|
209
|
+
agent is outside that construction: it is asked not to touch GitHub and
|
|
210
|
+
gets no GitHub credential (as above), and only a moved git anchor (a
|
|
211
|
+
commit, reset, checkout or branch switch) is detected;
|
|
212
|
+
a `gh` write or a push from the agent is not
|
|
213
|
+
(see [Local mode](#local-mode-no-github)).
|
|
214
|
+
- **Logs and CLI output are redacted.** Tokens, API keys and authorization
|
|
215
|
+
headers are masked (a baseline, with no claim of completeness), and no
|
|
216
|
+
environment dump is ever written.
|
|
217
|
+
([Secrets and logging](docs/agent-guides/secrets-and-logging.md))
|
|
218
|
+
|
|
219
|
+
## Prerequisites
|
|
220
|
+
|
|
221
|
+
[Compatibility](https://github.com/iceboundrock/AutoForge/blob/main/docs/compatibility.md)
|
|
222
|
+
has the full matrix and the evidence for each entry.
|
|
223
|
+
|
|
224
|
+
- Linux on x86_64. macOS, Linux ARM64 and WSL2 are untested; Windows is
|
|
225
|
+
unsupported (AutoForge's lock needs POSIX `fcntl`)
|
|
226
|
+
- CPython 3.11 or 3.12, the versions CI tests; 3.13 and later are untested.
|
|
227
|
+
`uv` fetches one when the host has none (`--python 3.12` below)
|
|
228
|
+
- `uv` ([install](https://docs.astral.sh/uv/getting-started/installation/))
|
|
229
|
+
- `git`, and `gh` (GitHub CLI **2.48.0 or newer**, authenticated): the
|
|
230
|
+
client lists branch rules and a PR's changed files with
|
|
231
|
+
`gh api --paginate --slurp`, which older releases reject; `autoforge doctor`
|
|
232
|
+
refuses an older `gh` up front. `gh` is **not** needed for
|
|
233
|
+
[local mode](https://github.com/iceboundrock/AutoForge#local-mode-no-github)
|
|
234
|
+
- `claude` (Claude Code CLI) for `analyze_execute` / `fix` profiles
|
|
235
|
+
- `opencode` (OpenCode CLI) 2.0.0 or newer for the `review_*`,
|
|
236
|
+
`replan_reexecute` and `update_epic` profiles; 1.x is refused by `doctor`
|
|
237
|
+
(see [OpenCode profiles](https://github.com/iceboundrock/AutoForge/blob/main/docs/configuration.md#opencode-profiles))
|
|
238
|
+
- `pi` 1.0.0 or newer, only if a profile you route to uses `provider: pi`,
|
|
239
|
+
holding a DeepSeek API key or signed in with your ChatGPT subscription
|
|
240
|
+
(see the [Pi operator guide](https://github.com/iceboundrock/AutoForge/blob/main/docs/pi.md)). `doctor` checks
|
|
241
|
+
only the agent CLIs your configured profiles actually reach
|
|
242
|
+
- a state directory (`.autoforge/` by default; `--state-dir` or
|
|
243
|
+
`state_dir` in config) on a filesystem with hard links: run logs and
|
|
244
|
+
other controller files are published by `link(2)` so that a crash never
|
|
245
|
+
leaves one half-written, and there is no non-atomic fallback. vfat/exFAT
|
|
246
|
+
and some FUSE, SMB/CIFS and overlay mounts have no hard links; a run, and
|
|
247
|
+
`autoforge doctor`, refuse such a state directory and say why
|
|
248
|
+
|
|
249
|
+
Run `autoforge doctor` to check all of the above (read-only apart from
|
|
250
|
+
creating the state directory if it is missing and a probe file it removes),
|
|
251
|
+
or
|
|
252
|
+
`autoforge local doctor` for the local-mode subset (no `gh`, no GitHub
|
|
253
|
+
authentication, no `origin` remote).
|
|
254
|
+
|
|
255
|
+
CLI flag syntax in `autoforge.example.yaml` was checked against the locally
|
|
256
|
+
installed CLIs (Claude Code 2.1.263, OpenCode 2.0.23, gh 2.100.0); the
|
|
257
|
+
versions verified since are in [Compatibility](https://github.com/iceboundrock/AutoForge/blob/main/docs/compatibility.md#agent-clis).
|
|
258
|
+
|
|
259
|
+
## Installation
|
|
260
|
+
|
|
261
|
+
The distribution is **`autoforge-cli`**; the command it installs is
|
|
262
|
+
`autoforge`. `autoforge` on PyPI is an unrelated project: never
|
|
263
|
+
`pip install autoforge`.
|
|
264
|
+
|
|
265
|
+
A git commit, or a wheel built from one, installs from any commit at or
|
|
266
|
+
after the one that introduced `autoforge-cli` (#256; an earlier commit
|
|
267
|
+
installs a package without its prompt templates); the PyPI method needs a
|
|
268
|
+
published version.
|
|
269
|
+
|
|
270
|
+
**From a git commit.** Install the command into its own environment with
|
|
271
|
+
`uv tool`. Pin a full commit SHA, or the tag of a published version
|
|
272
|
+
(`v<version>`):
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
uv tool install --python 3.12 'git+https://github.com/iceboundrock/AutoForge@<commit>'
|
|
276
|
+
autoforge --version
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`uv tool install --reinstall` with another commit replaces it, and
|
|
280
|
+
`uv tool uninstall autoforge-cli` removes it. Add the YAML extra with
|
|
281
|
+
`'autoforge-cli[yaml] @ git+https://github.com/iceboundrock/AutoForge@<commit>'`.
|
|
282
|
+
|
|
283
|
+
**From a built wheel.** From a checkout of the commit you want:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
uv build # dist/autoforge_cli-<version>.tar.gz and -py3-none-any.whl
|
|
287
|
+
uv tool install --python 3.12 dist/autoforge_cli-<version>-py3-none-any.whl
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**From PyPI, once a version is published.** Until the first upload
|
|
291
|
+
([#295](https://github.com/iceboundrock/AutoForge/issues/295)),
|
|
292
|
+
`autoforge-cli` is not on PyPI and the command below fails: uv reports that
|
|
293
|
+
`autoforge-cli` was not found in the package registry. The
|
|
294
|
+
[releases page](https://github.com/iceboundrock/AutoForge/releases) lists
|
|
295
|
+
each version that has been published, with the SHA-256 digests of its
|
|
296
|
+
files; if it lists none, install from a git commit or a built wheel
|
|
297
|
+
instead. Install a published version only after checking that its PyPI
|
|
298
|
+
project page links back to this repository:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
uv tool install --python 3.12 --prerelease allow autoforge-cli
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`--prerelease allow` is needed while every published version is a
|
|
305
|
+
prerelease (`0.x`, [Releasing](https://github.com/iceboundrock/AutoForge/blob/main/docs/releasing.md#version-scheme)).
|
|
306
|
+
[Releasing](https://github.com/iceboundrock/AutoForge/blob/main/docs/releasing.md)
|
|
307
|
+
describes how a version is built and published.
|
|
308
|
+
|
|
309
|
+
Whichever way it was installed, run `autoforge` from a checkout of the
|
|
310
|
+
repository whose issues it drives (or, in LOCAL mode, whose feature file it
|
|
311
|
+
implements); `autoforge doctor` checks the rest.
|
|
312
|
+
|
|
313
|
+
**For development** on AutoForge itself, from a clone of this repository:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
uv sync # create .venv, install autoforge-cli (editable) + dev tools
|
|
317
|
+
uv sync --extra yaml # optional: full YAML config support (PyYAML)
|
|
318
|
+
uv run autoforge --help
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
`uv run autoforge` is the same command, run from that clone's `.venv`.
|
|
322
|
+
[Development](https://github.com/iceboundrock/AutoForge/blob/main/docs/development.md) has the checks CI runs.
|
|
323
|
+
|
|
324
|
+
To configure profiles, bounds or the merge gate, copy
|
|
325
|
+
`autoforge.example.yaml` to `autoforge.yaml` and pass it with `--config`
|
|
326
|
+
before the subcommand; see [Configuration](https://github.com/iceboundrock/AutoForge/blob/main/docs/configuration.md).
|
|
327
|
+
|
|
328
|
+
## Quick start
|
|
329
|
+
|
|
330
|
+
Run these from a checkout of the repository the issues belong to. URLs must
|
|
331
|
+
be HTTPS GitHub issue URLs, and the EPIC and the issue must be in that same
|
|
332
|
+
repository (cross-repo runs are rejected).
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# 1. check the environment (writes nothing but a state-dir probe)
|
|
336
|
+
autoforge doctor
|
|
337
|
+
|
|
338
|
+
# 2. preview without touching anything (no subprocess, no gh call, no state file)
|
|
339
|
+
autoforge run --epic https://github.com/owner/repo/issues/1 \
|
|
340
|
+
--issue https://github.com/owner/repo/issues/2 --dry-run
|
|
341
|
+
|
|
342
|
+
# 3. create a run and drive it until READY_FOR_MERGE / BLOCKED / FAILED
|
|
343
|
+
autoforge run --epic https://github.com/owner/repo/issues/1 \
|
|
344
|
+
--issue https://github.com/owner/repo/issues/2
|
|
345
|
+
|
|
346
|
+
# 4. inspect it, and continue after an interruption
|
|
347
|
+
autoforge status
|
|
348
|
+
autoforge resume
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
With the merge gate closed (the default) the run stops at
|
|
352
|
+
`READY_FOR_MERGE` with a banner naming the issue, PR, review round and
|
|
353
|
+
reviewed HEAD, and a human merges the PR. Only with `safety.allow_merge:
|
|
354
|
+
true` in config does `autoforge resume --allow-merge` let the
|
|
355
|
+
controller verify the PR on GitHub and merge it itself.
|
|
356
|
+
|
|
357
|
+
A run in `BLOCKED` stays there until you fix the cause and run
|
|
358
|
+
`autoforge unblock --reason "..."`, which re-inspects GitHub and either
|
|
359
|
+
re-enters the one phase that inspection supports or refuses. When a fixer
|
|
360
|
+
asked the controller to post an acceptance comment on the issue, the run
|
|
361
|
+
waits for you to approve or decline that exact comment
|
|
362
|
+
(`unblock --approve-action` / `--decline-action`). When it asked for a
|
|
363
|
+
comment on another issue (one the run's issue references, or the EPIC),
|
|
364
|
+
you post it yourself, bind an existing comment or withdraw it
|
|
365
|
+
(`unblock --bind-evidence` / `--decline-action`); the controller never posts
|
|
366
|
+
there, and verifies the comment on GitHub. Every command,
|
|
367
|
+
where a run stops, and how to recover are in
|
|
368
|
+
[Running the remote workflow](docs/usage.md).
|
|
369
|
+
|
|
370
|
+
To work through an EPIC's issues several at a time,
|
|
371
|
+
`autoforge epic run https://github.com/owner/repo/issues/1` runs up to
|
|
372
|
+
`scheduler.max_parallel` (1-4) of them at once, admitted in dependency order
|
|
373
|
+
from GitHub's native sub-issues and "blocked by" links, each in its own
|
|
374
|
+
worker, namespace and worktree. Every worker stops at its settlement
|
|
375
|
+
boundary (`READY_FOR_MERGE`, `BLOCKED`, `DONE`, `FAILED`), so nothing is
|
|
376
|
+
merged without a human. `epic status` shows each child's category and next
|
|
377
|
+
step without taking a lock, `epic stop` drains it, and `epic resume`
|
|
378
|
+
recovers after a crash, a kill or a reboot
|
|
379
|
+
([Running an EPIC in parallel](docs/usage.md#running-an-epic-in-parallel)).
|
|
380
|
+
It is experimental: it is verified offline only and has not yet driven a
|
|
381
|
+
real EPIC ([Current maturity](#current-maturity)).
|
|
382
|
+
|
|
383
|
+
## Local mode (no GitHub)
|
|
384
|
+
|
|
385
|
+
Sometimes there is no GitHub to orchestrate: a coding interview, a scratch
|
|
386
|
+
repository, an air-gapped machine, or simply a change you want driven by the
|
|
387
|
+
same review loop without opening an Issue. `autoforge local` is a separate,
|
|
388
|
+
explicit workflow for exactly that: the same controller, the same
|
|
389
|
+
"never trust the agent" discipline, none of the GitHub lifecycle.
|
|
390
|
+
|
|
391
|
+
```text
|
|
392
|
+
features/<slug>.md → INITIALIZING → ANALYZE_EXECUTE → REVIEW
|
|
393
|
+
→ clean ─────────────▶ DONE
|
|
394
|
+
→ findings ──────────▶ FIX → REVIEW
|
|
395
|
+
→ findings after the fix budget ─▶ BLOCKED
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The *controller* never touches GitHub in a local run: no `gh` invocation,
|
|
399
|
+
no Issue, no PR, no comment, no push, no branch, no merge, no EPIC update, no
|
|
400
|
+
follow-up issue, and no replan. The `GitHubClient` is not even constructed.
|
|
401
|
+
Nothing is faked either: there are no placeholder PR URLs in local state or
|
|
402
|
+
local prompts.
|
|
403
|
+
|
|
404
|
+
That is a property of the controller, not of the agents it launches. An agent
|
|
405
|
+
is a same-UID subprocess with `gh` on `PATH` and network access; it is
|
|
406
|
+
instructed not to use them, and it gets no GitHub or git credential through
|
|
407
|
+
anything AutoForge controls, so a `gh` write or a push fails unless the agent
|
|
408
|
+
finds a credential on its own (by reading the operator's files by absolute
|
|
409
|
+
path, say). Beyond that, the controller can neither prevent nor detect a
|
|
410
|
+
`gh` write, a `git push` or a network request made by the agent. What the
|
|
411
|
+
controller *does* detect is a moved git anchor: HEAD and the checked-out branch
|
|
412
|
+
are compared with the values the run was pinned to before and after every
|
|
413
|
+
phase, and before every correction relaunch within one, so a commit, reset,
|
|
414
|
+
checkout or branch switch blocks the run before another agent starts. It detects
|
|
415
|
+
nothing else. Real containment is a sandbox, which LOCAL v1 does not provide
|
|
416
|
+
under the default `sandbox.mode: disabled`
|
|
417
|
+
([ADR 0001](docs/adr/0001-local-mode-workspace-identity-and-filesystem-boundary.md)
|
|
418
|
+
§2.2 and §8.1; isolation is tracked in #10). With `sandbox.mode: required`
|
|
419
|
+
every LOCAL agent and validation command runs inside ADR 0005's outer
|
|
420
|
+
sandbox, where the git directory is read-only, so a commit, stash or branch
|
|
421
|
+
switch fails outright; the agent still runs as your UID on the host
|
|
422
|
+
network. `preferred` does the same where the host can enforce and, where it
|
|
423
|
+
cannot, says at every launch that it runs with logical isolation only
|
|
424
|
+
([Local mode](docs/local-mode.md#what-the-controller-does-and-does-not-do)).
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
autoforge local doctor # config, git, agent CLIs; never gh
|
|
428
|
+
autoforge local init add-transaction-filter
|
|
429
|
+
# a human (with or without an AI) refines features/add-transaction-filter.md
|
|
430
|
+
autoforge local run features/add-transaction-filter.md --dry-run
|
|
431
|
+
autoforge local run features/add-transaction-filter.md
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
The specification is frozen for the whole run (its SHA-256 is re-checked
|
|
435
|
+
before and after every agent phase), every review is bound to a fingerprint
|
|
436
|
+
of the working tree, and the controller never commits, stages, pushes,
|
|
437
|
+
stashes, resets or switches branches in a local run. The [Local mode guide](docs/local-mode.md) covers the
|
|
438
|
+
workspace fingerprint, dirty working trees, the review/fix bound, validation
|
|
439
|
+
commands, and resume and recovery.
|
|
440
|
+
|
|
441
|
+
## Documentation
|
|
442
|
+
|
|
443
|
+
The [documentation index](docs/README.md) lists everything by intent. The
|
|
444
|
+
most common entry points:
|
|
445
|
+
|
|
446
|
+
| I want to… | Read |
|
|
447
|
+
|---|---|
|
|
448
|
+
| know which OS, Python, git, `gh`, agent CLI and sandbox host it runs on | [Compatibility](docs/compatibility.md) |
|
|
449
|
+
| run the remote workflow, merge, unblock, troubleshoot or recover a run | [Running the remote workflow](docs/usage.md), [troubleshooting and recovery](docs/usage.md#troubleshooting-and-recovery) |
|
|
450
|
+
| work without GitHub | [Local mode](docs/local-mode.md) |
|
|
451
|
+
| run phases through Pi on a DeepSeek API key or a ChatGPT subscription | [Pi operator guide](docs/pi.md) |
|
|
452
|
+
| configure profiles, bounds and the merge gate | [Configuration](docs/configuration.md), [`autoforge.example.yaml`](autoforge.example.yaml) |
|
|
453
|
+
| know what AutoForge protects, which GitHub token it needs, or report a vulnerability | [Security boundaries](docs/security.md), [SECURITY.md](SECURITY.md) |
|
|
454
|
+
| understand the phases and legal transitions | [Workflow](docs/agent-guides/workflow.md) |
|
|
455
|
+
| know what is verified on GitHub, and what gates a merge | [GitHub safety](docs/agent-guides/github-safety.md) |
|
|
456
|
+
| know how state, locking and crash recovery work | [State and recovery](docs/agent-guides/state-and-recovery.md) |
|
|
457
|
+
| see how the code is divided | [Architecture](docs/agent-guides/architecture.md), [module map](src/autoforge/AGENTS.md) |
|
|
458
|
+
| contribute, run the checks, write tests | [Development](docs/development.md), [Testing](docs/agent-guides/testing.md) |
|
|
459
|
+
| cut or publish a release | [Releasing](docs/releasing.md) |
|
|
460
|
+
| read the design records | [ADR 0001](docs/adr/0001-local-mode-workspace-identity-and-filesystem-boundary.md), [ADR 0002](docs/adr/0002-executor-nothing-outlives-the-invocation.md), [ADR 0003](docs/adr/0003-pi-agent-provider.md) |
|
|
461
|
+
|
|
462
|
+
Coding agents working on this repository start at [AGENTS.md](AGENTS.md).
|
|
463
|
+
|
|
464
|
+
## Current maturity
|
|
465
|
+
|
|
466
|
+
**Supported now (Phase 2):** GitHub issue → Claude Code implementation → the
|
|
467
|
+
controller's push and PR, read back via `gh` → OpenCode review with
|
|
468
|
+
round-based model routing → Claude Code remediation of finding IDs →
|
|
469
|
+
repeated review with SHA binding → `READY_FOR_MERGE`; the bounded REVIEW/FIX
|
|
470
|
+
loop with stagnation detection and the `REPLAN_REEXECUTE` transaction;
|
|
471
|
+
journal-first recovery of an interrupted push or PR creation;
|
|
472
|
+
bounded correction retry for malformed results; `doctor`; redacted
|
|
473
|
+
per-invocation logs; LOCAL mode against a feature Markdown file.
|
|
474
|
+
|
|
475
|
+
**Opt-in, and only on a host that can enforce it:** the outer sandbox on
|
|
476
|
+
Linux (`sandbox.mode`, off by default), with its capability probe,
|
|
477
|
+
pre-launch gate and `doctor` rows. It needs Linux 6.12+ with Landlock ABI 6,
|
|
478
|
+
unprivileged user, PID and IPC namespaces (some distributions restrict
|
|
479
|
+
them), and a bubblewrap that can mount an overlay (0.11 or later)
|
|
480
|
+
([ADR 0005](docs/adr/0005-outer-sandbox-and-host-resource-capability-model.md)).
|
|
481
|
+
`sandbox.mode: disabled` and a `preferred` fallback are not sandboxed. Its
|
|
482
|
+
boundary is tested across every provider path on a capable host
|
|
483
|
+
(`make test-sandbox`). Hosted CI measures its runner on every run (its
|
|
484
|
+
`bwrap`, user-namespace policy and Landlock ABI, in the job summary) and
|
|
485
|
+
requires the real-backend tests wherever the runner can enforce; where it
|
|
486
|
+
cannot, they skip with the probe's reason. It is experimental until a
|
|
487
|
+
`make test-sandbox` run on a capable host is recorded at the release
|
|
488
|
+
candidate.
|
|
489
|
+
|
|
490
|
+
**Experimental: implemented and verified, but exercised only against the
|
|
491
|
+
in-memory fake:** the controller-owned `MERGE` step behind the merge safety
|
|
492
|
+
gate (off by default), including its pre-merge verification, and
|
|
493
|
+
`UPDATE_EPIC`. Every claim these phases depend on is re-read from GitHub
|
|
494
|
+
before state advances, but no automated test has ever merged a real PR or
|
|
495
|
+
edited a real EPIC, so treat an opened gate as unproven against real
|
|
496
|
+
services. The supported path keeps the gate closed: a human reviews and
|
|
497
|
+
merges the PR the run leaves at `READY_FOR_MERGE`.
|
|
498
|
+
|
|
499
|
+
**Experimental: implemented and verified offline:** the parallel EPIC
|
|
500
|
+
scheduler (`autoforge epic run|resume|status|stop|archive`, ADR 0008). Its
|
|
501
|
+
crash windows are tested by killing real scheduler and worker processes at
|
|
502
|
+
each one, but against the in-memory GitHub and scripted agents only, and it
|
|
503
|
+
has not yet driven a real EPIC: run it on an EPIC you watch, with
|
|
504
|
+
`epic status` open.
|
|
505
|
+
|
|
506
|
+
**Experimental:** acceptance actions on other issues, which the operator
|
|
507
|
+
posts or binds (`unblock --bind-evidence`, #243). They are tested offline
|
|
508
|
+
and have been used once for real, in a run on this repository. They stay
|
|
509
|
+
experimental until they are used on a repository other than AutoForge.
|
|
510
|
+
|
|
511
|
+
**Experimental and opt-in:** Pi as a provider (`provider: pi`, the
|
|
512
|
+
[Pi operator guide](docs/pi.md)). No built-in profile uses it, and its one
|
|
513
|
+
recorded live run is a LOCAL review on DeepSeek (#135).
|
|
514
|
+
|
|
515
|
+
The Public Alpha release claims these capabilities at exactly these levels
|
|
516
|
+
([#255](https://github.com/iceboundrock/AutoForge/issues/255), conditions
|
|
517
|
+
C1–C7). An earlier registration prerelease of the package (#295) is not the
|
|
518
|
+
Public Alpha and claims no more than this.
|
|
519
|
+
|
|
520
|
+
**Explicitly not yet:** unattended production operation; the controller
|
|
521
|
+
feeding CI results into the review prompt (the reviewer is asked to inspect
|
|
522
|
+
`gh pr checks` itself, and the merge gate reads the checks); the merge gate
|
|
523
|
+
consulting branch rules (`doctor` reads them, the gate does not); dequeuing a
|
|
524
|
+
PR from a merge queue (the controller refuses to merge into queue-protected
|
|
525
|
+
branches instead).
|