forgeo-cli 0.10.0__tar.gz → 0.11.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.
Files changed (97) hide show
  1. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/CHANGELOG.md +24 -1
  2. forgeo_cli-0.11.0/PKG-INFO +188 -0
  3. forgeo_cli-0.11.0/README.md +134 -0
  4. forgeo_cli-0.11.0/docs/agent-contract.md +78 -0
  5. forgeo_cli-0.11.0/docs/backlog.md +217 -0
  6. forgeo_cli-0.11.0/docs/cli-reference.md +173 -0
  7. forgeo_cli-0.11.0/docs/configuration.md +263 -0
  8. forgeo_cli-0.11.0/docs/getting-started.md +116 -0
  9. forgeo_cli-0.11.0/docs/index.md +37 -0
  10. forgeo_cli-0.11.0/docs/web-console-api.md +220 -0
  11. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/install.sh +1 -1
  12. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/mkdocs.yml +1 -1
  13. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/pyproject.toml +1 -1
  14. forgeo_cli-0.11.0/scripts/test-github-backlog-e2e.sh +225 -0
  15. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/__init__.py +1 -1
  16. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/agent.py +18 -26
  17. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/backlog.py +196 -40
  18. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/backlog_github.py +126 -177
  19. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/backlog_gitlab.py +123 -169
  20. forgeo_cli-0.11.0/src/forgeo/backlog_issue_base.py +366 -0
  21. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/backlog_jira.py +113 -103
  22. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/central.py +185 -88
  23. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/config.py +15 -12
  24. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/daemon.py +10 -5
  25. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/forgeo.py +158 -59
  26. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/git.py +76 -9
  27. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/io.py +2 -0
  28. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/models.py +149 -175
  29. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/paths.py +1 -1
  30. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/runs.py +5 -4
  31. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/setup.py +170 -138
  32. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/validate.py +36 -52
  33. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/central/central.css +12 -0
  34. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/central/central.js +86 -3
  35. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/central/instance.html +21 -0
  36. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/style.css +16 -1
  37. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web_common.py +5 -7
  38. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_cli.py +2 -0
  39. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_web.py +2 -1
  40. forgeo_cli-0.10.0/PKG-INFO +0 -254
  41. forgeo_cli-0.10.0/README.md +0 -200
  42. forgeo_cli-0.10.0/docs/agent-contract.md +0 -154
  43. forgeo_cli-0.10.0/docs/backlog.md +0 -515
  44. forgeo_cli-0.10.0/docs/cli-reference.md +0 -374
  45. forgeo_cli-0.10.0/docs/configuration.md +0 -536
  46. forgeo_cli-0.10.0/docs/getting-started.md +0 -221
  47. forgeo_cli-0.10.0/docs/index.md +0 -67
  48. forgeo_cli-0.10.0/docs/web-console-api.md +0 -695
  49. forgeo_cli-0.10.0/src/forgeo/backlog_issue_base.py +0 -183
  50. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/.github/workflows/ci.yml +0 -0
  51. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/.gitignore +0 -0
  52. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/CONTRIBUTING.md +0 -0
  53. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/LICENSE +0 -0
  54. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/config/nginx-forgeo.conf +0 -0
  55. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/docs/img/console.png +0 -0
  56. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/docs/img/demo.gif +0 -0
  57. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/docs/img/logo.png +0 -0
  58. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/docs/img/og.png +0 -0
  59. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/docs/img/title.svg +0 -0
  60. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/forgeo.spec +0 -0
  61. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/scripts/__init__.py +0 -0
  62. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/scripts/render_homebrew_formula.py +0 -0
  63. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/__main__.py +0 -0
  64. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/backlog_http.py +0 -0
  65. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/cli.py +0 -0
  66. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/daemon_control.py +0 -0
  67. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/instances.py +0 -0
  68. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/notify.py +0 -0
  69. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/oauth.py +0 -0
  70. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/update.py +0 -0
  71. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/central/index.html +0 -0
  72. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/src/forgeo/web/central/login.html +0 -0
  73. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/conftest.py +0 -0
  74. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_agent.py +0 -0
  75. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_backlog.py +0 -0
  76. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_backlog_github.py +0 -0
  77. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_backlog_gitlab.py +0 -0
  78. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_backlog_http.py +0 -0
  79. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_backlog_jira.py +0 -0
  80. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_daemon.py +0 -0
  81. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_factory.py +0 -0
  82. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_git.py +0 -0
  83. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_install.py +0 -0
  84. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_instances.py +0 -0
  85. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_io.py +0 -0
  86. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_models.py +0 -0
  87. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_oauth.py +0 -0
  88. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_paths.py +0 -0
  89. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_remote_backlog_cycle.py +0 -0
  90. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_render_homebrew.py +0 -0
  91. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_runs.py +0 -0
  92. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_setup.py +0 -0
  93. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_update.py +0 -0
  94. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_web_common.py +0 -0
  95. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/tests/test_web_lock.py +0 -0
  96. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/www/404.html +0 -0
  97. {forgeo_cli-0.10.0 → forgeo_cli-0.11.0}/www/index.html +0 -0
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.0] - 2026-08-31
11
+
12
+ ### Added
13
+
14
+ - **REVIEW status with feature-branch workflow** (`review_mode: branch`). When enabled, a successful agent run no longer commits directly to `main` as `COMPLETED`: the engine creates a feature branch `forgeo/review/<TASK_ID>` (via `review_branch_prefix`, default `forgeo/review/`), commits there, pushes, and marks the task `REVIEW`. Tasks in `REVIEW` block dependants (like `BLOCKED`/`FAILED`) while independent tasks keep running.
15
+ - Per-task `review_required` override (`bool | null`): `true` forces branch+REVIEW, `false` forces direct `COMPLETED`, `null` inherits `review_mode`. Editable via `PATCH /api/instances/<name>/tasks/<id>` and persisted across all providers (file/http body, hidden `<!-- forgeo: {...} -->` block on GitHub/GitLab, Jira issue property `review_branch`/`review_commit_sha`).
16
+ - Engine-managed `review_branch` and `review_commit_sha` on `Task` (set on `REVIEW`, cleared on leave), carried through document stores (`DocumentBacklogStore.set_review`/`complete_review`/`request_changes`) and issue stores via `forgeo-review` label (`forgeo_labels()`) plus engine state.
17
+ - Web console: dedicated **REVIEW** kanban column, review-branch display on cards/modals, and human-in-the-loop actions `Complete` (`POST …/complete-review` → `COMPLETED` after manual merge) and `Request changes` (`POST …/request-changes` → `OPEN` for rework). Issue providers also show `external_url`/board links for the branch.
18
+ - Generic webhook now supports `review` event (`WEBHOOK_EVENTS += "review"`, `notify_webhook_events` validation), sent by `Forgeo._run_task` on the `REVIEW` transition via `GitManager.create_review_branch`/`a_create_review_branch` and `_commit_on_review_branch` (creates/resets branch, commits, pushes, switches back to `branch` and hard-resets `main`).
19
+ - `HttpBacklog`/`JSONBacklog`/`IssueBacklogBase` now expose `set_review`/`complete_review`/`request_changes` and central dashboard routes `POST /api/instances/<name>/tasks/<id>/{complete-review,request-changes}`. Shared helpers `_issue_provider_base`, `_github_repo_root`, `_gitlab_issues_root`, `forgeo_labels`, `extract_issue_number/labels`, `bump_state_counter` unify Jira/GitHub/GitLab handling.
20
+ - `config/forgeo.yaml` and `docs/configuration.md` document `review_mode` and `review_branch_prefix`; `mkdocs.yml` `site_description` updated.
21
+
22
+ ### Changed
23
+
24
+ - Docs restructured and condensed (~55% shorter) while preserving full coverage: `README`, `docs/agent-contract.md`, `docs/backlog.md`, `docs/cli-reference.md`, `docs/configuration.md`, `docs/getting-started.md`, `docs/index.md`, `docs/web-console-api.md` rewritten for scannability (tables, endpoint summary, concise curl examples).
25
+ - `docs/backlog.md`, `docs/configuration.md`, `docs/web-console-api.md`, and `README` document the new REVIEW workflow, `REVIEW` task lifecycle, and new `review`-related API fields.
26
+ - Internal maintainability refactor: `backlog.py` helpers `_require_string`/`_require_string_list`/`_status_by_id`/`_set_agent_response`/`_blocked_notice`/`_blocker_sections`/`_render_block`, `forgeo.py` split of blocker/commit logic, `models.py` `_IssueFieldMappingBase`/`_IssueBacklogConfigBase`/`_PatAuthBase`/`_IssueWorkflowBase`/`_RepoBacklogConfigBase` extraction, `IssueBacklogBase` shared `_call`/`_labels`/`_get_issue`/`_search_all`/`_task_from_issue`/`list_tasks`/`get_task`/`validate_connection`/`bump_failed_wait`/`_update_issue_labels`, `GitManager.ensure_branch`/`current_branch`/`create_review_branch`/`commit_all_on_branch` plus async wrappers, `central.py` `_github_web_base` exact-host rewrite and `_external_board_url`/`_external_issue_url` helpers, `config.py` `_maybe_resolve`, `validate.py`/`daemon.py`/`runs.py`/`paths.py`/`io.py`/`web_common.py`/`setup.py` lint-driven cleanups.
27
+
28
+ ### Fixed
29
+
30
+ - `ruff`/`mypy` compliance across the review branch (BLE001/S110/F541 suppressions in `setup.py`, type narrowing in `Forgeo`, `src/forgeo/backlog.py:21`, etc.); `pytest` green including new `REVIEW` column/counts and delete tests.
31
+
10
32
  ## [0.10.0] - 2026-08-24
11
33
 
12
34
  ### Added
@@ -407,7 +429,8 @@ Initial release of the scheduled, agent-driven software forgeo.
407
429
  overlapping-run skipping.
408
430
  - Dogfooding docs removed; local configs kept out of the repository.
409
431
 
410
- [Unreleased]: https://github.com/lucaGazzola/forgeo/compare/v0.10.0...HEAD
432
+ [Unreleased]: https://github.com/lucaGazzola/forgeo/compare/v0.11.0...HEAD
433
+ [0.11.0]: https://github.com/lucaGazzola/forgeo/compare/v0.10.0...v0.11.0
411
434
  [0.10.0]: https://github.com/lucaGazzola/forgeo/compare/v0.9.0...v0.10.0
412
435
  [0.9.0]: https://github.com/lucaGazzola/forgeo/compare/v0.8.0...v0.9.0
413
436
  [0.8.0]: https://github.com/lucaGazzola/forgeo/compare/v0.7.3...v0.8.0
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.5
2
+ Name: forgeo-cli
3
+ Version: 0.11.0
4
+ Summary: A scheduled software forgeo: executes backlog tasks on main, refactors when idle, and writes BLOCKER.md when it needs human input.
5
+ Project-URL: Homepage, https://forgeo.org
6
+ Project-URL: Documentation, https://forgeo.org
7
+ Project-URL: Repository, https://github.com/lucaGazzola/forgeo
8
+ Project-URL: Issues, https://github.com/lucaGazzola/forgeo/issues
9
+ Author: Forgeo Contributors
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Software Forgeo Contributors
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agents,ai,automation,backlog,orchestration,scheduler
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Topic :: Software Development :: Build Tools
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: pydantic>=2.5
43
+ Requires-Dist: pyyaml>=6.0
44
+ Requires-Dist: rich>=13.7
45
+ Provides-Extra: dev
46
+ Requires-Dist: mypy>=1.8; extra == 'dev'
47
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
48
+ Requires-Dist: pytest>=8.0; extra == 'dev'
49
+ Requires-Dist: ruff>=0.5; extra == 'dev'
50
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
51
+ Provides-Extra: docs
52
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
53
+ Description-Content-Type: text/markdown
54
+
55
+ <div align="center">
56
+ <img src="docs/img/logo.png" alt="Forgeo logo" width="128">
57
+ </div>
58
+
59
+ <div align="center">
60
+ <img src="docs/img/title.svg" alt="Forgeo" width="128">
61
+ </div>
62
+
63
+ [![CI](https://github.com/lucaGazzola/forgeo/actions/workflows/ci.yml/badge.svg)](https://github.com/lucaGazzola/forgeo/actions/workflows/ci.yml)
64
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
65
+
66
+ <div align="center">
67
+ <img src="docs/img/demo.gif" alt="Forgeo running a backlog task end to end" width="720">
68
+ </div>
69
+
70
+ **Forgeo is a software factory for your coding agent.**
71
+
72
+ Give it a backlog and an agent CLI — Forgeo picks the next runnable task, runs the agent, and commits the result. It tracks progress in plain files and a web dashboard, and only interrupts you when a human decision is needed.
73
+
74
+ - **One task at a time** — oldest `OPEN` task whose dependencies are `COMPLETED` (or a `run_at` schedule). `REVIEW` blocks dependants but not independent tasks.
75
+ - **Agent-agnostic** — any CLI that reads `FORGEO_TASK` (aider, Claude, custom script).
76
+ - **Refactors when idle** — runs a refactoring pass when the backlog is empty.
77
+ - **Handles failure gracefully** — `BLOCKED` for human input (`BLOCKER.md`), `FAILED` with retry policy, snapshots for file backlogs, Telegram/webhook notifications.
78
+ - **Optional review** — `review_mode: branch` commits to `forgeo/review/TASK-001`, marks `REVIEW`, pushes and waits for human merge → `Complete`.
79
+
80
+ Requires a terminal, a git repo, and an agent CLI.
81
+
82
+ ## Quickstart
83
+
84
+ Full walkthrough: [Getting Started](docs/getting-started.md).
85
+
86
+ ### 1. Install
87
+
88
+ Pick one (no root; re-run to upgrade):
89
+
90
+ ```bash
91
+ brew install lucaGazzola/forgeo/forgeo # Homebrew, no Python needed
92
+ curl -fsSL https://forgeo.org/install.sh | bash # binary or pip fallback
93
+ pipx install forgeo-cli # Python 3.11+
94
+ ```
95
+
96
+ ### 2. Init
97
+
98
+ ```bash
99
+ forgeo init
100
+ ```
101
+
102
+ Wizard in your project root. Creates `forgeo.yaml` and `.forgeo/` (backlog, logs, blockers). Prompts for backlog provider (`file` / `github` / `gitlab` / `jira` / `http`) and agent command. For `github` it auto-detects `owner/repo` and can persist `GITHUB_TOKEN` to `~/.config/forgeo/`.
103
+
104
+ ### 3. Fill the backlog
105
+
106
+ ```bash
107
+ # file provider: edit .forgeo/backlog.json (see Backlog format)
108
+ # github/gitlab/jira/http: configured in forgeo.yaml, then:
109
+ forgeo validate
110
+
111
+ # or add tasks from the dashboard:
112
+ forgeo web # http://0.0.0.0:8790 (use -d to keep it running)
113
+ ```
114
+
115
+ ![Forgeo web console](docs/img/console.png)
116
+
117
+ ### 4. Start
118
+
119
+ ```bash
120
+ forgeo validate # dry run: config, repo, backlog, agent, locks
121
+ forgeo start # daemon in background, one cycle per interval_minutes
122
+ ```
123
+
124
+ Each cycle: pick task → run agent → commit/push (or `REVIEW` branch when `review_mode: branch`). Empty backlog → refactoring pass.
125
+
126
+ ### Day-to-day
127
+
128
+ ```bash
129
+ forgeo status # config, counts, next task, daemon state, last outcome
130
+ forgeo once # one cycle in foreground, no daemon
131
+ forgeo run --task TASK-012 # run a specific OPEN task now
132
+ forgeo stop / restart # stop or restart daemon
133
+ forgeo web # dashboard for all instances
134
+ ```
135
+
136
+ `forgeo web` is open by default on `0.0.0.0:8790`. On a shared host use `forgeo web --token` for bearer auth — see [Web console](docs/web-console-api.md).
137
+
138
+ ### Docker sandbox
139
+
140
+ Run the agent isolated:
141
+
142
+ ```yaml
143
+ agent_sandbox: docker
144
+ agent_sandbox_image: your-image # must contain agent CLI + sh
145
+ agent_sandbox_network: none # default, no network
146
+ agent_sandbox_mounts: [~/.claude] # read-only mounts
147
+ ```
148
+
149
+ Repo is bind-mounted at the same path; task arrives as `FORGEO_TASK`. See [Configuration](docs/configuration.md).
150
+
151
+ ### Multiple repos
152
+
153
+ One config per repo, fully independent (own backlog, logs, locks). Use the instance registry:
154
+
155
+ ```bash
156
+ forgeo instance add site-a --config /path/to/site-a/forgeo.yaml
157
+ forgeo start --name site-a
158
+ forgeo list # all instances
159
+ forgeo web # aggregate dashboard
160
+ ```
161
+
162
+ ## Documentation
163
+
164
+ | Topic | Doc |
165
+ | --- | --- |
166
+ | Install, init, first cycle | [Getting Started](docs/getting-started.md) |
167
+ | All `forgeo.yaml` keys | [Configuration](docs/configuration.md) |
168
+ | Task schema & statuses | [Backlog format](docs/backlog.md) |
169
+ | Agent env, exit codes, timeouts | [Agent contract](docs/agent-contract.md) |
170
+ | All CLI commands | [CLI reference](docs/cli-reference.md) |
171
+ | Dashboard & HTTP API | [Web console & HTTP API](docs/web-console-api.md) |
172
+
173
+ **Backlog providers:** [file](docs/backlog.md#a-json-file-backlog) · [HTTP](docs/backlog.md#a-backlog-over-http) · [Jira](docs/backlog.md#a-jira-backlog) · [GitHub](docs/backlog.md#a-github-backlog) · [GitLab](docs/backlog.md#a-gitlab-backlog) — file/HTTP exchange the full document; Jira/GitHub/GitLab sync issues individually. File backlogs are snapshotted (`backlog.json.bak`) before each run and restored if corrupt.
174
+
175
+ **Dashboard:** `forgeo web` aggregates every instance. For `file`/`http` it is the primary editor; for `jira`/`github`/`gitlab` it is a read-mostly mirror (links to native issues, surfaces `BLOCKED`/`FAILED` reasons and retry state).
176
+
177
+ ## Develop
178
+
179
+ ```bash
180
+ pip install -e ".[dev]"
181
+ pytest
182
+ ```
183
+
184
+ See [CONTRIBUTING.md](CONTRIBUTING.md) (quality gates: `pytest`, `ruff check`, `mypy src/forgeo`).
185
+
186
+ ## License
187
+
188
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,134 @@
1
+ <div align="center">
2
+ <img src="docs/img/logo.png" alt="Forgeo logo" width="128">
3
+ </div>
4
+
5
+ <div align="center">
6
+ <img src="docs/img/title.svg" alt="Forgeo" width="128">
7
+ </div>
8
+
9
+ [![CI](https://github.com/lucaGazzola/forgeo/actions/workflows/ci.yml/badge.svg)](https://github.com/lucaGazzola/forgeo/actions/workflows/ci.yml)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+
12
+ <div align="center">
13
+ <img src="docs/img/demo.gif" alt="Forgeo running a backlog task end to end" width="720">
14
+ </div>
15
+
16
+ **Forgeo is a software factory for your coding agent.**
17
+
18
+ Give it a backlog and an agent CLI — Forgeo picks the next runnable task, runs the agent, and commits the result. It tracks progress in plain files and a web dashboard, and only interrupts you when a human decision is needed.
19
+
20
+ - **One task at a time** — oldest `OPEN` task whose dependencies are `COMPLETED` (or a `run_at` schedule). `REVIEW` blocks dependants but not independent tasks.
21
+ - **Agent-agnostic** — any CLI that reads `FORGEO_TASK` (aider, Claude, custom script).
22
+ - **Refactors when idle** — runs a refactoring pass when the backlog is empty.
23
+ - **Handles failure gracefully** — `BLOCKED` for human input (`BLOCKER.md`), `FAILED` with retry policy, snapshots for file backlogs, Telegram/webhook notifications.
24
+ - **Optional review** — `review_mode: branch` commits to `forgeo/review/TASK-001`, marks `REVIEW`, pushes and waits for human merge → `Complete`.
25
+
26
+ Requires a terminal, a git repo, and an agent CLI.
27
+
28
+ ## Quickstart
29
+
30
+ Full walkthrough: [Getting Started](docs/getting-started.md).
31
+
32
+ ### 1. Install
33
+
34
+ Pick one (no root; re-run to upgrade):
35
+
36
+ ```bash
37
+ brew install lucaGazzola/forgeo/forgeo # Homebrew, no Python needed
38
+ curl -fsSL https://forgeo.org/install.sh | bash # binary or pip fallback
39
+ pipx install forgeo-cli # Python 3.11+
40
+ ```
41
+
42
+ ### 2. Init
43
+
44
+ ```bash
45
+ forgeo init
46
+ ```
47
+
48
+ Wizard in your project root. Creates `forgeo.yaml` and `.forgeo/` (backlog, logs, blockers). Prompts for backlog provider (`file` / `github` / `gitlab` / `jira` / `http`) and agent command. For `github` it auto-detects `owner/repo` and can persist `GITHUB_TOKEN` to `~/.config/forgeo/`.
49
+
50
+ ### 3. Fill the backlog
51
+
52
+ ```bash
53
+ # file provider: edit .forgeo/backlog.json (see Backlog format)
54
+ # github/gitlab/jira/http: configured in forgeo.yaml, then:
55
+ forgeo validate
56
+
57
+ # or add tasks from the dashboard:
58
+ forgeo web # http://0.0.0.0:8790 (use -d to keep it running)
59
+ ```
60
+
61
+ ![Forgeo web console](docs/img/console.png)
62
+
63
+ ### 4. Start
64
+
65
+ ```bash
66
+ forgeo validate # dry run: config, repo, backlog, agent, locks
67
+ forgeo start # daemon in background, one cycle per interval_minutes
68
+ ```
69
+
70
+ Each cycle: pick task → run agent → commit/push (or `REVIEW` branch when `review_mode: branch`). Empty backlog → refactoring pass.
71
+
72
+ ### Day-to-day
73
+
74
+ ```bash
75
+ forgeo status # config, counts, next task, daemon state, last outcome
76
+ forgeo once # one cycle in foreground, no daemon
77
+ forgeo run --task TASK-012 # run a specific OPEN task now
78
+ forgeo stop / restart # stop or restart daemon
79
+ forgeo web # dashboard for all instances
80
+ ```
81
+
82
+ `forgeo web` is open by default on `0.0.0.0:8790`. On a shared host use `forgeo web --token` for bearer auth — see [Web console](docs/web-console-api.md).
83
+
84
+ ### Docker sandbox
85
+
86
+ Run the agent isolated:
87
+
88
+ ```yaml
89
+ agent_sandbox: docker
90
+ agent_sandbox_image: your-image # must contain agent CLI + sh
91
+ agent_sandbox_network: none # default, no network
92
+ agent_sandbox_mounts: [~/.claude] # read-only mounts
93
+ ```
94
+
95
+ Repo is bind-mounted at the same path; task arrives as `FORGEO_TASK`. See [Configuration](docs/configuration.md).
96
+
97
+ ### Multiple repos
98
+
99
+ One config per repo, fully independent (own backlog, logs, locks). Use the instance registry:
100
+
101
+ ```bash
102
+ forgeo instance add site-a --config /path/to/site-a/forgeo.yaml
103
+ forgeo start --name site-a
104
+ forgeo list # all instances
105
+ forgeo web # aggregate dashboard
106
+ ```
107
+
108
+ ## Documentation
109
+
110
+ | Topic | Doc |
111
+ | --- | --- |
112
+ | Install, init, first cycle | [Getting Started](docs/getting-started.md) |
113
+ | All `forgeo.yaml` keys | [Configuration](docs/configuration.md) |
114
+ | Task schema & statuses | [Backlog format](docs/backlog.md) |
115
+ | Agent env, exit codes, timeouts | [Agent contract](docs/agent-contract.md) |
116
+ | All CLI commands | [CLI reference](docs/cli-reference.md) |
117
+ | Dashboard & HTTP API | [Web console & HTTP API](docs/web-console-api.md) |
118
+
119
+ **Backlog providers:** [file](docs/backlog.md#a-json-file-backlog) · [HTTP](docs/backlog.md#a-backlog-over-http) · [Jira](docs/backlog.md#a-jira-backlog) · [GitHub](docs/backlog.md#a-github-backlog) · [GitLab](docs/backlog.md#a-gitlab-backlog) — file/HTTP exchange the full document; Jira/GitHub/GitLab sync issues individually. File backlogs are snapshotted (`backlog.json.bak`) before each run and restored if corrupt.
120
+
121
+ **Dashboard:** `forgeo web` aggregates every instance. For `file`/`http` it is the primary editor; for `jira`/`github`/`gitlab` it is a read-mostly mirror (links to native issues, surfaces `BLOCKED`/`FAILED` reasons and retry state).
122
+
123
+ ## Develop
124
+
125
+ ```bash
126
+ pip install -e ".[dev]"
127
+ pytest
128
+ ```
129
+
130
+ See [CONTRIBUTING.md](CONTRIBUTING.md) (quality gates: `pytest`, `ruff check`, `mypy src/forgeo`).
131
+
132
+ ## License
133
+
134
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,78 @@
1
+ # Agent contract
2
+
3
+ The coding agent is **any shell command** that can:
4
+
5
+ 1. Read the task from `FORGEO_TASK`.
6
+ 2. Work on the repository in the current directory.
7
+ 3. Report its outcome via **exit code**.
8
+
9
+ ```yaml
10
+ agent_command: "claude -p \"$FORGEO_TASK\""
11
+ ```
12
+
13
+ ## Environment
14
+
15
+ Launched with the repo as cwd and:
16
+
17
+ | Variable | Value |
18
+ | --- | --- |
19
+ | `FORGEO_TASK` | Full instruction — project context (if `task_context`), title, description, and "Acceptance criteria:" when present. |
20
+ | `FORGEO_REPO` | Absolute repo path. |
21
+ | `FORGEO_BRANCH` | Target branch (default `main`). |
22
+ | `agent_env` keys | Extra vars from config. |
23
+ | Inherited env | Daemon's own environment. |
24
+
25
+ `FORGEO_*` always wins. For refactoring runs (empty backlog), `FORGEO_TASK` carries the `refactor_prompt` (task ID `REFACTOR`).
26
+
27
+ When `task_context` is set, its file contents are prepended under `# Project context` before `# Task`. Re-read each run; missing file is a warning.
28
+
29
+ ## Exit codes
30
+
31
+ | Code | Outcome | What happens |
32
+ | --- | --- | --- |
33
+ | `0` | **SUCCESS** | `git add -A && git commit` as `<title> (#<id>)`, push if `remote` set, task → `COMPLETED`. |
34
+ | `no_changes_exit_code` (default `3`) | **SUCCESS, no changes** | Task → `COMPLETED` without commit. Tree must be clean. |
35
+ | `blocked_exit_code` (default `2`) | **BLOCKED** | Partial work committed as `<title> [partial]`, `blocker_reason` saved, notifications sent, task → `BLOCKED`, `BLOCKER.md` rendered next cycle. |
36
+ | anything else | **ERROR** | Changes discarded (`git reset --hard` + `clean -fd`), task → `FAILED`, `failure_reason` saved. |
37
+
38
+ `FAILED` stays `FAILED` until human reopens (or auto-retried via `failed_retry_max`). `BLOCKED` is never auto-retried.
39
+
40
+ ## The no-change contract
41
+
42
+ Forgeo cannot distinguish "deliberately no changes" from "did nothing":
43
+
44
+ - Exit `0` with **unchanged tree** → retried `no_changes_retry_max` times in the same cycle, then `BLOCKED` (never `FAILED` or silent `COMPLETED`).
45
+ - To complete without code change, exit `no_changes_exit_code` with a **clean tree**. Reporting no-change while leaving uncommitted work → `FAILED`.
46
+
47
+ Refactoring passes are exempt — a refactor finding nothing to improve is a normal success.
48
+
49
+ ## Timeouts
50
+
51
+ `agent_timeout_seconds` kills the agent after N seconds (`error: timed out after <n>s`). Unset = no timeout. A run overrunning `interval_minutes` is never killed — the next cycle is skipped. Tip: leave unset for long agents and rely on skip-on-overlap.
52
+
53
+ ## Output
54
+
55
+ Stdout/stderr are prefixed `[stdout]`/`[stderr]` and the last **1000 lines** are kept. On `BLOCKED`, the agent's questions (or output) become `blocker_reason` and the `BLOCKER.md` section (last 10 lines). Per-run tails go to `runs.jsonl` (`run_output_lines`); per-task `agent_response` is bounded by `agent_response_lines`.
56
+
57
+ ## Git contract
58
+
59
+ The agent should **not** run `git` itself — Forgeo handles it:
60
+
61
+ - Make changes in the repo.
62
+ - Do not `git add`/`commit`/`push`/`reset`.
63
+ - Exit `0` for commit, `no_changes_exit_code` for intentional no-op, `blocked_exit_code` for human input, anything else for discard.
64
+
65
+ Embed the contract in your prompt:
66
+
67
+ ```yaml
68
+ agent_command: >
69
+ opencode run --auto "Work on the repository at the current working directory.
70
+ Make the requested changes and nothing else. Do NOT run git commit/push/add.
71
+ Verify with tests. Read AGENTS.md and CONTEXT.md if present; update them
72
+ if your change affects the overview.
73
+ $FORGEO_TASK"
74
+ ```
75
+
76
+ ## Concurrency
77
+
78
+ One agent per Forgeo: `backlog.lock` prevents a second `start`/`once`, and `backlog.run` makes a waking daemon skip while a run is active.
@@ -0,0 +1,217 @@
1
+ # Backlog format
2
+
3
+ The backlog is a **plain JSON document** — a list of tasks Forgeo works through one by one. It can live as:
4
+
5
+ - [JSON file](#a-json-file-backlog) — local file
6
+ - [HTTP endpoint](#a-backlog-over-http) — another app serving the same document
7
+ - [Jira](#a-jira-backlog) / [GitHub](#a-github-backlog) / [GitLab](#a-gitlab-backlog) — native issues
8
+
9
+ ## A JSON file backlog
10
+
11
+ Default is a file wherever `backlog:` points (`backlog.json` or `.forgeo/backlog.json` from `forgeo init`). Keep it outside the repo if possible.
12
+
13
+ ```json
14
+ {
15
+ "tasks": [
16
+ {
17
+ "id": "TASK-001",
18
+ "title": "Implement fibonacci module",
19
+ "description": "Write a fibonacci module with memoization and tests.",
20
+ "status": "OPEN",
21
+ "created_at": "2026-07-31T10:00:00Z"
22
+ }
23
+ ]
24
+ }
25
+ ```
26
+
27
+ ## Task schema
28
+
29
+ | Field | Type | Default | Description |
30
+ | --- | --- | --- | --- |
31
+ | `id` | string | — | Unique task ID. Duplicates rejected. |
32
+ | `title` | string | — | Short title (logs, commits, status). |
33
+ | `description` | string | — | Full instruction for the agent. Must be non-blank. |
34
+ | `status` | `OPEN`/`REVIEW`/`BLOCKED`/`COMPLETED`/`FAILED` | `OPEN` | Task state. |
35
+ | `created_at` | ISO-8601 | now (UTC) | Creation time; controls oldest-first order. |
36
+ | `updated_at` | ISO-8601 | now (UTC) | Bumped on status changes. |
37
+ | `run_at` | ISO-8601 / `null` | `null` | One-shot schedule — earliest pick time. Past = fire now; future = wait. |
38
+ | `dependencies` | string[] | `[]` | Task IDs that must be `COMPLETED` first (`REVIEW` not satisfied). |
39
+ | `acceptance_criteria` | string[] | `[]` | Rendered under "Acceptance criteria:" in `FORGEO_TASK`. |
40
+ | `files_to_modify` | string[] | `[]` | Hint for the agent. |
41
+ | `agent_command` | string / string[] | — | Per-task agent override. |
42
+ | `agent_timeout_seconds` | number | — | Per-task timeout override. |
43
+ | `blocker_reason` | string[] | `[]` | Engine-managed: reason when `BLOCKED`. |
44
+ | `blocked_count` | int | `0` | Engine-managed: times transitioned to `BLOCKED`. |
45
+ | `failure_reason` | string[] | `[]` | Engine-managed: error when `FAILED`. |
46
+ | `agent_response` | string / `null` | `null` | Engine-managed: agent output on transitions. |
47
+ | `retries_left` | int / `null` | `null` | Per-task retry budget override (`null` = config default, `0` = no retries). |
48
+ | `retry_count` | int | `0` | Engine-managed: retries already attempted. |
49
+ | `failed_wait_cycles` | int | `0` | Engine-managed: cycles waiting for retry. |
50
+ | `review_required` | bool / `null` | `null` | Per-task review override (`null` = inherit `review_mode`). |
51
+ | `review_branch` | string / `null` | `null` | Engine-managed: feature branch for `REVIEW`. |
52
+ | `review_commit_sha` | string / `null` | `null` | Engine-managed: commit SHA on review branch. |
53
+
54
+ Only `id`, `title`, `description` are required.
55
+
56
+ ### Per-task agent routing
57
+
58
+ ```json
59
+ {
60
+ "tasks": [
61
+ {"id": "TASK-001", "title": "Add docstrings", "agent_command": "claude -p \"$FORGEO_TASK\" --model haiku"},
62
+ {"id": "TASK-002", "title": "Rearchitect cache", "agent_command": "claude -p \"$FORGEO_TASK\" --model opus"}
63
+ ]
64
+ }
65
+ ```
66
+
67
+ ## Statuses
68
+
69
+ | Status | Meaning |
70
+ | --- | --- |
71
+ | `OPEN` | To be picked. |
72
+ | `REVIEW` | Awaiting human review on feature branch; blocks dependants, not independent tasks. |
73
+ | `BLOCKED` | Needs human decision; Forgeo pauses. |
74
+ | `COMPLETED` | Agent finished, committed and pushed (or review approved). |
75
+ | `FAILED` | Agent errored; changes discarded, `failure_reason` recorded. |
76
+
77
+ ### Review workflow
78
+
79
+ With `review_mode: branch` (and per-task `review_required` override) a successful task is committed on `review_branch_prefix + id` (default `forgeo/review/TASK-001`), pushed if `remote` set, and marked `REVIEW`. Independent `OPEN` tasks continue; dependants wait until `REVIEW` → `COMPLETED`.
80
+
81
+ Human merges the branch manually (PR or `git merge`), then marks **Complete** (`POST .../tasks/<id>/complete-review` → `COMPLETED`, clears `review_branch/sha`) or **Request changes** (`POST .../tasks/<id>/request-changes` → `OPEN`). `REVIEW` tasks are deletable and show `review_branch`/`review_commit_sha`. Issue providers use label `forgeo-review`.
82
+
83
+ ### Retrying failed tasks
84
+
85
+ With `failed_retry_max` set, a `FAILED` task is moved back to `OPEN` after `failed_retry_wait_cycles` cycles and `retry_count` is incremented. Exhausted tasks stay `FAILED`. `BLOCKED` is never auto-retried.
86
+
87
+ Per-task override via `retries_left`:
88
+
89
+ ```json
90
+ {"id": "TASK-001", "title": "Flaky test", "retries_left": 0},
91
+ {"id": "TASK-002", "title": "Migrate cache", "retries_left": 3}
92
+ ```
93
+
94
+ Retry state is visible in `runs.jsonl` and the dashboard (task card/modal, History **retry** column). Reopening a `FAILED` task manually (edit backlog or dashboard) resets `retry_count`.
95
+
96
+ ### Resolving blocked tasks
97
+
98
+ On `BLOCKED`, Forgeo commits partial work as `[partial]` and records `blocker_reason`. `BLOCKER.md` is a derived view — re-rendered each cycle, auto-removed when no `BLOCKED` tasks remain.
99
+
100
+ Reopen via dashboard (**Reopen** button) or `POST /api/.../tasks/<id>/reopen` — clears `blocker_reason`, keeps `blocked_count`. Editing the file's `status` back to `OPEN` does *not* clear `blocker_reason`; prefer the Reopen action.
101
+
102
+ ### Resolving review tasks
103
+
104
+ On `REVIEW`, code is on the feature branch. Merge manually, then **Complete** (`POST .../tasks/<id>/complete-review`) or **Request changes** (`POST .../tasks/<id>/request-changes` → `OPEN`). Webhook `review` event fires on entry to `REVIEW` when enabled.
105
+
106
+ ## Picking order
107
+
108
+ Forgeo picks the **oldest runnable `OPEN` task** — smallest `created_at` whose dependencies are all `COMPLETED` (`REVIEW` does not satisfy) and whose `run_at` is not in the future.
109
+
110
+ - `run_at` in the **past** → picked before tasks without `run_at` (most overdue first); daemon wakes early for it.
111
+ - `run_at` in the **future** → skipped until that moment; daemon sleeps only until then.
112
+ - `null` / omitted → plain oldest-first.
113
+ - Dependencies: missing or non-`COMPLETED` dependencies keep the task waiting forever. Surfaced in `forgeo status` (`waiting on:`) and the dashboard's *Waiting on dependencies* banner.
114
+
115
+ ## One-shot scheduling
116
+
117
+ ```json
118
+ {"id": "TASK-001", "title": "Regenerate docs", "run_at": "2026-08-21T09:00:00Z"}
119
+ ```
120
+
121
+ Use for time-sensitive work ("run after deploy"). Ignored for non-`OPEN` tasks or tasks with unmet dependencies. Set/clear via dashboard Create/Edit forms (`PATCH`).
122
+
123
+ ## Dependencies
124
+
125
+ ```json
126
+ {"id": "TASK-003", "title": "Deploy", "dependencies": ["TASK-001", "TASK-002"]}
127
+ ```
128
+
129
+ Oldest-first among *runnable* tasks — if the oldest `OPEN` task is blocked, the next runnable one is picked. Cyclic or permanently blocked dependencies yield no runnable task → refactoring pass until resolved.
130
+
131
+ ## Execution
132
+
133
+ Once picked, the task goes to the agent as `FORGEO_TASK`; exit code decides commit/push vs `BLOCKED` vs discarded. See [Agent contract](agent-contract.md).
134
+
135
+ ## File backlog: corruption tolerance & snapshots
136
+
137
+ - Missing file → empty backlog (created on first write).
138
+ - Corrupt file → renamed to `backlog.json.corrupt-<timestamp>`, restored from newest valid snapshot or empty.
139
+ - Unparsable row → kept as `FAILED` placeholder, not a store failure.
140
+ - Before every agent run (and on daemon start), the backlog is copied to `backlog.json.bak` / `backlog.json.bak.1` (rotating, keeps last 2). On corrupt read, newest valid snapshot is restored. No snapshots for remote backlogs.
141
+
142
+ ## A backlog over HTTP
143
+
144
+ ```yaml
145
+ backlog: https://api.example.com/backlog
146
+ ```
147
+
148
+ | Operation | Request |
149
+ | --- | --- |
150
+ | Every read | `GET <url>` returns `{"tasks": [...]}` |
151
+ | Every write | `POST <url>` sends the full document |
152
+
153
+ Add `backlog_auth` for OAuth2. Same schema and ordering. Endpoint must:
154
+
155
+ - Return `{"tasks": [...]}`; non-object or non-list → empty.
156
+ - Replace, not append — POST body is the complete list.
157
+ - Send dates as ISO-8601 strings (not epoch numbers).
158
+ - Never send `null` for list fields.
159
+ - Preserve `agent_command` shape (string vs list).
160
+ - Store and return engine fields (`status`, `blocker_reason`, `failure_reason`, etc.).
161
+
162
+ A failed request fails the cycle (retried next interval), never treated as empty — otherwise a `POST` would overwrite the remote with nothing. Dashboard shows `502` for unreachable instances.
163
+
164
+ Runtime files (`backlog.lock`, `runs.jsonl`, etc.) go in `state_dir` (defaults to config dir).
165
+
166
+ ## A Jira backlog
167
+
168
+ ```yaml
169
+ backlog_provider: jira
170
+ backlog: https://jira.example.com
171
+ jira:
172
+ jql: 'project = APP AND labels = forgeo'
173
+ project_key: APP
174
+ auth: {scheme: basic, username_env: JIRA_USER, token_env: JIRA_TOKEN}
175
+ workflow: {open_statuses: ["10000", "10001"], open_status: "10000", running_status: "3", completed_status: "10002"}
176
+ ```
177
+
178
+ - Jira keys → task IDs; `summary`/`description`/`created`/`updated` → task fields.
179
+ - `open_statuses` = pickable; `running_status` = claimed before agent runs; `completed_status`/`blocked_status`/`failed_status` = terminal (blocked/failed optional — labels `forgeo-blocked`/`forgeo-failed` always applied).
180
+ - Engine state (`blocker_reason`, `retry_count`, `agent_response`, etc.) in Jira issue property `forgeo`.
181
+ - Optional `jira.fields` maps custom fields for `acceptance_criteria`, `dependencies`, etc. Without `run_at` mapping, Jira `duedate` is used at midnight UTC. Dependencies also inferred from `blocks` issue links.
182
+ - Auth from env vars: `basic` (username + token) or `bearer` (PAT). Uses REST API v3 (`/search/jql` + cursor) by default; set `api_version: 2` for older servers.
183
+ - Daemon paginates JQL; stale claims released after `claim_timeout_seconds`. Unavailable Jira fails the cycle.
184
+
185
+ ## A GitHub backlog
186
+
187
+ ```yaml
188
+ backlog_provider: github
189
+ backlog: https://api.github.com # or https://github.example.com/api/v3
190
+ github: {repo: owner/repo, token_env: GITHUB_TOKEN}
191
+ ```
192
+
193
+ - Issue numbers → task IDs; `title`/`body`/`created_at`/`updated_at` → task fields.
194
+ - `open` → `OPEN`, `closed` → `COMPLETED`; labels `forgeo-running`/`blocked`/`failed` for the rest.
195
+ - Engine state in hidden `<!-- forgeo: {...} -->` block inside the body.
196
+ - Paginated `GET /repos/{owner}/{repo}/issues?state=all`; claiming adds `forgeo-running` + `claimed_at`.
197
+
198
+ Test live with `scripts/test-github-backlog-e2e.sh`:
199
+
200
+ ```bash
201
+ GITHUB_TOKEN=... ./scripts/test-github-backlog-e2e.sh
202
+ ```
203
+
204
+ ## A GitLab backlog
205
+
206
+ ```yaml
207
+ backlog_provider: gitlab
208
+ backlog: https://gitlab.example.com # instance root, /api/v4 appended
209
+ gitlab: {repo: group/project, token_env: GITLAB_TOKEN}
210
+ ```
211
+
212
+ - `iid` → task ID; `opened`/`closed` → `OPEN`/`COMPLETED`; same hidden-block and label mechanics as GitHub.
213
+ - Paginated `GET /api/v4/projects/:id/issues?state=all`.
214
+
215
+ ## Managing tasks
216
+
217
+ Edit the file directly, or use the dashboard: **Create** form (`POST /api/instances/<name>/tasks` → auto `WEB-###` ID, `review_required` checkbox), task modal **Edit** (`PATCH` including `review_required`), **Delete** (`DELETE` for `OPEN`/`BLOCKED`/`REVIEW`), **Reopen** for `BLOCKED`, **Complete** / **Request changes** for `REVIEW`. For `jira`/`github`/`gitlab` the dashboard is a read-mostly mirror with links to native issues and banners to the native board.