forgeo-cli 0.4.0__tar.gz → 0.5.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.5.0}/.github/workflows/ci.yml +60 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/.gitignore +1 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/CHANGELOG.md +110 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/CONTRIBUTING.md +10 -3
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/PKG-INFO +29 -11
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/README.md +27 -9
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/agent-contract.md +30 -2
- forgeo_cli-0.5.0/docs/backlog.md +284 -0
- forgeo_cli-0.5.0/docs/cli-reference.md +346 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/configuration.md +116 -2
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/getting-started.md +50 -20
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/index.md +28 -11
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/web-console-api.md +201 -41
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/install.sh +29 -3
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/pyproject.toml +1 -1
- forgeo_cli-0.5.0/scripts/__init__.py +0 -0
- forgeo_cli-0.5.0/scripts/render_homebrew_formula.py +119 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/__init__.py +1 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/agent.py +25 -1
- forgeo_cli-0.5.0/src/forgeo/backlog.py +554 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/central.py +504 -38
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/cli.py +359 -43
- forgeo_cli-0.5.0/src/forgeo/daemon.py +425 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/daemon_control.py +46 -13
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/forgeo.py +221 -37
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/git.py +14 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/models.py +158 -0
- forgeo_cli-0.5.0/src/forgeo/notify.py +131 -0
- forgeo_cli-0.5.0/src/forgeo/runs.py +131 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/setup.py +23 -3
- forgeo_cli-0.5.0/src/forgeo/update.py +172 -0
- forgeo_cli-0.5.0/src/forgeo/validate.py +221 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web/central/central.css +329 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web/central/central.js +448 -58
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web/central/instance.html +61 -13
- forgeo_cli-0.5.0/src/forgeo/web/central/login.html +76 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web/style.css +7 -1
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web_common.py +2 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/conftest.py +11 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_agent.py +27 -0
- forgeo_cli-0.5.0/tests/test_backlog.py +899 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_cli.py +358 -9
- forgeo_cli-0.5.0/tests/test_daemon.py +383 -0
- forgeo_cli-0.5.0/tests/test_factory.py +947 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_git.py +20 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_install.py +3 -2
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_models.py +105 -0
- forgeo_cli-0.5.0/tests/test_render_homebrew.py +83 -0
- forgeo_cli-0.5.0/tests/test_runs.py +515 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_setup.py +16 -1
- forgeo_cli-0.5.0/tests/test_update.py +205 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_web.py +515 -8
- forgeo_cli-0.5.0/tests/test_web_lock.py +521 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/www/index.html +3 -3
- 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/src/forgeo/backlog.py +0 -296
- forgeo_cli-0.4.0/src/forgeo/daemon.py +0 -212
- 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.5.0}/LICENSE +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/config/nginx-forgeo.conf +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/img/console.png +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/img/logo.png +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/docs/img/title.svg +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/forgeo.spec +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/mkdocs.yml +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/__main__.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/config.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/instances.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/io.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/src/forgeo/web/central/index.html +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_instances.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_io.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.0}/tests/test_web_common.py +0 -0
- {forgeo_cli-0.4.0 → forgeo_cli-0.5.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')
|
|
@@ -7,6 +7,114 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-08-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `forgeo validate` (and the pre-flight check before a detached
|
|
15
|
+
`forgeo start`) distinguishes a repository with no commits yet: a clean
|
|
16
|
+
tree is now a warning — the first cycle creates the initial commit — while
|
|
17
|
+
a non-clean tree is a problem that names the fix
|
|
18
|
+
(`git add -A && git commit -m "Initial commit"`), since every file is
|
|
19
|
+
untracked and every cycle would otherwise refuse as dirty. Previously
|
|
20
|
+
"no commits" was always a hard problem with a misleading message.
|
|
21
|
+
|
|
22
|
+
- `forgeo start` now starts the daemon **detached in the background and
|
|
23
|
+
exits**, like `forgeo restart` and the web console's start button already
|
|
24
|
+
did; the daemon is managed with `forgeo stop`/`forgeo restart`/`forgeo
|
|
25
|
+
status`. `forgeo start -f` (`--foreground`) keeps the historical
|
|
26
|
+
foreground behavior. A detached start refuses while the per-forgeo lock is
|
|
27
|
+
held and runs the same read-only checks as `forgeo validate` first, so a
|
|
28
|
+
broken config fails fast instead of leaving a silently dead daemon.
|
|
29
|
+
`--interval-minutes` is forwarded to the detached daemon.
|
|
30
|
+
|
|
31
|
+
- The daemon reloads `forgeo.yaml` on the next cycle boundary when the file
|
|
32
|
+
changes (or on `SIGHUP`): a valid change is revalidated, logged, and used
|
|
33
|
+
from the next cycle; an invalid change is logged and the last valid config
|
|
34
|
+
stays in use. The web console's config save reflects this
|
|
35
|
+
(`restart_required: false`). Path changes (`repo`, `backlog`,
|
|
36
|
+
`blocker_file`, `log_file`) stay pinned to the daemon's startup values and
|
|
37
|
+
still need `forgeo restart`, so the daemon's lock files are never detached
|
|
38
|
+
from the config.
|
|
39
|
+
|
|
40
|
+
- Optional bearer-token auth for the central web dashboard (`forgeo web`):
|
|
41
|
+
`forgeo web --token` (or a `token` key in `~/.config/forgeo/web.toml`)
|
|
42
|
+
requires `Authorization: Bearer <token>` on every `/api/*` route and
|
|
43
|
+
answers `401` otherwise. `forgeo web --token` with no value generates a
|
|
44
|
+
token, prints it once on startup, and saves it (mode `0600`); a generated
|
|
45
|
+
token is only ever printed once. Static assets and the new token prompt
|
|
46
|
+
page (`/central/login.html`) stay reachable without a token, and a
|
|
47
|
+
`?token=...` URL signs the browser in automatically. With no flag and no
|
|
48
|
+
token file the dashboard keeps its historical open-by-default behavior.
|
|
49
|
+
|
|
50
|
+
- `forgeo validate` — a read-only dry run that checks whether a forgeo is
|
|
51
|
+
ready to run before starting it: the config schema, the repository (exists,
|
|
52
|
+
is a git repo, `git` on PATH), the branch and remote resolution, the
|
|
53
|
+
backlog parsing, a non-blank agent command, and the run lock state. It
|
|
54
|
+
reports every problem at once, never invokes the agent, and makes no writes
|
|
55
|
+
(no lock, no backlog changes). Exit code `0` when healthy, `1` with a
|
|
56
|
+
summary of problems otherwise. Supports `--config` and `--name`.
|
|
57
|
+
|
|
58
|
+
- `run_history_keep` config key: `runs.jsonl` is trimmed to that many records
|
|
59
|
+
on append (default `2000`), so a busy Forgeo's run history never grows
|
|
60
|
+
forever. Trimming is atomic (temp file + rename) and a failed trim is
|
|
61
|
+
logged and skipped, never fatal to the cycle; `run_history_keep: 0`
|
|
62
|
+
disables retention entirely (the previous grow-forever behavior).
|
|
63
|
+
|
|
64
|
+
- Persisted agent output per run: each `RunRecord` now stores a bounded tail
|
|
65
|
+
of the agent's stdout/stderr (last `run_output_lines` lines, default `200`),
|
|
66
|
+
so failed and blocked runs keep the full tail of what the agent said. The
|
|
67
|
+
web console's **History** tab shows it in a read-only, monospace,
|
|
68
|
+
collapsible view; `run_output_lines: 0` disables persistence, and records
|
|
69
|
+
written before the field existed render as empty.
|
|
70
|
+
|
|
71
|
+
- Backlog snapshots: before every agent run (and on daemon startup) Forgeo
|
|
72
|
+
copies the backlog to a rotating snapshot (`backlog.json.bak`,
|
|
73
|
+
`backlog.json.bak.1`, ... keeping the last 2 by default), and a read that
|
|
74
|
+
finds the backlog corrupt restores the newest valid snapshot in place —
|
|
75
|
+
with the corrupt file still preserved — instead of falling back to an
|
|
76
|
+
empty store. A missing backlog is a no-op.
|
|
77
|
+
|
|
78
|
+
- Task dependencies are now enforced when picking the next task: Forgeo picks
|
|
79
|
+
the oldest `OPEN` task whose `dependencies` are all `COMPLETED` instead of
|
|
80
|
+
the plain oldest `OPEN` task, so a task never runs before the work it
|
|
81
|
+
depends on. Unsatisfied dependencies (including ids that don't exist in the
|
|
82
|
+
backlog) are surfaced on `forgeo status` (`waiting on:` line) and in the web
|
|
83
|
+
console's task detail modal (*Waiting on dependencies* banner); the
|
|
84
|
+
`GET /api/instances/<name>/tasks*` responses annotate each task with an
|
|
85
|
+
`unsatisfied_dependencies` field.
|
|
86
|
+
|
|
87
|
+
- Homebrew install support: `brew install lucaGazzola/forgeo/forgeo`
|
|
88
|
+
installs the prebuilt binary on macOS (arm64/Intel) and Linux (Intel). The
|
|
89
|
+
`publish-homebrew` CI job re-renders the tap formula (sha256 + version)
|
|
90
|
+
from `scripts/render_homebrew_formula.py` on every release; it needs the
|
|
91
|
+
`HOMEBREW_TAP_TOKEN` repository secret (PAT with write access to
|
|
92
|
+
`lucaGazzola/homebrew-forgeo`). The update notification now also names
|
|
93
|
+
`brew upgrade lucaGazzola/forgeo/forgeo`.
|
|
94
|
+
|
|
95
|
+
- Update notification: when `forgeo start` or `forgeo once` begins a cycle,
|
|
96
|
+
Forgeo checks PyPI at most once a day and, if a newer `forgeo-cli` release
|
|
97
|
+
exists, prints/logs a short notice with the upgrade command. The check is
|
|
98
|
+
best-effort (short timeout, failures logged and skipped), never modifies
|
|
99
|
+
the install, and can be disabled with `FORGEO_UPDATE_CHECK=0`.
|
|
100
|
+
|
|
101
|
+
- Automatic retries for `FAILED` tasks: `failed_retry_max` config key (default
|
|
102
|
+
`0`, unchanged behavior) plus `failed_retry_wait_cycles` (default `1`) let a
|
|
103
|
+
transiently failed task move back to `OPEN` after a backoff and be run
|
|
104
|
+
again. A task that exhausts its budget stays `FAILED` with its original
|
|
105
|
+
`failure_reason`; a per-task `retries_left` field overrides the budget for
|
|
106
|
+
one task. `BLOCKED` tasks are never auto-retried. The retry count is
|
|
107
|
+
recorded in `runs.jsonl` (the run record that succeeds carries it), shown
|
|
108
|
+
in the web console (task cards/modal and a History-tab **retry** column),
|
|
109
|
+
and exposed by the tasks/runs API.
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- The Linux prebuilt binary is now built on Ubuntu 22.04 (glibc 2.35) instead
|
|
114
|
+
of 24.04 (glibc 2.38), so it runs on older distros (e.g. Ubuntu 22.04,
|
|
115
|
+
Debian 12, Homebrew-on-Linux). The 0.4.0 `forgeo-linux-amd64` release
|
|
116
|
+
asset was rebuilt and re-uploaded with the same version number.
|
|
117
|
+
|
|
10
118
|
## [0.4.0] - 2026-08-10
|
|
11
119
|
|
|
12
120
|
### Added
|
|
@@ -142,7 +250,8 @@ Initial release of the scheduled, agent-driven software forgeo.
|
|
|
142
250
|
overlapping-run skipping.
|
|
143
251
|
- Dogfooding docs removed; local configs kept out of the repository.
|
|
144
252
|
|
|
145
|
-
[Unreleased]: https://github.com/lucaGazzola/forgeo/compare/v0.
|
|
253
|
+
[Unreleased]: https://github.com/lucaGazzola/forgeo/compare/v0.5.0...HEAD
|
|
254
|
+
[0.5.0]: https://github.com/lucaGazzola/forgeo/compare/v0.4.0...v0.5.0
|
|
146
255
|
[0.4.0]: https://github.com/lucaGazzola/forgeo/compare/v0.3.0...v0.4.0
|
|
147
256
|
[0.3.0]: https://github.com/lucaGazzola/forgeo/compare/v0.2.0...v0.3.0
|
|
148
257
|
[0.2.1]: https://github.com/lucaGazzola/forgeo/compare/v0.2.0...v0.2.1
|
|
@@ -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.5.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,10 @@ 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 is snapshotted
|
|
144
|
+
(rotating `backlog.json.bak` files) before every agent run and on daemon
|
|
145
|
+
startup, and restored automatically if it is ever found corrupt — a bad write
|
|
146
|
+
never loses your tasks.
|
|
129
147
|
|
|
130
148
|
## Develop
|
|
131
149
|
|
|
@@ -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,10 @@ 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 is snapshotted
|
|
90
|
+
(rotating `backlog.json.bak` files) before every agent run and on daemon
|
|
91
|
+
startup, and restored automatically if it is ever found corrupt — a bad write
|
|
92
|
+
never loses your tasks.
|
|
75
93
|
|
|
76
94
|
## Develop
|
|
77
95
|
|
|
@@ -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.
|