diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b617446 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,29 @@ +version: 2 + +updates: + - package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + day: monday + groups: + minor-and-patch: + update-types: + - minor + - patch + labels: + - dependencies + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + day: monday + groups: + actions-minor-patch: + update-types: + - minor + - patch + labels: + - dependencies + - github-actions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e021b59 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + version: "latest" + + - name: Set up Python ${{ matrix.python-version }} + run: uv python install ${{ matrix.python-version }} + + - name: Install dependencies + run: uv sync --extra dev + + - name: Run tests with coverage + run: uv run pytest --cov=src/foreman --cov-report=xml --cov-report=term-missing + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + if: matrix.python-version == '3.11' + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + fail_ci_if_error: false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..5753120 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,155 @@ +name: Publish to PyPI + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+a[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+b[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+" + workflow_dispatch: + inputs: + target: + description: "Publish target" + required: true + default: "testpypi" + type: choice + options: + - testpypi + - pypi + +jobs: + test: + name: Test before publish + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + version: "latest" + + - name: Run tests + run: | + uv python install 3.11 + uv sync --extra dev + uv run pytest + + build: + name: Build distribution + runs-on: ubuntu-latest + needs: test + outputs: + version: ${{ steps.version.outputs.version }} + is_prerelease: ${{ steps.version.outputs.is_prerelease }} + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + version: "latest" + + - name: Extract version + id: version + run: | + VERSION=$(uv run python -c "import tomllib; d=tomllib.loads(open('pyproject.toml').read()); print(d['project']['version'])") + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + if [[ "$VERSION" =~ (a|b|rc)[0-9]+ ]]; then + echo "is_prerelease=true" >> "$GITHUB_OUTPUT" + else + echo "is_prerelease=false" >> "$GITHUB_OUTPUT" + fi + + - name: Assert tag matches pyproject.toml version + if: startsWith(github.ref, 'refs/tags/') + run: | + TAG="${GITHUB_REF_NAME#v}" + PKG="${{ steps.version.outputs.version }}" + if [ "$TAG" != "$PKG" ]; then + echo "Tag $TAG does not match pyproject.toml version $PKG" >&2 + exit 1 + fi + + - name: Build sdist and wheel + run: uv build + + - name: Validate with twine + run: | + uv run --with twine twine check dist/* + + - name: Upload dist artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + publish-testpypi: + name: Publish to TestPyPI + runs-on: ubuntu-latest + needs: build + if: | + needs.build.outputs.is_prerelease == 'true' || + github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi' + environment: + name: testpypi + url: https://test.pypi.org/p/foreman-orchestrator + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Publish to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + + publish-pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + needs: build + if: | + startsWith(github.ref, 'refs/tags/') && + needs.build.outputs.is_prerelease == 'false' + environment: + name: pypi + url: https://pypi.org/p/foreman-orchestrator + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: [build, publish-pypi] + if: startsWith(github.ref, 'refs/tags/') && needs.build.outputs.is_prerelease == 'false' + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: "v${{ needs.build.outputs.version }}" + generate_release_notes: true + files: dist/* + prerelease: false diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b65d6..9f14bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## 0.6.0 +All notable changes to this project are documented here. +Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); +versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.6.0] - 2026-05-01 ### Added — WS7: skills-suite expansion (4 worker skills + 2 read-only gate agents) Vendored six new capabilities, sourced from obra/superpowers (MIT) and Anthropic's @@ -27,7 +33,7 @@ suite is green (368 tests). stages that reuse the existing bounce/escalate policy; config gained their enable/model/budget knobs; `foreman init` installs all six new files. -## 0.5.0 +## [0.5.0] - 2026-04-25 ### Changed (internal architecture — no behaviour change) Eight behaviour-preserving deepenings from an architecture review; the full suite @@ -49,7 +55,13 @@ Eight behaviour-preserving deepenings from an architecture review; the full suit - **`StreamEvent`** exposes `is_assistant` / `is_result` / `made_progress`; CLI tool-name knowledge lives behind the parser, so the TUI survives schema drift. -## 0.4.12 +## [0.4.13] - 2026-04-18 + +### Added +- Validate human checkpoints H4–H7 via TUI/controller integration tests; wire + amendment-reject path and retro review screen (see 0.4.12 bug fixes B5/B6/B7). + +## [0.4.12] - 2026-04-18 ### Fixed - **Worker could bypass the verification.json/issue-file deny hook via MCP tools.** The @@ -62,8 +74,7 @@ Eight behaviour-preserving deepenings from an architecture review; the full suit protected paths are denied while reads and unprotected writes are allowed. Verified end-to-end: a real worker's `ctx_edit` of `verification.json` is blocked. - -## 0.4.11 +## [0.4.11] - 2026-04-18 ### Fixed - **False `stuck: no file/test progress` when the worker uses MCP tools.** The stuck @@ -73,20 +84,17 @@ Eight behaviour-preserving deepenings from an architecture review; the full suit killed after `stuck_turns` turns despite actively working. Any `mcp__*` tool call now counts as progress; pure rumination (no tool calls) is still caught. - -## 0.4.10 +## [0.4.10] - 2026-04-11 ### Fixed - **Plan revise loop ignored the reviewer's comment (found in checkpoint H1).** When you requested changes on a plan and re-ran the planner, `run_planner` rebuilt the prompt from the *original* feature request only — it never passed the reviewer's comment or the prior - plan (unlike the grill loop). It appeared to work because the planner happened to read - `.foreman/reviews/` while exploring the repo, but that's incidental and unreliable. The - planner now receives the prior plan + the latest `request_changes` comment, is told to - address every comment and keep earlier requirements, and appends a `## Changelog`. - + plan (unlike the grill loop). The planner now receives the prior plan + the latest + `request_changes` comment, is told to address every comment and keep earlier requirements, + and appends a `## Changelog`. -## 0.4.9 +## [0.4.9] - 2026-04-11 ### Changed - **Vendored skills/agents auto-refresh — no more manual `foreman init` after an @@ -94,187 +102,147 @@ Eight behaviour-preserving deepenings from an architecture review; the full suit `.claude/agents/foreman-*` go stale (status shows `[outdated]` with a ✗). Builds and pipeline phases now bring those Foreman-owned files current in place (idempotent; they're git-excluded so they don't touch your history). A genuinely *missing* required - skill is still a hard error (not silently reinstalled). Outdated never blocked a build — - it was only a stale status — but you no longer have to re-init each upgrade. + skill is still a hard error (not silently reinstalled). - -## 0.4.8 +## [0.4.8] - 2026-04-11 ### Fixed - **`foreman-tdd skill is not registered` (worker then went `stuck`).** Issue worktrees are forked from the integration branch, which usually does NOT have the vendored `foreman-*` skills/agents committed — `foreman init` installs them into the repo's working tree, but they're typically left untracked, so a fresh worktree had no - `.claude/skills/`. The worker couldn't load `foreman-tdd` (and the evaluator couldn't - run as `foreman-evaluator`), floundered, and got killed for no progress. Foreman now - provisions the vendored skills + agents into each issue worktree, git-excluded - (`.claude/skills/foreman-*`, `.claude/agents/foreman-*`) so they never leak into a - merge. (Earlier cheaper models silently ignored the skill and coded directly; stricter - models correctly errored.) - + `.claude/skills/`. Foreman now provisions the vendored skills + agents into each issue + worktree, git-excluded so they never leak into a merge. -## 0.4.7 +## [0.4.7] - 2026-04-11 ### Fixed - **`working directory does not exist … (worktree creation may have failed)` during a - run.** `_work_issue` created the issue worktree *before* taking the per-issue lock, - and the worktree path is shared per issue id. When a second worker grabbed the same - issue (a resume overlapping a build, or two builds), its `create_issue_worktree` - removed and recreated the **live** worker's worktree, then removed it again on - backoff — so the first worker's evaluator (or worker) found its cwd gone. The lock is - now acquired **before** any worktree work, so a second worker backs off cleanly and - the live worktree is never touched. (Worktree/hook setup failures release the lock - too, so it can't leak.) + run.** `_work_issue` created the issue worktree *before* taking the per-issue lock. + When a second worker grabbed the same issue, it removed and recreated the live + worker's worktree — so the first worker's evaluator found its cwd gone. The lock is + now acquired **before** any worktree work. - -## 0.4.6 +## [0.4.6] - 2026-04-04 ### Fixed -- **Run errored with `ValueError: ... chunk is longer than limit`.** Foreman reads the - `claude` subprocess output line by line, but asyncio's default stream buffer is only - 64 KiB — a single large stream-json event (a big tool result, a file read, a large - diff — common for the evaluator) overflowed it and killed the run. The reader now - uses a 64 MiB limit and, as a backstop, skips an over-limit line and keeps reading - instead of crashing the whole run. - +- **Run errored with `ValueError: ... chunk is longer than limit`.** asyncio's default + stream buffer is 64 KiB; a single large stream-json event overflowed it and killed the + run. The reader now uses a 64 MiB limit and skips an over-limit line instead of + crashing. -## 0.4.5 +## [0.4.5] - 2026-04-04 ### Fixed - **TUI crash rendering worker logs with brackets** (`MarkupError: Expected markup - value …`). Worker log lines are raw agent output (shell commands) and routinely - contain an unbalanced `[` (e.g. a truncated `if [ -f …`). They were passed straight - to `Static.update()`, which parses content as Textual markup, so an unclosed bracket - crashed the Workers screen. All agent/file-derived text shown in the TUI (worker log, - global log, status bar, escalation detail, doc open-questions/digest) is now escaped; - intentional markup is preserved. - + value …`). Worker log lines are raw agent output and routinely contain an unbalanced + `[`. All agent/file-derived text shown in the TUI is now escaped; intentional markup + is preserved. -## 0.4.4 +## [0.4.4] - 2026-04-04 ### Changed -- **Evaluator grounds its verdict in the current worktree (→ agent v3).** Investigating - a stuck issue showed the evaluator objecting to "remove duplicate file X" that the - worker had *already removed* — it over-explored (read 10+ files), ran out of turns, - and the turn-extension resume emitted the verdict from stale context. (The worker and - evaluator worktrees were verified identical — same cwd — so this was a grading-accuracy - issue, not a worktree mismatch.) The evaluator now starts from the diff, reads only the - files it touches, and must confirm a file's CURRENT state before objecting about it. - Re-run `foreman init` in a target repo to pick up the improved evaluator agent. +- **Evaluator grounds its verdict in the current worktree (→ agent v3).** The evaluator + now starts from the diff, reads only the files it touches, and must confirm a file's + current state before objecting about it. Re-run `foreman init` to pick up the improved + evaluator agent. - -## 0.4.3 +## [0.4.3] - 2026-04-04 ### Fixed - **Endless builder↔evaluator loop: a `pass` verdict with a noted nit was rejected.** - `Verdict.is_pass` required an *empty* objections list, so when the evaluator returned - `verdict: "pass"` but listed a minor suggestion, Foreman treated it as a failure and - bounced the work to a fresh builder — which the evaluator then re-nitpicked, forever. - `is_pass` now trusts the `verdict` field (objections on a `pass` are advisory) and - keeps the rubric-score guardrail. The evaluator agent prompt (→ v2) was also - recalibrated: pass when the acceptance check passes and every dimension ≥ 3/5; - reserve `objections` for concrete, blocking defects, not stylistic nitpicks. - Re-run `foreman init` in a target repo to pick up the improved evaluator agent. + `Verdict.is_pass` now trusts the `verdict` field (advisory objections on a `pass` no + longer block). Evaluator agent prompt recalibrated to v2: pass when acceptance check + passes and every dimension ≥ 3/5; `objections` reserved for blocking defects only. -## 0.4.2 +## [0.4.2] - 2026-04-04 ### Fixed -- **Crash after answering an escalation when you navigate away.** The "resume" runs in - a background worker; when it finished it called `refresh_escs()`, which queried the - `#elist` widget. If the resume outlived the Attention screen (long resume + you left - the screen), the widget was gone → `NoMatches` crashed the app. `refresh_escs` now - bails if its widgets are gone (`is_mounted` is unreliable here), and the resume result - is surfaced via the app (which always outlives the screen). +- **Crash after answering an escalation when you navigate away.** `refresh_escs` now + bails if its widgets are gone; resume result is surfaced via the app instead. -## 0.4.1 +## [0.4.1] - 2026-04-04 ### Fixed -- **Attention screen: "Answer & resume" was bound to Enter, conflicting with the - answer box.** Enter is needed for newlines in the answer TextArea (and selection in - the escalation list), so submitting was ambiguous and unreliable depending on focus. - Submit is now **Ctrl+S** (a priority binding that works whether or not the answer box - is focused); Enter stays a plain newline. "Next escalation" moved from Tab to Ctrl+N - so Tab can move focus normally. The answer-box label shows the keys. +- **Attention screen: "Answer & resume" was bound to Enter, conflicting with the answer + box.** Submit is now **Ctrl+S**; Enter stays a plain newline; "Next escalation" moved + to Ctrl+N. -## 0.4.0 +## [0.4.0] - 2026-03-28 ### Changed -- **Turn-budget extensions now cover the evaluator, auditor, and e2e agents.** - Previously only build workers and the Phase-A agents (planner/grill/slicer) could - resume on a turn cut-off; the read-only evaluator that runs out of turns mid-grading - would produce an unparseable verdict and escalate the issue. These agents now resume - the same session with more turns (up to `max_turn_extensions`) to finish, governed by - the existing `auto_extend_turns` / `max_turn_extensions` / `turn_extension_size` +- **Turn-budget extensions now cover the evaluator, auditor, and e2e agents.** These + agents now resume the same session with more turns (up to `max_turn_extensions`) to + finish, governed by `auto_extend_turns` / `max_turn_extensions` / `turn_extension_size` config. Factored into a shared `_run_agent_with_extensions` helper. -## 0.3.2 +## [0.3.2] - 2026-03-28 ### Fixed -- **Worker sidebar flicker + crash on selecting a worker.** The Workers screen - rebuilt its list (clear + re-append) every 0.3s, which flickered, wiped the arrow-key - highlight, and raced with click handling — clicking a worker crashed with a Textual - `ValueError` (the clicked item had just been cleared from the node list). The list - now updates labels in place and only rebuilds when the set of workers changes; - arrow/tab navigation follows the highlight into the log pane. -- **`RuntimeError: aclose(): asynchronous generator is already running`.** When a run - was cancelled mid-step (e.g. during the TUI teardown above), the runner closed the - backend stream while a `__anext__` was still in flight. It now drains the in-flight - step before closing, so a cancelled run ends cleanly. - -## 0.3.1 +- **Worker sidebar flicker + crash on selecting a worker.** List now updates labels in + place and only rebuilds when the set of workers changes. +- **`RuntimeError: aclose(): asynchronous generator is already running`.** Runner now + drains the in-flight step before closing on cancellation. + +## [0.3.1] - 2026-03-28 ### Fixed - **Build failed to start when the repo is checked out on the integration branch** - (`fatal: 'main' is already used by worktree …`). Git refuses a second worktree on a - branch the primary checkout already holds — the common case where your repo sits on - `main`. Foreman now uses the repo itself as the integration worktree in that case, so - merges land directly on your branch (the intended deliverable). A safety guard also - prevents the worktree cleanup from ever removing the primary checkout. Test fixtures - used plain `git init` (default `master`), which masked the bug. + (`fatal: 'main' is already used by worktree …`). Foreman now uses the repo itself as + the integration worktree in that case. -## 0.3.0 +## [0.3.0] - 2026-03-28 ### Added -- **Turn-budget awareness + request-more-turns / continue.** Agents and workers are - now told their per-run turn budget and asked to finish within it. A worker that is - making progress but running low can emit `request_more_turns: N` in its - FOREMAN-SUMMARY (instead of being cut off); and a hard turn cut-off is treated as an - implicit request. In both cases Foreman **resumes the same session** with a fresh - turn allowance and the agent **continues where it left off**, up to - `max_turn_extensions` (default 2) before escalating to a human. Applies to build - workers and the Phase-A agents (planner/grill/slicer) — the planner previously hit - the turn limit and was thrown away every run. Only turn exhaustion extends; cost / - timeout / stuck kills still escalate. New config: `auto_extend_turns`, +- **Turn-budget awareness + request-more-turns / continue.** Workers and Phase-A agents + can emit `request_more_turns: N`; Foreman resumes the same session with a fresh + allowance up to `max_turn_extensions` (default 2). New config: `auto_extend_turns`, `max_turn_extensions`, `turn_extension_size`. (`foreman-tdd` skill → v3.) -## 0.2.0 +## [0.2.0] - 2026-03-18 -First release after an end-to-end dogfooding shakedown (see `validation/`). Hardens -the TUI and the Phase-A document pipeline; adds live activity visibility. +First release after an end-to-end dogfooding shakedown. Hardens the TUI and Phase-A +document pipeline; adds live activity visibility. ### Added -- **Live TUI status line.** The dashboard now shows a persistent, spinner-animated - status bar — `ACTIVE · planner · turn 4 · 12s · ⚙ Bash(…)` while work runs, or - `idle · ` otherwise. Phase-A agents (planner/grill/slicer) now stream - their activity into the global log instead of running silently. +- **Live TUI status line** — `ACTIVE · planner · turn 4 · 12s · ⚙ Bash(…)` while + work runs, `idle · ` otherwise. ### Fixed -- **Plan/ADR/PRD "reverted to v1" during a run.** Document agents now write to a - Foreman-owned draft path (`feature/drafts/.md`); only Foreman writes the - canonical doc. The version-of-record can no longer be corrupted or read mid-write — - it stays at the prior version until Foreman re-stamps it. -- **TUI crash on non-canonical doc status** (`ValueError: 'draft' is not a valid - DocStatus`). Doc loading is now tolerant (unknown status → a non-approved state), - mirroring issue-status loading; never crashes on a mid-write or hand-edited file. -- **TUI crash selecting list items** on Textual 8 (`Label.renderable` removed). List - selection now reads the item's `name`, independent of Textual internals. -- **Crash-recovery orphan reconciliation (B1).** After a hard crash (SIGKILL), - an issue left mid-flight (`in_progress`/`tests_failing`/`awaiting_evaluation`) is now - requeued on restart instead of silently stalling; no duplicate merge. -- **`foreman init` no longer guesses uninstalled tools** (e.g. `typecheck: mypy .` on a - project without mypy). Command detection now gates on tool availability. - -## 0.1.0 -- Initial Phase 1 + Phase 2 implementation: gated plan→ADR/PRD→issues→TDD→e2e +- **Plan/ADR/PRD "reverted to v1" during a run.** Document agents now write to a draft + path; only Foreman writes the canonical doc. +- **TUI crash on non-canonical doc status** (`ValueError: 'draft' is not a valid DocStatus`). +- **TUI crash selecting list items** on Textual 8 (`Label.renderable` removed). +- **Crash-recovery orphan reconciliation** — issues left mid-flight after a hard crash + are requeued on restart. +- **`foreman init` no longer guesses uninstalled tools.** + +## [0.1.0] - 2026-03-14 + +### Added +- Initial Phase 1 + Phase 2 implementation: gated `plan → ADR/PRD → issues → TDD → e2e` pipeline, conflict-aware scheduler, verification gate + regression ratchet, read-only evaluator/auditor, janitor passes, retro/bench flywheel, TUI. + +[Unreleased]: https://github.com/VisionForge-OU/foreman/compare/v0.6.0...HEAD +[0.6.0]: https://github.com/VisionForge-OU/foreman/compare/v0.5.0...v0.6.0 +[0.5.0]: https://github.com/VisionForge-OU/foreman/compare/v0.4.13...v0.5.0 +[0.4.13]: https://github.com/VisionForge-OU/foreman/compare/v0.4.12...v0.4.13 +[0.4.12]: https://github.com/VisionForge-OU/foreman/compare/v0.4.11...v0.4.12 +[0.4.11]: https://github.com/VisionForge-OU/foreman/compare/v0.4.10...v0.4.11 +[0.4.10]: https://github.com/VisionForge-OU/foreman/compare/v0.4.9...v0.4.10 +[0.4.9]: https://github.com/VisionForge-OU/foreman/compare/v0.4.8...v0.4.9 +[0.4.8]: https://github.com/VisionForge-OU/foreman/compare/v0.4.7...v0.4.8 +[0.4.7]: https://github.com/VisionForge-OU/foreman/compare/v0.4.6...v0.4.7 +[0.4.6]: https://github.com/VisionForge-OU/foreman/compare/v0.4.5...v0.4.6 +[0.4.5]: https://github.com/VisionForge-OU/foreman/compare/v0.4.4...v0.4.5 +[0.4.4]: https://github.com/VisionForge-OU/foreman/compare/v0.4.3...v0.4.4 +[0.4.3]: https://github.com/VisionForge-OU/foreman/compare/v0.4.2...v0.4.3 +[0.4.2]: https://github.com/VisionForge-OU/foreman/compare/v0.4.1...v0.4.2 +[0.4.1]: https://github.com/VisionForge-OU/foreman/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/VisionForge-OU/foreman/compare/v0.3.2...v0.4.0 +[0.3.2]: https://github.com/VisionForge-OU/foreman/compare/v0.3.1...v0.3.2 +[0.3.1]: https://github.com/VisionForge-OU/foreman/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/VisionForge-OU/foreman/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/VisionForge-OU/foreman/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/VisionForge-OU/foreman/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a7bbebc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# Contributing to Foreman + +## Versioning + +Foreman follows **[Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH)**. The single source of truth is `version` in `pyproject.toml` — the README badge, changelog, and PyPI package metadata are all derived from it. + +### Bump policy + +| Change type | Version bump | Example | +|-------------|-------------|---------| +| Breaking change to the pipeline, CLI flags, or public config schema | **MAJOR** | Removing a `foreman.yaml` key, renaming the `foreman` CLI entry-point | +| New feature or opt-in behaviour (backwards-compatible) | **MINOR** | New gate agent, new `--flag`, new config knob | +| Bug fix, docs, or internal refactor with no user-visible change | **PATCH** | Crash fix, performance tweak, typo | + +> **Pre-1.0 note:** while the project is < 1.0 the minor version acts as the major — breaking changes may land in a minor bump. The project will signal 1.0 when the pipeline API and config schema are stable. + +### Releasing + +1. Update `version` in `pyproject.toml`. +2. Add a `## [X.Y.Z] - YYYY-MM-DD` section to `CHANGELOG.md` following [Keep a Changelog](https://keepachangelog.com/). +3. Open a PR; merge to `main`. +4. Push a `vX.Y.Z` tag — CI will build, validate, publish to PyPI, and create a GitHub Release automatically. + +Pre-releases use `vX.Y.ZaN` / `vX.Y.ZbN` / `vX.Y.ZrcN` — these publish to TestPyPI only. + +## Development setup + +```bash +uv sync --extra dev +uv run pytest +``` + +## Pull requests + +- One logical change per PR. +- Tests must pass (`uv run pytest`). +- Add a `CHANGELOG.md` entry for any user-visible change. +- Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `refactor:`, `docs:`, `chore:`. diff --git a/README.md b/README.md index 6a6847b..d1cbc51 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,13 @@ `plan → ADR/PRD → issues → TDD build → e2e` +[![CI](https://github.com/VisionForge-OU/foreman/actions/workflows/ci.yml/badge.svg)](https://github.com/VisionForge-OU/foreman/actions/workflows/ci.yml) +[![Coverage](https://codecov.io/gh/VisionForge-OU/foreman/branch/main/graph/badge.svg)](https://codecov.io/gh/VisionForge-OU/foreman) +[![PyPI version](https://img.shields.io/pypi/v/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/) +[![PyPI - Downloads](https://img.shields.io/pypi/dm/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) -[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/) -[![Version](https://img.shields.io/badge/version-0.6.0-blueviolet.svg)](./CHANGELOG.md) [![TUI: Textual](https://img.shields.io/badge/TUI-Textual-5a3fd6.svg)](https://textual.textualize.io/) -[![No database](https://img.shields.io/badge/database-none-lightgrey.svg)](#how-it-works) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#contributing) [Why Foreman?](#why-foreman) · [Demo](#demo) · [Quickstart](#5-minute-quickstart) · [Guide](#guide--driving-the-tui) · [How it works](#how-it-works) · [Roadmap](#roadmap) · [Contributing](#contributing) diff --git a/pyproject.toml b/pyproject.toml index 760ea91..68a99eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,15 +9,20 @@ description = "A Boris-style agentic orchestrator TUI that supervises headless C readme = "README.md" requires-python = ">=3.11" license = { text = "MIT" } -authors = [{ name = "Foreman" }] +authors = [{ name = "ehsantg", email = "me@ehsan.ee" }] keywords = ["claude", "claude-code", "tui", "agents", "orchestrator", "textual", "tdd"] classifiers = [ + "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Build Tools", ] + dependencies = [ "textual>=0.79", "pyyaml>=6.0", @@ -27,10 +32,17 @@ dependencies = [ dev = [ "pytest>=8.0", "pytest-asyncio>=0.23", + "pytest-cov>=5.0", "pytest-textual-snapshot>=1.0", "textual-dev>=1.5", ] +[project.urls] +Homepage = "https://github.com/VisionForge-OU/foreman" +Repository = "https://github.com/VisionForge-OU/foreman" +Issues = "https://github.com/VisionForge-OU/foreman/issues" +Changelog = "https://github.com/VisionForge-OU/foreman/blob/main/CHANGELOG.md" + [project.scripts] foreman = "foreman.cli:main"