forgeo-cli 0.4.0__tar.gz → 0.6.0__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.
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/.github/workflows/ci.yml +60 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/.gitignore +1 -0
- forgeo_cli-0.6.0/CHANGELOG.md +293 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/CONTRIBUTING.md +10 -3
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/PKG-INFO +32 -11
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/README.md +30 -9
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/agent-contract.md +30 -2
- forgeo_cli-0.6.0/docs/backlog.md +350 -0
- forgeo_cli-0.6.0/docs/cli-reference.md +346 -0
- forgeo_cli-0.6.0/docs/configuration.md +356 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/getting-started.md +53 -21
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/index.md +35 -13
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/web-console-api.md +218 -45
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/install.sh +29 -3
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/pyproject.toml +1 -1
- forgeo_cli-0.6.0/scripts/__init__.py +0 -0
- forgeo_cli-0.6.0/scripts/render_homebrew_formula.py +119 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/__init__.py +1 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/agent.py +25 -1
- forgeo_cli-0.6.0/src/forgeo/backlog.py +630 -0
- forgeo_cli-0.6.0/src/forgeo/backlog_http.py +149 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/central.py +586 -69
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/cli.py +378 -50
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/config.py +18 -3
- forgeo_cli-0.6.0/src/forgeo/daemon.py +432 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/daemon_control.py +49 -20
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/forgeo.py +238 -42
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/git.py +14 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/instances.py +2 -1
- forgeo_cli-0.6.0/src/forgeo/models.py +526 -0
- forgeo_cli-0.6.0/src/forgeo/notify.py +131 -0
- forgeo_cli-0.6.0/src/forgeo/oauth.py +151 -0
- forgeo_cli-0.6.0/src/forgeo/paths.py +80 -0
- forgeo_cli-0.6.0/src/forgeo/runs.py +126 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/setup.py +23 -3
- forgeo_cli-0.6.0/src/forgeo/update.py +167 -0
- forgeo_cli-0.6.0/src/forgeo/validate.py +249 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web/central/central.css +329 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web/central/central.js +449 -59
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web/central/instance.html +61 -13
- forgeo_cli-0.6.0/src/forgeo/web/central/login.html +76 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web/style.css +7 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web_common.py +2 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/conftest.py +83 -2
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_agent.py +27 -0
- forgeo_cli-0.6.0/tests/test_backlog.py +899 -0
- forgeo_cli-0.6.0/tests/test_backlog_http.py +309 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_cli.py +389 -15
- forgeo_cli-0.6.0/tests/test_daemon.py +383 -0
- forgeo_cli-0.6.0/tests/test_factory.py +947 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_git.py +20 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_install.py +3 -2
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_models.py +191 -0
- forgeo_cli-0.6.0/tests/test_oauth.py +186 -0
- forgeo_cli-0.6.0/tests/test_paths.py +98 -0
- forgeo_cli-0.6.0/tests/test_remote_backlog_cycle.py +89 -0
- forgeo_cli-0.6.0/tests/test_render_homebrew.py +83 -0
- forgeo_cli-0.6.0/tests/test_runs.py +516 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_setup.py +16 -1
- forgeo_cli-0.6.0/tests/test_update.py +200 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_web.py +623 -9
- forgeo_cli-0.6.0/tests/test_web_lock.py +521 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/www/index.html +27 -3
- forgeo_cli-0.4.0/CHANGELOG.md +0 -150
- forgeo_cli-0.4.0/docs/backlog.md +0 -135
- forgeo_cli-0.4.0/docs/cli-reference.md +0 -211
- forgeo_cli-0.4.0/docs/configuration.md +0 -195
- forgeo_cli-0.4.0/src/forgeo/backlog.py +0 -296
- forgeo_cli-0.4.0/src/forgeo/daemon.py +0 -212
- forgeo_cli-0.4.0/src/forgeo/models.py +0 -269
- forgeo_cli-0.4.0/src/forgeo/notify.py +0 -77
- forgeo_cli-0.4.0/src/forgeo/runs.py +0 -73
- forgeo_cli-0.4.0/tests/test_backlog.py +0 -373
- forgeo_cli-0.4.0/tests/test_daemon.py +0 -162
- forgeo_cli-0.4.0/tests/test_factory.py +0 -427
- forgeo_cli-0.4.0/tests/test_runs.py +0 -240
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/LICENSE +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/config/nginx-forgeo.conf +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/img/console.png +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/img/logo.png +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/docs/img/title.svg +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/forgeo.spec +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/mkdocs.yml +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/__main__.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/io.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/src/forgeo/web/central/index.html +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_instances.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_io.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/tests/test_web_common.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.6.0}/www/404.html +0 -0
|
@@ -35,7 +35,10 @@ jobs:
|
|
|
35
35
|
fail-fast: false
|
|
36
36
|
matrix:
|
|
37
37
|
include:
|
|
38
|
-
|
|
38
|
+
# Linux is built on ubuntu-22.04 (glibc 2.35) so the binary also
|
|
39
|
+
# runs on older distros (Homebrew-on-Linux, Ubuntu 22.04+): a build
|
|
40
|
+
# on ubuntu-latest (24.04) would require glibc >= 2.38.
|
|
41
|
+
- os: ubuntu-22.04
|
|
39
42
|
asset: forgeo-linux-amd64
|
|
40
43
|
binary: dist/forgeo
|
|
41
44
|
- os: macos-15-intel
|
|
@@ -90,6 +93,24 @@ jobs:
|
|
|
90
93
|
with:
|
|
91
94
|
path: binaries
|
|
92
95
|
merge-multiple: true
|
|
96
|
+
- name: Extract release notes from CHANGELOG.md
|
|
97
|
+
id: notes
|
|
98
|
+
run: |
|
|
99
|
+
python - "${{ github.ref_name }}" <<'EOF'
|
|
100
|
+
import re
|
|
101
|
+
import sys
|
|
102
|
+
import pathlib
|
|
103
|
+
|
|
104
|
+
version = sys.argv[1].removeprefix("v")
|
|
105
|
+
text = pathlib.Path("CHANGELOG.md").read_text(encoding="utf-8")
|
|
106
|
+
pattern = re.compile(
|
|
107
|
+
rf"^## \[{re.escape(version)}\] .*?\n(.*?)(?=^## \[|\Z)",
|
|
108
|
+
re.MULTILINE | re.DOTALL,
|
|
109
|
+
)
|
|
110
|
+
match = pattern.search(text)
|
|
111
|
+
notes = match.group(1).strip() if match else ""
|
|
112
|
+
pathlib.Path("release-body.md").write_text(notes, encoding="utf-8")
|
|
113
|
+
EOF
|
|
93
114
|
- name: Publish GitHub Release
|
|
94
115
|
uses: softprops/action-gh-release@v2
|
|
95
116
|
with:
|
|
@@ -97,6 +118,44 @@ jobs:
|
|
|
97
118
|
dist/*.whl
|
|
98
119
|
dist/*.tar.gz
|
|
99
120
|
binaries/*
|
|
121
|
+
body_path: release-body.md
|
|
122
|
+
|
|
123
|
+
publish-homebrew:
|
|
124
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
125
|
+
needs: build-binaries
|
|
126
|
+
runs-on: ubuntu-latest
|
|
127
|
+
steps:
|
|
128
|
+
- uses: actions/checkout@v4
|
|
129
|
+
- uses: actions/setup-python@v5
|
|
130
|
+
with:
|
|
131
|
+
python-version: "3.11"
|
|
132
|
+
- name: Download binary artifacts
|
|
133
|
+
uses: actions/download-artifact@v4
|
|
134
|
+
with:
|
|
135
|
+
path: binaries
|
|
136
|
+
merge-multiple: true
|
|
137
|
+
- name: Render the Homebrew formula
|
|
138
|
+
run: python scripts/render_homebrew_formula.py "${{ github.ref_name }}" binaries > /tmp/forgeo.rb
|
|
139
|
+
- name: Publish the formula to the homebrew-forgeo tap
|
|
140
|
+
env:
|
|
141
|
+
TAP_REPO_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
142
|
+
run: |
|
|
143
|
+
set -eu
|
|
144
|
+
if [ -z "$TAP_REPO_TOKEN" ]; then
|
|
145
|
+
echo "::error::HOMEBREW_TAP_TOKEN secret is not set. Create a PAT with write access to lucaGazzola/homebrew-forgeo and store it as HOMEBREW_TAP_TOKEN; without it the Homebrew tap is not updated for this release."
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
git clone "https://x-access-token:${TAP_REPO_TOKEN}@github.com/lucaGazzola/homebrew-forgeo.git" tap
|
|
149
|
+
cp /tmp/forgeo.rb tap/Formula/forgeo.rb
|
|
150
|
+
git -C tap config user.name "Forgeo release bot"
|
|
151
|
+
git -C tap config user.email "forgeo-releases@users.noreply.github.com"
|
|
152
|
+
if git -C tap diff --quiet; then
|
|
153
|
+
echo "Formula unchanged; nothing to push."
|
|
154
|
+
else
|
|
155
|
+
git -C tap add Formula/forgeo.rb
|
|
156
|
+
git -C tap commit -m "forgeo ${{ github.ref_name }}"
|
|
157
|
+
git -C tap push origin main
|
|
158
|
+
fi
|
|
100
159
|
|
|
101
160
|
publish-pypi:
|
|
102
161
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.6.0] - 2026-08-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- The backlog can now live in another application instead of a file: set
|
|
15
|
+
`backlog:` to an `http(s)` URL and Forgeo reads the whole document with
|
|
16
|
+
`GET` on every read and writes it back with `POST` on every change, using
|
|
17
|
+
the same JSON shape as `backlog.json`. The endpoint replaces its task list
|
|
18
|
+
with the body it receives. A request that fails (network error, 5xx,
|
|
19
|
+
malformed body) fails the cycle and is retried on the next interval — it is
|
|
20
|
+
never read as an empty backlog, which would start a refactoring pass and let
|
|
21
|
+
the next `POST` overwrite the remote task list with nothing.
|
|
22
|
+
|
|
23
|
+
- `backlog_auth`: OAuth2 client-credentials access for a backlog URL behind an
|
|
24
|
+
identity provider such as Keycloak. Forgeo obtains an access token for a
|
|
25
|
+
confidential client (a service account, not a human login) and sends it as a
|
|
26
|
+
bearer on every backlog request; tokens are cached in memory, renewed before
|
|
27
|
+
they expire, and refreshed once with a retry when the endpoint answers 401 or
|
|
28
|
+
403. The client secret is never a config value: `client_secret_env` names the
|
|
29
|
+
environment variable holding it, so it stays out of `forgeo.yaml`.
|
|
30
|
+
|
|
31
|
+
- `state_dir`: where Forgeo's own runtime files go (`backlog.lock`,
|
|
32
|
+
`backlog.run`, `backlog.state.json`, `backlog.update.json`, `runs.jsonl`).
|
|
33
|
+
It only matters with a backlog URL, where there is no backlog file for them
|
|
34
|
+
to sit beside; it then defaults to the directory holding `forgeo.yaml`. With
|
|
35
|
+
a backlog file those paths are unchanged.
|
|
36
|
+
|
|
37
|
+
- `forgeo validate` now checks a backlog URL by fetching it once (a plain
|
|
38
|
+
`GET`, with `backlog_auth` credentials when configured), so an unreachable
|
|
39
|
+
endpoint or a rejected token is reported by the dry run instead of by the
|
|
40
|
+
first cycle. A file backlog is still read from disk, and nothing is written
|
|
41
|
+
either way.
|
|
42
|
+
|
|
43
|
+
## [0.5.0] - 2026-08-14
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- `forgeo validate` (and the pre-flight check before a detached
|
|
48
|
+
`forgeo start`) distinguishes a repository with no commits yet: a clean
|
|
49
|
+
tree is now a warning — the first cycle creates the initial commit — while
|
|
50
|
+
a non-clean tree is a problem that names the fix
|
|
51
|
+
(`git add -A && git commit -m "Initial commit"`), since every file is
|
|
52
|
+
untracked and every cycle would otherwise refuse as dirty. Previously
|
|
53
|
+
"no commits" was always a hard problem with a misleading message.
|
|
54
|
+
|
|
55
|
+
- `forgeo start` now starts the daemon **detached in the background and
|
|
56
|
+
exits**, like `forgeo restart` and the web console's start button already
|
|
57
|
+
did; the daemon is managed with `forgeo stop`/`forgeo restart`/`forgeo
|
|
58
|
+
status`. `forgeo start -f` (`--foreground`) keeps the historical
|
|
59
|
+
foreground behavior. A detached start refuses while the per-forgeo lock is
|
|
60
|
+
held and runs the same read-only checks as `forgeo validate` first, so a
|
|
61
|
+
broken config fails fast instead of leaving a silently dead daemon.
|
|
62
|
+
`--interval-minutes` is forwarded to the detached daemon.
|
|
63
|
+
|
|
64
|
+
- The daemon reloads `forgeo.yaml` on the next cycle boundary when the file
|
|
65
|
+
changes (or on `SIGHUP`): a valid change is revalidated, logged, and used
|
|
66
|
+
from the next cycle; an invalid change is logged and the last valid config
|
|
67
|
+
stays in use. The web console's config save reflects this
|
|
68
|
+
(`restart_required: false`). Path changes (`repo`, `backlog`,
|
|
69
|
+
`blocker_file`, `log_file`) stay pinned to the daemon's startup values and
|
|
70
|
+
still need `forgeo restart`, so the daemon's lock files are never detached
|
|
71
|
+
from the config.
|
|
72
|
+
|
|
73
|
+
- Optional bearer-token auth for the central web dashboard (`forgeo web`):
|
|
74
|
+
`forgeo web --token` (or a `token` key in `~/.config/forgeo/web.toml`)
|
|
75
|
+
requires `Authorization: Bearer <token>` on every `/api/*` route and
|
|
76
|
+
answers `401` otherwise. `forgeo web --token` with no value generates a
|
|
77
|
+
token, prints it once on startup, and saves it (mode `0600`); a generated
|
|
78
|
+
token is only ever printed once. Static assets and the new token prompt
|
|
79
|
+
page (`/central/login.html`) stay reachable without a token, and a
|
|
80
|
+
`?token=...` URL signs the browser in automatically. With no flag and no
|
|
81
|
+
token file the dashboard keeps its historical open-by-default behavior.
|
|
82
|
+
|
|
83
|
+
- `forgeo validate` — a read-only dry run that checks whether a forgeo is
|
|
84
|
+
ready to run before starting it: the config schema, the repository (exists,
|
|
85
|
+
is a git repo, `git` on PATH), the branch and remote resolution, the
|
|
86
|
+
backlog parsing, a non-blank agent command, and the run lock state. It
|
|
87
|
+
reports every problem at once, never invokes the agent, and makes no writes
|
|
88
|
+
(no lock, no backlog changes). Exit code `0` when healthy, `1` with a
|
|
89
|
+
summary of problems otherwise. Supports `--config` and `--name`.
|
|
90
|
+
|
|
91
|
+
- `run_history_keep` config key: `runs.jsonl` is trimmed to that many records
|
|
92
|
+
on append (default `2000`), so a busy Forgeo's run history never grows
|
|
93
|
+
forever. Trimming is atomic (temp file + rename) and a failed trim is
|
|
94
|
+
logged and skipped, never fatal to the cycle; `run_history_keep: 0`
|
|
95
|
+
disables retention entirely (the previous grow-forever behavior).
|
|
96
|
+
|
|
97
|
+
- Persisted agent output per run: each `RunRecord` now stores a bounded tail
|
|
98
|
+
of the agent's stdout/stderr (last `run_output_lines` lines, default `200`),
|
|
99
|
+
so failed and blocked runs keep the full tail of what the agent said. The
|
|
100
|
+
web console's **History** tab shows it in a read-only, monospace,
|
|
101
|
+
collapsible view; `run_output_lines: 0` disables persistence, and records
|
|
102
|
+
written before the field existed render as empty.
|
|
103
|
+
|
|
104
|
+
- Backlog snapshots: before every agent run (and on daemon startup) Forgeo
|
|
105
|
+
copies the backlog to a rotating snapshot (`backlog.json.bak`,
|
|
106
|
+
`backlog.json.bak.1`, ... keeping the last 2 by default), and a read that
|
|
107
|
+
finds the backlog corrupt restores the newest valid snapshot in place —
|
|
108
|
+
with the corrupt file still preserved — instead of falling back to an
|
|
109
|
+
empty store. A missing backlog is a no-op.
|
|
110
|
+
|
|
111
|
+
- Task dependencies are now enforced when picking the next task: Forgeo picks
|
|
112
|
+
the oldest `OPEN` task whose `dependencies` are all `COMPLETED` instead of
|
|
113
|
+
the plain oldest `OPEN` task, so a task never runs before the work it
|
|
114
|
+
depends on. Unsatisfied dependencies (including ids that don't exist in the
|
|
115
|
+
backlog) are surfaced on `forgeo status` (`waiting on:` line) and in the web
|
|
116
|
+
console's task detail modal (*Waiting on dependencies* banner); the
|
|
117
|
+
`GET /api/instances/<name>/tasks*` responses annotate each task with an
|
|
118
|
+
`unsatisfied_dependencies` field.
|
|
119
|
+
|
|
120
|
+
- Homebrew install support: `brew install lucaGazzola/forgeo/forgeo`
|
|
121
|
+
installs the prebuilt binary on macOS (arm64/Intel) and Linux (Intel). The
|
|
122
|
+
`publish-homebrew` CI job re-renders the tap formula (sha256 + version)
|
|
123
|
+
from `scripts/render_homebrew_formula.py` on every release; it needs the
|
|
124
|
+
`HOMEBREW_TAP_TOKEN` repository secret (PAT with write access to
|
|
125
|
+
`lucaGazzola/homebrew-forgeo`). The update notification now also names
|
|
126
|
+
`brew upgrade lucaGazzola/forgeo/forgeo`.
|
|
127
|
+
|
|
128
|
+
- Update notification: when `forgeo start` or `forgeo once` begins a cycle,
|
|
129
|
+
Forgeo checks PyPI at most once a day and, if a newer `forgeo-cli` release
|
|
130
|
+
exists, prints/logs a short notice with the upgrade command. The check is
|
|
131
|
+
best-effort (short timeout, failures logged and skipped), never modifies
|
|
132
|
+
the install, and can be disabled with `FORGEO_UPDATE_CHECK=0`.
|
|
133
|
+
|
|
134
|
+
- Automatic retries for `FAILED` tasks: `failed_retry_max` config key (default
|
|
135
|
+
`0`, unchanged behavior) plus `failed_retry_wait_cycles` (default `1`) let a
|
|
136
|
+
transiently failed task move back to `OPEN` after a backoff and be run
|
|
137
|
+
again. A task that exhausts its budget stays `FAILED` with its original
|
|
138
|
+
`failure_reason`; a per-task `retries_left` field overrides the budget for
|
|
139
|
+
one task. `BLOCKED` tasks are never auto-retried. The retry count is
|
|
140
|
+
recorded in `runs.jsonl` (the run record that succeeds carries it), shown
|
|
141
|
+
in the web console (task cards/modal and a History-tab **retry** column),
|
|
142
|
+
and exposed by the tasks/runs API.
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- The Linux prebuilt binary is now built on Ubuntu 22.04 (glibc 2.35) instead
|
|
147
|
+
of 24.04 (glibc 2.38), so it runs on older distros (e.g. Ubuntu 22.04,
|
|
148
|
+
Debian 12, Homebrew-on-Linux). The 0.4.0 `forgeo-linux-amd64` release
|
|
149
|
+
asset was rebuilt and re-uploaded with the same version number.
|
|
150
|
+
|
|
151
|
+
## [0.4.0] - 2026-08-10
|
|
152
|
+
|
|
153
|
+
### Added
|
|
154
|
+
|
|
155
|
+
- Delete OPEN tasks from the web console: a Delete button (with
|
|
156
|
+
confirmation) in the task detail modal, backed by `DELETE
|
|
157
|
+
/api/instances/<name>/tasks/<id>` and `JSONBacklog.delete_task`.
|
|
158
|
+
- Resolve BLOCKED tasks from the web console: the task modal shows the
|
|
159
|
+
blocker reason and can reopen the task (back to `OPEN`) via `POST
|
|
160
|
+
/api/instances/<name>/tasks/<id>/reopen`.
|
|
161
|
+
- The web console stays usable with many tasks: non-OPEN columns collapse
|
|
162
|
+
behind count badges with an expand toggle, so a long backlog no longer
|
|
163
|
+
renders every task as a tall card up front.
|
|
164
|
+
- The failure/block reason is shown prominently in the task detail modal.
|
|
165
|
+
- Config editing from the web console: `PUT /api/instances/<name>/config`
|
|
166
|
+
validates and persists `forgeo.yaml` changes, and a new Config tab in the
|
|
167
|
+
instance page edits the fields in a form (with a restart hint).
|
|
168
|
+
- Daemon control from the web console: start, stop, and restart an
|
|
169
|
+
instance's daemon from the top bar via `POST
|
|
170
|
+
/api/instances/<name>/{start,stop,restart}`.
|
|
171
|
+
- `forgeo init` now asks only for the bare agent command and appends the
|
|
172
|
+
task prompt automatically.
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
|
|
176
|
+
- Commit messages no longer carry the `forgeo: ` prefix.
|
|
177
|
+
- The instance is registered before the run lock is taken, so a `--name`
|
|
178
|
+
lookup never fails while starting.
|
|
179
|
+
- README revised for clarity and formatting.
|
|
180
|
+
|
|
181
|
+
## [0.3.0] - 2026-08-07
|
|
182
|
+
|
|
183
|
+
### Added
|
|
184
|
+
|
|
185
|
+
- `forgeo web [--host HOST] [--port PORT]` — a standalone central dashboard
|
|
186
|
+
(default `0.0.0.0:8790`, foreground like `forgeo start`) that aggregates
|
|
187
|
+
every registered instance. It reads each instance's data straight from its
|
|
188
|
+
files (`backlog.json`, `runs.jsonl`, `forgeo.log`, `BLOCKER.md`), so it
|
|
189
|
+
works whether or not that instance's daemon is running. Home page at `/`,
|
|
190
|
+
per-instance pages at `/instances/<name>/` (kanban backlog plus logs,
|
|
191
|
+
runs, blocker and config tabs), and a per-instance API under
|
|
192
|
+
`/api/instances/<name>/`.
|
|
193
|
+
- Shared web-server helpers (`forgeo.web_common`) used by the central
|
|
194
|
+
dashboard.
|
|
195
|
+
- Task editing in the web console: the task detail modal gained an **Edit**
|
|
196
|
+
mode (Save/Cancel), backed by a new `PATCH
|
|
197
|
+
/api/instances/<name>/tasks/<id>` endpoint and `JSONBacklog.update_task`.
|
|
198
|
+
- PyPI publishing: tagging a release now also publishes the `forgeo-cli`
|
|
199
|
+
wheel and sdist to PyPI via trusted publishing.
|
|
200
|
+
|
|
201
|
+
### Changed
|
|
202
|
+
|
|
203
|
+
- **The embedded per-daemon web server is gone.** `forgeo start` no longer
|
|
204
|
+
binds any port (`web_host`/`web_port` config keys are removed). The daemon
|
|
205
|
+
instead writes its live state (pid, started at, last outcome, next run) to
|
|
206
|
+
`daemon.state.json` next to the backlog after every cycle.
|
|
207
|
+
- The central dashboard (`forgeo web`) is now the **only** web interface:
|
|
208
|
+
it reads the daemon state files for accurate status, and it gained the
|
|
209
|
+
instance backlog's write endpoints, `POST
|
|
210
|
+
/api/instances/<name>/tasks` (with the web form on each instance page) and
|
|
211
|
+
`PATCH /api/instances/<name>/tasks/<id>`, so no feature was lost.
|
|
212
|
+
- `forgeo.web_common` docstring/API updated; `forgeo.server` module
|
|
213
|
+
removed.
|
|
214
|
+
|
|
215
|
+
## [0.2.1] - 2026-08-05
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
|
|
219
|
+
- `web_host` config option: the web dashboard/API bind address. Default
|
|
220
|
+
`127.0.0.1` (unchanged behavior); set `0.0.0.0` to reach it from other
|
|
221
|
+
hosts on the local network.
|
|
222
|
+
- `install.sh` now prefers a prebuilt standalone binary downloaded from the
|
|
223
|
+
matching GitHub Release for the host OS/arch — **no Python required**.
|
|
224
|
+
The pipx/pip fallback remains, used only when no prebuilt binary matches
|
|
225
|
+
the platform and a Python >= 3.11 is available.
|
|
226
|
+
- Tag-triggered CI builds single-file executables with PyInstaller on
|
|
227
|
+
Linux (amd64), macOS (amd64/arm64), and Windows (amd64) and attaches them
|
|
228
|
+
to the GitHub Release (`forgeo.spec`).
|
|
229
|
+
- Installer tests cover the binary-download path and the pipx/pip fallback
|
|
230
|
+
with stubs (no network).
|
|
231
|
+
|
|
232
|
+
## [0.2.0] - 2026-08-04
|
|
233
|
+
|
|
234
|
+
### Added
|
|
235
|
+
|
|
236
|
+
- `CHANGELOG.md` in Keep a Changelog format, with the `0.1.0` history
|
|
237
|
+
backfilled.
|
|
238
|
+
- Tag-triggered CI job that builds the wheel and sdist and attaches them to a
|
|
239
|
+
GitHub Release.
|
|
240
|
+
- Release steps documented in `CONTRIBUTING.md`.
|
|
241
|
+
- Web console frontend in `src/forgeo/web/`: a self-contained
|
|
242
|
+
HTML/CSS/JS dashboard (no framework, no build step, no external assets)
|
|
243
|
+
served at `/` showing the backlog grouped by status and daemon status,
|
|
244
|
+
auto-refreshing every 30 seconds.
|
|
245
|
+
- `install.sh` is now hosted on the project's own server and served from
|
|
246
|
+
<https://forgeo.org/install.sh>; README and docs use it in the one-liner.
|
|
247
|
+
|
|
248
|
+
## [0.1.0] - 2026-08-03
|
|
249
|
+
|
|
250
|
+
Initial release of the scheduled, agent-driven software forgeo.
|
|
251
|
+
|
|
252
|
+
### Added
|
|
253
|
+
|
|
254
|
+
- `forgeo start` persistent daemon: every `interval_minutes` it picks the
|
|
255
|
+
oldest `OPEN` task, runs it through the configured agent command, and commits
|
|
256
|
+
and pushes the result directly on `main`.
|
|
257
|
+
- Refactoring mode: when the backlog is empty, runs the agent with the
|
|
258
|
+
configured `refactor_prompt`.
|
|
259
|
+
- Blocker flow: an agent exiting with `blocked_exit_code` commits partial work,
|
|
260
|
+
writes `BLOCKER.md`, and pauses Forgeo until the task is reopened.
|
|
261
|
+
- Guided first-time setup: `forgeo init` wizard.
|
|
262
|
+
- `forgeo once` command to run a single cycle and exit.
|
|
263
|
+
- `forgeo status`, `forgeo stop`, and `forgeo restart` commands.
|
|
264
|
+
- `--auto` flag for the agent command for unattended runs.
|
|
265
|
+
- Local web dashboard and HTTP API served by the daemon.
|
|
266
|
+
- Durable run history recorded to `runs.jsonl` and exposed through the API.
|
|
267
|
+
- Telegram notification when a task is marked `BLOCKED`.
|
|
268
|
+
- Curl-to-bash one-liner installer (`install.sh`), pipx-first.
|
|
269
|
+
- MkDocs documentation website, published at <https://forgeo.org/>.
|
|
270
|
+
- GitHub Actions CI running `pytest`, `ruff`, and `mypy` on Python 3.11-3.13.
|
|
271
|
+
- Optional Docker sandbox for agent execution.
|
|
272
|
+
- Per-task `agent_command` override for cheap/expensive model routing.
|
|
273
|
+
- Project renamed to Forgeo, with MIT `LICENSE` and `CONTRIBUTING.md`.
|
|
274
|
+
|
|
275
|
+
### Changed
|
|
276
|
+
|
|
277
|
+
- Project slimmed down to a single-purpose scheduled worker; the interactive
|
|
278
|
+
backlog generator utility was removed.
|
|
279
|
+
- Duplicated commit/blocker handling unified between task and refactor runs.
|
|
280
|
+
- Agent stdout/stderr streamed into run logs instead of buffered.
|
|
281
|
+
- Corrupt backlog files preserved instead of silently discarded.
|
|
282
|
+
- Git command timeout made configurable; agent timeout made optional with
|
|
283
|
+
overlapping-run skipping.
|
|
284
|
+
- Dogfooding docs removed; local configs kept out of the repository.
|
|
285
|
+
|
|
286
|
+
[Unreleased]: https://github.com/lucaGazzola/forgeo/compare/v0.6.0...HEAD
|
|
287
|
+
[0.6.0]: https://github.com/lucaGazzola/forgeo/compare/v0.5.0...v0.6.0
|
|
288
|
+
[0.5.0]: https://github.com/lucaGazzola/forgeo/compare/v0.4.0...v0.5.0
|
|
289
|
+
[0.4.0]: https://github.com/lucaGazzola/forgeo/compare/v0.3.0...v0.4.0
|
|
290
|
+
[0.3.0]: https://github.com/lucaGazzola/forgeo/compare/v0.2.0...v0.3.0
|
|
291
|
+
[0.2.1]: https://github.com/lucaGazzola/forgeo/compare/v0.2.0...v0.2.1
|
|
292
|
+
[0.2.0]: https://github.com/lucaGazzola/forgeo/compare/v0.1.0...v0.2.0
|
|
293
|
+
[0.1.0]: https://github.com/lucaGazzola/forgeo/releases/tag/v0.1.0
|
|
@@ -80,15 +80,20 @@ Human contributions use the normal GitHub flow:
|
|
|
80
80
|
|
|
81
81
|
Releases are cut from `main` and published as GitHub Releases. Tagging the
|
|
82
82
|
repo triggers CI, which builds the wheel, sdist, **and prebuilt standalone
|
|
83
|
-
binaries** and attaches them to the release
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
binaries** and attaches them to the release; `install.sh` downloads the
|
|
84
|
+
matching prebuilt binary from the release (`pipx`/`pip` fallback only when no
|
|
85
|
+
binary matches the platform), and the `publish-homebrew` job re-renders and
|
|
86
|
+
pushes the formula of the `lucaGazzola/homebrew-forgeo` tap.
|
|
86
87
|
|
|
87
88
|
> Patch and minor releases **must** include the built binaries, otherwise the
|
|
88
89
|
> `install.sh` binary path (the default, no-Python install) breaks. The CI
|
|
89
90
|
> `build-binaries` job builds them automatically on any `v*` tag, but make
|
|
90
91
|
> sure the release actually carries them — the `forgeo-<os>-<arch>` assets
|
|
91
92
|
> listed below are what the installer downloads.
|
|
93
|
+
>
|
|
94
|
+
> The `publish-homebrew` job needs the `HOMEBREW_TAP_TOKEN` repository secret
|
|
95
|
+
> (a PAT with write access to `lucaGazzola/homebrew-forgeo`); a release cut
|
|
96
|
+
> without it fails that job and leaves the tap outdated until re-run.
|
|
92
97
|
|
|
93
98
|
1. Confirm the [quality gates](#quality-gates) are green on `main`.
|
|
94
99
|
2. Bump the version in `pyproject.toml` (`version = "x.y.z"`) and in
|
|
@@ -114,6 +119,8 @@ and `install.sh` downloads the matching prebuilt binary from the release
|
|
|
114
119
|
`forgeo-linux-amd64`, `forgeo-darwin-amd64`, `forgeo-darwin-arm64`,
|
|
115
120
|
`forgeo-windows-amd64.exe` binaries) are listed under
|
|
116
121
|
<https://github.com/lucaGazzola/forgeo/releases>.
|
|
122
|
+
8. Confirm the `publish-homebrew` job updated the tap: `brew update` and
|
|
123
|
+
`brew upgrade lucaGazzola/forgeo/forgeo` should now install the new version.
|
|
117
124
|
|
|
118
125
|
## License
|
|
119
126
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: forgeo-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A scheduled software forgeo: executes backlog tasks on main, refactors when idle, and writes BLOCKER.md when it needs human input.
|
|
5
5
|
Project-URL: Homepage, https://forgeo.org
|
|
6
6
|
Project-URL: Documentation, https://forgeo.org
|
|
@@ -71,7 +71,10 @@ a backlog, and it decides what to work on next, runs your
|
|
|
71
71
|
agent on it, and commits the result. Progress, pending decisions, and history
|
|
72
72
|
are tracked in plain files you can inspect at any time, plus a web dashboard.
|
|
73
73
|
Forgeo only interrupts you when a decision is genuinely yours to
|
|
74
|
-
make, everything else happens autonomously.
|
|
74
|
+
make, everything else happens autonomously. Transient failures (a network
|
|
75
|
+
blip, a flaky test) are retried automatically when the retry policy is
|
|
76
|
+
enabled, and only a task that keeps failing or genuinely needs a human
|
|
77
|
+
decision ever reaches you.
|
|
75
78
|
|
|
76
79
|
All you need is basic comfort with a terminal, a git repository, and any coding
|
|
77
80
|
agent CLI.
|
|
@@ -81,29 +84,41 @@ agent CLI.
|
|
|
81
84
|
The full walkthrough is in [Getting started](docs/getting-started.md).
|
|
82
85
|
|
|
83
86
|
```bash
|
|
84
|
-
# 1. Install
|
|
85
|
-
|
|
87
|
+
# 1. Install (any one of these)
|
|
88
|
+
|
|
89
|
+
# Homebrew (macOS / Linux)
|
|
90
|
+
brew install lucaGazzola/forgeo/forgeo
|
|
86
91
|
|
|
87
|
-
or
|
|
92
|
+
# or: the one-liner (prebuilt binary, no Python required)
|
|
93
|
+
curl -fsSL https://forgeo.org/install.sh | bash
|
|
88
94
|
|
|
95
|
+
# or: pipx
|
|
89
96
|
pipx install forgeo-cli
|
|
90
97
|
|
|
91
98
|
# 2. Create your Forgeo (guided wizard, run from your project root)
|
|
92
99
|
forgeo init
|
|
93
100
|
|
|
94
|
-
# 3. Start Forgeo
|
|
95
|
-
forgeo start #
|
|
101
|
+
# 3. Start Forgeo (detached in the background; exits immediately)
|
|
102
|
+
forgeo start # every interval_minutes, implement the oldest OPEN task (dependencies first)
|
|
103
|
+
forgeo stop # stop the daemon again
|
|
96
104
|
```
|
|
97
105
|
|
|
98
106
|
`forgeo init` writes `forgeo.yaml` and a `.forgeo/` folder for the backlog
|
|
99
107
|
and logs. Fill the backlog with plain JSON tasks (see
|
|
100
108
|
[Backlog format](docs/backlog.md)) or add them from the web console while
|
|
101
|
-
it runs, Forgeo does the rest. Open the dashboard with `forgeo web` (default <http://0.0.0.0:8790>):
|
|
109
|
+
it runs, Forgeo does the rest. Open the dashboard with `forgeo web` (default <http://0.0.0.0:8790>), or keep it always-on with `forgeo web -d` (stop it with `forgeo web stop`, check it with `forgeo web status`):
|
|
102
110
|
|
|
103
111
|

|
|
104
112
|
|
|
113
|
+
By default the dashboard is open to anyone who can reach the port. On a
|
|
114
|
+
shared host, protect it with bearer-token auth: `forgeo web --token`
|
|
115
|
+
generates a token (printed once, saved to `~/.config/forgeo/web.toml`) and
|
|
116
|
+
requires `Authorization: Bearer <token>` on every `/api/*` route — see
|
|
117
|
+
[Web console & HTTP API](docs/web-console-api.md).
|
|
118
|
+
|
|
105
119
|
One-off commands: `forgeo once` (single cycle), `forgeo status` (summary),
|
|
106
|
-
`forgeo
|
|
120
|
+
`forgeo validate` (read-only dry run before starting), `forgeo stop`,
|
|
121
|
+
`forgeo restart`, every command is in the
|
|
107
122
|
[CLI reference](docs/cli-reference.md).
|
|
108
123
|
|
|
109
124
|
You can run several factories at once, one per repository, each config is
|
|
@@ -125,7 +140,13 @@ central dashboard, `forgeo web`.
|
|
|
125
140
|
| Web dashboard & HTTP API | [Web console & HTTP API](docs/web-console-api.md) |
|
|
126
141
|
|
|
127
142
|
Everything is stored in plain files: the backlog, `forgeo.log`, and
|
|
128
|
-
`BLOCKER.md` whenever a decision is pending.
|
|
143
|
+
`BLOCKER.md` whenever a decision is pending. The backlog can also live in
|
|
144
|
+
another application behind an `http(s)` URL — Forgeo reads the whole task
|
|
145
|
+
document with `GET` and writes it back with `POST`, with optional OAuth2
|
|
146
|
+
client-credentials auth (see [Backlog format](docs/backlog.md)). A *file*
|
|
147
|
+
backlog is snapshotted (rotating `backlog.json.bak` files) before every
|
|
148
|
+
agent run and on daemon startup, and restored automatically if it is ever
|
|
149
|
+
found corrupt — a bad write never loses your tasks.
|
|
129
150
|
|
|
130
151
|
## Develop
|
|
131
152
|
|
|
@@ -17,7 +17,10 @@ a backlog, and it decides what to work on next, runs your
|
|
|
17
17
|
agent on it, and commits the result. Progress, pending decisions, and history
|
|
18
18
|
are tracked in plain files you can inspect at any time, plus a web dashboard.
|
|
19
19
|
Forgeo only interrupts you when a decision is genuinely yours to
|
|
20
|
-
make, everything else happens autonomously.
|
|
20
|
+
make, everything else happens autonomously. Transient failures (a network
|
|
21
|
+
blip, a flaky test) are retried automatically when the retry policy is
|
|
22
|
+
enabled, and only a task that keeps failing or genuinely needs a human
|
|
23
|
+
decision ever reaches you.
|
|
21
24
|
|
|
22
25
|
All you need is basic comfort with a terminal, a git repository, and any coding
|
|
23
26
|
agent CLI.
|
|
@@ -27,29 +30,41 @@ agent CLI.
|
|
|
27
30
|
The full walkthrough is in [Getting started](docs/getting-started.md).
|
|
28
31
|
|
|
29
32
|
```bash
|
|
30
|
-
# 1. Install
|
|
31
|
-
|
|
33
|
+
# 1. Install (any one of these)
|
|
34
|
+
|
|
35
|
+
# Homebrew (macOS / Linux)
|
|
36
|
+
brew install lucaGazzola/forgeo/forgeo
|
|
32
37
|
|
|
33
|
-
or
|
|
38
|
+
# or: the one-liner (prebuilt binary, no Python required)
|
|
39
|
+
curl -fsSL https://forgeo.org/install.sh | bash
|
|
34
40
|
|
|
41
|
+
# or: pipx
|
|
35
42
|
pipx install forgeo-cli
|
|
36
43
|
|
|
37
44
|
# 2. Create your Forgeo (guided wizard, run from your project root)
|
|
38
45
|
forgeo init
|
|
39
46
|
|
|
40
|
-
# 3. Start Forgeo
|
|
41
|
-
forgeo start #
|
|
47
|
+
# 3. Start Forgeo (detached in the background; exits immediately)
|
|
48
|
+
forgeo start # every interval_minutes, implement the oldest OPEN task (dependencies first)
|
|
49
|
+
forgeo stop # stop the daemon again
|
|
42
50
|
```
|
|
43
51
|
|
|
44
52
|
`forgeo init` writes `forgeo.yaml` and a `.forgeo/` folder for the backlog
|
|
45
53
|
and logs. Fill the backlog with plain JSON tasks (see
|
|
46
54
|
[Backlog format](docs/backlog.md)) or add them from the web console while
|
|
47
|
-
it runs, Forgeo does the rest. Open the dashboard with `forgeo web` (default <http://0.0.0.0:8790>):
|
|
55
|
+
it runs, Forgeo does the rest. Open the dashboard with `forgeo web` (default <http://0.0.0.0:8790>), or keep it always-on with `forgeo web -d` (stop it with `forgeo web stop`, check it with `forgeo web status`):
|
|
48
56
|
|
|
49
57
|

|
|
50
58
|
|
|
59
|
+
By default the dashboard is open to anyone who can reach the port. On a
|
|
60
|
+
shared host, protect it with bearer-token auth: `forgeo web --token`
|
|
61
|
+
generates a token (printed once, saved to `~/.config/forgeo/web.toml`) and
|
|
62
|
+
requires `Authorization: Bearer <token>` on every `/api/*` route — see
|
|
63
|
+
[Web console & HTTP API](docs/web-console-api.md).
|
|
64
|
+
|
|
51
65
|
One-off commands: `forgeo once` (single cycle), `forgeo status` (summary),
|
|
52
|
-
`forgeo
|
|
66
|
+
`forgeo validate` (read-only dry run before starting), `forgeo stop`,
|
|
67
|
+
`forgeo restart`, every command is in the
|
|
53
68
|
[CLI reference](docs/cli-reference.md).
|
|
54
69
|
|
|
55
70
|
You can run several factories at once, one per repository, each config is
|
|
@@ -71,7 +86,13 @@ central dashboard, `forgeo web`.
|
|
|
71
86
|
| Web dashboard & HTTP API | [Web console & HTTP API](docs/web-console-api.md) |
|
|
72
87
|
|
|
73
88
|
Everything is stored in plain files: the backlog, `forgeo.log`, and
|
|
74
|
-
`BLOCKER.md` whenever a decision is pending.
|
|
89
|
+
`BLOCKER.md` whenever a decision is pending. The backlog can also live in
|
|
90
|
+
another application behind an `http(s)` URL — Forgeo reads the whole task
|
|
91
|
+
document with `GET` and writes it back with `POST`, with optional OAuth2
|
|
92
|
+
client-credentials auth (see [Backlog format](docs/backlog.md)). A *file*
|
|
93
|
+
backlog is snapshotted (rotating `backlog.json.bak` files) before every
|
|
94
|
+
agent run and on daemon startup, and restored automatically if it is ever
|
|
95
|
+
found corrupt — a bad write never loses your tasks.
|
|
75
96
|
|
|
76
97
|
## Develop
|
|
77
98
|
|
|
@@ -39,11 +39,37 @@ The exit code decides the outcome of the run:
|
|
|
39
39
|
| Exit code | Outcome | What happens |
|
|
40
40
|
| --- | --- | --- |
|
|
41
41
|
| `0` | **SUCCESS** | Everything is committed (`git add -A && git commit`) with the message `<title> (#<id>)`, pushed when a remote is set, and the task is marked `COMPLETED`. |
|
|
42
|
-
| `
|
|
42
|
+
| `no_changes_exit_code` (default `3`) | **SUCCESS, no changes** | The agent explicitly reports the task needs **no code change**: the task is marked `COMPLETED` without a commit (and the run record notes why). Only accepted when the working tree is clean. |
|
|
43
|
+
| `blocked_exit_code` (default `2`) | **BLOCKED** | The agent needs a human decision. Partial work is committed as `<title> [partial]`, the agent's reason is persisted on the task (`blocker_reason`), optional Telegram and/or webhook notifications are sent, and the task is marked `BLOCKED`. `BLOCKER.md` is rendered from the backlog's `BLOCKED` tasks on the next cycle — real per-task reasons, never generic text — and disappears once the last one is resolved (reopen it from the web console). |
|
|
43
44
|
| anything else | **ERROR** | Changes are discarded (`git reset --hard` + `git clean -fd`), the failure is logged, and the task is marked `FAILED`. |
|
|
44
45
|
|
|
45
46
|
The blocked exit code is configurable via `blocked_exit_code` in
|
|
46
|
-
[forgeo.yaml](configuration.md)
|
|
47
|
+
[forgeo.yaml](configuration.md), and the no-change exit code via
|
|
48
|
+
`no_changes_exit_code`.
|
|
49
|
+
|
|
50
|
+
A `FAILED` task stays `FAILED` until a human reopens it — unless the retry
|
|
51
|
+
policy is enabled (`failed_retry_max`, see [Configuration](configuration.md)),
|
|
52
|
+
in which case Forgeo moves the task back to `OPEN` after
|
|
53
|
+
`failed_retry_wait_cycles` cycles and runs it again, incrementing its retry
|
|
54
|
+
count. `BLOCKED` is never retried automatically: it always waits for a human.
|
|
55
|
+
|
|
56
|
+
## The no-change contract
|
|
57
|
+
|
|
58
|
+
Forgeo cannot tell "the agent deliberately made no changes" from "the agent
|
|
59
|
+
did nothing". A `SUCCESS` exit that produces **no changes is therefore not a
|
|
60
|
+
valid completion for a task**:
|
|
61
|
+
|
|
62
|
+
- exiting `0` while leaving the working tree **unchanged** fails the task
|
|
63
|
+
(`FAILED`, reason: *"Agent exited 0 but produced no changes"*);
|
|
64
|
+
- to complete a task **without touching the code**, exit
|
|
65
|
+
`no_changes_exit_code` (default `3`). The working tree must be clean — an
|
|
66
|
+
agent that reports "no changes" while leaving uncommitted work behind fails
|
|
67
|
+
instead.
|
|
68
|
+
|
|
69
|
+
Refactoring passes are the exception: when the backlog is empty, a refactor
|
|
70
|
+
that finds nothing to improve is a normal, successful run (the default
|
|
71
|
+
refactor prompt already says "if nothing needs refactoring, make no
|
|
72
|
+
changes").
|
|
47
73
|
|
|
48
74
|
## Timeouts
|
|
49
75
|
|
|
@@ -84,6 +110,8 @@ that, based on the exit code. The working contract is:
|
|
|
84
110
|
- make your changes in the repository;
|
|
85
111
|
- **do not** run `git add`, `git commit`, `git push`, or reset the tree;
|
|
86
112
|
- exit `0` to have your changes committed and pushed as one commit;
|
|
113
|
+
- exit `no_changes_exit_code` when the task needs no code change (never exit
|
|
114
|
+
`0` with an empty tree — that fails the task);
|
|
87
115
|
- exit `blocked_exit_code` to have partial work preserved and a blocker
|
|
88
116
|
written;
|
|
89
117
|
- exit anything else to have your changes discarded.
|