diff --git a/swarm-forge/bb.edn b/bb.edn similarity index 100% rename from swarm-forge/bb.edn rename to bb.edn diff --git a/swarm-forge/close-swarm b/close-swarm similarity index 100% rename from swarm-forge/close-swarm rename to close-swarm diff --git a/swarm-forge/doc/plan-swarmforge-dir.md b/doc/plan-swarmforge-dir.md similarity index 100% rename from swarm-forge/doc/plan-swarmforge-dir.md rename to doc/plan-swarmforge-dir.md diff --git a/swarm-forge/doc/quality-level-proposal.md b/doc/quality-level-proposal.md similarity index 100% rename from swarm-forge/doc/quality-level-proposal.md rename to doc/quality-level-proposal.md diff --git a/swarm-forge/doc/sf-handoff-protocol.md b/doc/sf-handoff-protocol.md similarity index 100% rename from swarm-forge/doc/sf-handoff-protocol.md rename to doc/sf-handoff-protocol.md diff --git a/swarm-forge/doc/swarmforge.md b/doc/swarmforge.md similarity index 100% rename from swarm-forge/doc/swarmforge.md rename to doc/swarmforge.md diff --git a/swarm-forge/swarm b/swarm similarity index 100% rename from swarm-forge/swarm rename to swarm diff --git a/swarm-forge/.gitignore b/swarm-forge/.gitignore deleted file mode 100644 index 02be7d6..0000000 --- a/swarm-forge/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.DS_Store -.env -.claude/ -.swarmforge/ -.worktrees/ diff --git a/swarm-forge/README.md b/swarm-forge/README.md deleted file mode 100644 index d92c0ad..0000000 --- a/swarm-forge/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# SwarmForge — pi-optimized, universal agent support - -Fork of [unclebob/swarm-forge](https://github.com/unclebob/swarm-forge) (based on the `four-pack` -workflow) that runs the swarm with **[pi](https://pi.dev)** as the agent harness — while keeping -**universal support** for other agent CLIs, **any model** per role, and **bash** instead of zsh. - -The `four-pack` pipeline is unchanged: `specifier` → `coder` → `refactorer` → `architect` with -human approval at the specifier gate. - - ---- - -## Quickstart - -```bash -# copy this fork's main branch into a project directory -curl -L "https://github.com/pablo-io/swarm-forge/archive/refs/heads/main.tar.gz" | tar -xz --strip-components=1 - -# edit swarmforge/swarmforge.conf (pick your models, see below), then start -SWARMFORGE_TERMINAL=none ./swarm - -# observe/steer agents (headless Linux: attach to sessions manually) -tmux -S "$(cat .swarmforge/tmux-socket)" attach -t swarmforge-coder - -# stop the swarm -./close-swarm -``` - -## Using any model (per role) - -Models are **configuration, not code**: the `extra-args` field of `swarmforge.conf` is passed -straight to the agent CLI. To pick a different model, change `--model` (pi) or the equivalent -flag of your backend: - -```conf -# pi + models per role (one provider per model family) -window specifier pi master --model opencode-go/deepseek-v4-flash -window coder pi coder --model opencode-go/deepseek-v4-flash -window refactorer pi refactorer batch --model qwen-token-plan/qwen3.7-max -window architect pi architect batch --model qwen-token-plan/glm-5.2 - -# or a different backend entirely -window coder codex coder --yolo -window architect claude architect batch --dangerously-skip-permissions -``` - -- List what your harness offers: `pi --list-models` / `pi --list-models ` (run - `pi update --models` after catalog changes). -- pi supports DeepSeek, Qwen (incl. GLM) and many providers natively — no custom provider - extensions needed for those. -- Anything after the receive mode (`task`/`batch`) is passed to the agent CLI: `--model`, - `--thinking`, `--yolo`, etc. - - -## Monitoring tools - -The `tools/` folder ships two small bash utilities (no dependencies) for operating a swarm: - -- **`tools/sf-queue [project-dir]`** — live handoff queue state for every role: pending (`new`), - in-process (incl. batches), completed, outbox, sent, plus task names. Reads `.swarmforge/roles.tsv` - and works with any agent backend. -- **`tools/sf-tokens [project-dir]`** — token consumption per role (input / output / cache / total) - from pi's session files (`~/.pi/agent/sessions`, organized per worktree). Cumulative across - restarts. pi-specific (only meaningful when pi is the backend). - -```bash -bash tools/sf-queue /path/to/project # queue state per role -bash tools/sf-tokens /path/to/project # tokens per role (pi sessions) -``` - -## Adding another agent backend - -The launcher validates backends in `parse-config` and builds the launch command in -`launch-command` (`swarmforge/scripts/swarmforge.bb`). To add a CLI: - -1. Add the name to the allowed set in `parse-config`: - ```clojure - (when-not (#{"claude" "codex" "copilot" "grok" "pi" "your-agent"} agent) - ``` -2. Add a `case` arm in `launch-command` that starts the CLI interactively with the initial - prompt, e.g. for pi: - ```clojure - "pi" (str "pi -a --name " (sq (str "SwarmForge " display)) " " - (extra-args-prefix row) "\"$(cat " (sq (str prompt-file)) ")\"") - ``` -3. The binary must be on `PATH` (the launcher checks it). The agent must be an **interactive - TUI/REPL** that accepts typed input — wake-ups arrive as a typed message + Enter. - -Tip: for many backends, a per-harness launch script (like `terminal-adapters/`) is cleaner than -adding `case` arms — the fork is happy to host one per agent. - -## Changes & improvements vs upstream - -| # | Change | Why | -|---|---|---| -| 1 | **pi as agent backend** | `parse-config` accepts `pi`; launch arm `pi -a --name 'SwarmForge ' [extra] "$(cat prompt)"`. pi starts interactive, sends the initial prompt, stays in the TUI. | -| 2 | **Bash-native, zero zsh dependency** | All shell scripts migrated: shebangs `zsh` → `bash`, `${1:l}` → `tr`, `<->` glob → regex, `&!` → `& disown` (tmux pane shell is bash), `zsh -c` → `bash -c` in `swarmforge.bb`/`swarm-window-watchdog.bb`. Bash is the default on Linux and exists on every platform. | -| 3 | **Universal wake-up (pi + others)** | Upstream typed the wake-up text then a separate Enter; pi-tui drops a standalone CR, so messages sat in the editor. The fork embeds the CR in the same write (`text\r`) and keeps the trailing LF for other TUIs — validated in pi, compatible with claude/codex/grok. | -| 4 | **Self-contained branch** | `swarmforge/scripts/` vendored (upstream ignores it and downloads from `main`); `.gitignore` adjusted; empty `scripts/shared-articles/` stops the wrapper download. No surprise overwrites from upstream. | -| 5 | **Shared constitution articles included** | `engineering.prompt`, `handoffs.prompt`, `workflow.prompt` copied into `constitution/articles/` (upstream `four-pack` only carries `project.prompt`, so agents had no handoff/workflow rules). | -| 6 | **Git identity and worktree failure detection** | Upstream fails *silently* when `git commit` cannot run (no `user.name`/`user.email`) → unborn HEAD → empty worktrees. Now: clear error with instructions before `git init`, and `fail!` if `git worktree add` fails. | -| 7 | **Written review reports** | The architect commits `docs/reviews/-summary.md` at the end of every task/batch (what was reviewed, fixes, verification results, suite status, handoffs sent) — the review record is durable and versioned instead of living only in the agent's session. | - -### Where review reports are documented, and when - -The architect writes the summary to **`docs/reviews/-summary.md`** (one per task, created -under `docs/reviews/` in the repo) **at the end of each task or batch**, committed with its byline -in the same commit as the review changes. Because it is a git commit, the report: - -- travels with the branch and arrives on `master` when the specifier merges the architect's work, -- is versioned — you can diff `docs/reviews/` across runs to see every review checkpoint - (the pipeline "cuts"), -- replaces the informal closing message the architect used to leave only in its own TUI. - -Example layout after a run: - -```text -docs/reviews/ - user-login-summary.md - login-form-summary.md -``` - -## Scope (verified) - -Verified on Linux (Arch) with the real pi CLI and real provider credentials: - -- [x] `bb test` — 24 tests, 91 assertions, 0 failures (no zsh required) -- [x] Launch command generation: `pi -a --name 'SwarmForge ' --model "$(cat prompt)"` -- [x] Swarm startup headless (`SWARMFORGE_TERMINAL=none`): tmux sessions, real git worktrees with - `swarmforge-` branches, agents live with the correct model per role -- [x] Handoff protocol end-to-end: commit → draft → validation → outbox → daemon → inbox - (generated headers + `merge_and_process` payload) → tmux wake-up → `ready_for_next.sh` - (task and batch semantics) -- [x] Autonomous chain: coder → refactorer → architect with automatic task pickup and forwarding -- [x] Clean shutdown via `close-swarm` -- [x] Git identity guard: clear failure with instructions when identity is missing -- [x] Universal wake-up: auto-submit in pi with embedded CR; trailing LF retained for other TUIs - -Not tested: macOS/Windows terminal adapters (bash-ported from upstream, not exercised on Linux), -window watchdog with a trackable terminal backend (Linux headless mode has no windows by design). - -## Requirements - -- **bash** (default shell; tmux panes run it). No zsh required. - - Linux: any modern distro (bash ≥ 4.4). Windows/WSL: fine. - - macOS: system bash is 3.2 — `close-swarm` uses array append (`sessions+=(...)`, bash ≥ 4); - use a modern bash (Homebrew) or zsh on macOS. -- `git` with **`user.name` and `user.email` configured** — enforced with a clear error at startup. -- `tmux` ≥ 3.5 (recommended for pi extended keys). -- Babashka (`bb`) — single static binary. -- One or more agent CLIs on `PATH` (pi, codex, claude, …), authenticated for the providers you use. - -## Notes - -- **This branch is self-contained**: it does not auto-follow upstream `main` script updates - (scripts are vendored). Rebase/merge manually if you want upstream changes. -- Handoff semantics are unchanged from upstream: only `git_handoff` / `note`, priorities 00–99, - chain forwarding always, terminal broadcast merge-only. See `swarmforge/handoff-protocol.md`. -- Upstream is zsh-based; if you pull upstream scripts, re-apply the bash migration - (2 syntax sites + shebangs + `zsh -c` + `&!`). diff --git a/swarm-forge/swarmforge/constitution.prompt b/swarmforge/constitution.prompt similarity index 100% rename from swarm-forge/swarmforge/constitution.prompt rename to swarmforge/constitution.prompt diff --git a/swarm-forge/swarmforge/constitution/articles/engineering.prompt b/swarmforge/constitution/articles/engineering.prompt similarity index 100% rename from swarm-forge/swarmforge/constitution/articles/engineering.prompt rename to swarmforge/constitution/articles/engineering.prompt diff --git a/swarm-forge/swarmforge/constitution/articles/handoffs.prompt b/swarmforge/constitution/articles/handoffs.prompt similarity index 100% rename from swarm-forge/swarmforge/constitution/articles/handoffs.prompt rename to swarmforge/constitution/articles/handoffs.prompt diff --git a/swarm-forge/swarmforge/constitution/articles/project.prompt b/swarmforge/constitution/articles/project.prompt similarity index 100% rename from swarm-forge/swarmforge/constitution/articles/project.prompt rename to swarmforge/constitution/articles/project.prompt diff --git a/swarm-forge/swarmforge/constitution/articles/workflow.prompt b/swarmforge/constitution/articles/workflow.prompt similarity index 100% rename from swarm-forge/swarmforge/constitution/articles/workflow.prompt rename to swarmforge/constitution/articles/workflow.prompt diff --git a/swarm-forge/swarmforge/roles/architect.prompt b/swarmforge/roles/architect.prompt similarity index 100% rename from swarm-forge/swarmforge/roles/architect.prompt rename to swarmforge/roles/architect.prompt diff --git a/swarm-forge/swarmforge/roles/coder.prompt b/swarmforge/roles/coder.prompt similarity index 100% rename from swarm-forge/swarmforge/roles/coder.prompt rename to swarmforge/roles/coder.prompt diff --git a/swarm-forge/swarmforge/roles/refactorer.prompt b/swarmforge/roles/refactorer.prompt similarity index 100% rename from swarm-forge/swarmforge/roles/refactorer.prompt rename to swarmforge/roles/refactorer.prompt diff --git a/swarm-forge/swarmforge/roles/specifier.prompt b/swarmforge/roles/specifier.prompt similarity index 100% rename from swarm-forge/swarmforge/roles/specifier.prompt rename to swarmforge/roles/specifier.prompt diff --git a/swarm-forge/swarmforge/scripts/done_with_current.bb b/swarmforge/scripts/done_with_current.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current.bb rename to swarmforge/scripts/done_with_current.bb diff --git a/swarm-forge/swarmforge/scripts/done_with_current.sh b/swarmforge/scripts/done_with_current.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current.sh rename to swarmforge/scripts/done_with_current.sh diff --git a/swarm-forge/swarmforge/scripts/done_with_current_batch.bb b/swarmforge/scripts/done_with_current_batch.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current_batch.bb rename to swarmforge/scripts/done_with_current_batch.bb diff --git a/swarm-forge/swarmforge/scripts/done_with_current_batch.sh b/swarmforge/scripts/done_with_current_batch.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current_batch.sh rename to swarmforge/scripts/done_with_current_batch.sh diff --git a/swarm-forge/swarmforge/scripts/done_with_current_task.bb b/swarmforge/scripts/done_with_current_task.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current_task.bb rename to swarmforge/scripts/done_with_current_task.bb diff --git a/swarm-forge/swarmforge/scripts/done_with_current_task.sh b/swarmforge/scripts/done_with_current_task.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/done_with_current_task.sh rename to swarmforge/scripts/done_with_current_task.sh diff --git a/swarm-forge/swarmforge/scripts/handoff_lib.bb b/swarmforge/scripts/handoff_lib.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/handoff_lib.bb rename to swarmforge/scripts/handoff_lib.bb diff --git a/swarm-forge/swarmforge/scripts/handoffd.bb b/swarmforge/scripts/handoffd.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/handoffd.bb rename to swarmforge/scripts/handoffd.bb diff --git a/swarm-forge/swarmforge/scripts/ready_for_next.bb b/swarmforge/scripts/ready_for_next.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next.bb rename to swarmforge/scripts/ready_for_next.bb diff --git a/swarm-forge/swarmforge/scripts/ready_for_next.sh b/swarmforge/scripts/ready_for_next.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next.sh rename to swarmforge/scripts/ready_for_next.sh diff --git a/swarm-forge/swarmforge/scripts/ready_for_next_batch.bb b/swarmforge/scripts/ready_for_next_batch.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next_batch.bb rename to swarmforge/scripts/ready_for_next_batch.bb diff --git a/swarm-forge/swarmforge/scripts/ready_for_next_batch.sh b/swarmforge/scripts/ready_for_next_batch.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next_batch.sh rename to swarmforge/scripts/ready_for_next_batch.sh diff --git a/swarm-forge/swarmforge/scripts/ready_for_next_task.bb b/swarmforge/scripts/ready_for_next_task.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next_task.bb rename to swarmforge/scripts/ready_for_next_task.bb diff --git a/swarm-forge/swarmforge/scripts/ready_for_next_task.sh b/swarmforge/scripts/ready_for_next_task.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/ready_for_next_task.sh rename to swarmforge/scripts/ready_for_next_task.sh diff --git a/swarm-forge/swarmforge/scripts/shared-articles/.gitkeep b/swarmforge/scripts/shared-articles/.gitkeep similarity index 100% rename from swarm-forge/swarmforge/scripts/shared-articles/.gitkeep rename to swarmforge/scripts/shared-articles/.gitkeep diff --git a/swarm-forge/swarmforge/scripts/stop_handoff_daemon.bb b/swarmforge/scripts/stop_handoff_daemon.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/stop_handoff_daemon.bb rename to swarmforge/scripts/stop_handoff_daemon.bb diff --git a/swarm-forge/swarmforge/scripts/stop_handoff_daemon.sh b/swarmforge/scripts/stop_handoff_daemon.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/stop_handoff_daemon.sh rename to swarmforge/scripts/stop_handoff_daemon.sh diff --git a/swarm-forge/swarmforge/scripts/swarm-cleanup.sh b/swarmforge/scripts/swarm-cleanup.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm-cleanup.sh rename to swarmforge/scripts/swarm-cleanup.sh diff --git a/swarm-forge/swarmforge/scripts/swarm-terminal-adapter.sh b/swarmforge/scripts/swarm-terminal-adapter.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm-terminal-adapter.sh rename to swarmforge/scripts/swarm-terminal-adapter.sh diff --git a/swarm-forge/swarmforge/scripts/swarm-window-watchdog.bb b/swarmforge/scripts/swarm-window-watchdog.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm-window-watchdog.bb rename to swarmforge/scripts/swarm-window-watchdog.bb diff --git a/swarm-forge/swarmforge/scripts/swarm-window-watchdog.sh b/swarmforge/scripts/swarm-window-watchdog.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm-window-watchdog.sh rename to swarmforge/scripts/swarm-window-watchdog.sh diff --git a/swarm-forge/swarmforge/scripts/swarm_handoff.bb b/swarmforge/scripts/swarm_handoff.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm_handoff.bb rename to swarmforge/scripts/swarm_handoff.bb diff --git a/swarm-forge/swarmforge/scripts/swarm_handoff.sh b/swarmforge/scripts/swarm_handoff.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/swarm_handoff.sh rename to swarmforge/scripts/swarm_handoff.sh diff --git a/swarm-forge/swarmforge/scripts/swarmforge.bb b/swarmforge/scripts/swarmforge.bb similarity index 100% rename from swarm-forge/swarmforge/scripts/swarmforge.bb rename to swarmforge/scripts/swarmforge.bb diff --git a/swarm-forge/swarmforge/scripts/swarmforge.sh b/swarmforge/scripts/swarmforge.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/swarmforge.sh rename to swarmforge/scripts/swarmforge.sh diff --git a/swarm-forge/swarmforge/scripts/terminal-adapters/ghostty.sh b/swarmforge/scripts/terminal-adapters/ghostty.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/terminal-adapters/ghostty.sh rename to swarmforge/scripts/terminal-adapters/ghostty.sh diff --git a/swarm-forge/swarmforge/scripts/terminal-adapters/iterm2.sh b/swarmforge/scripts/terminal-adapters/iterm2.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/terminal-adapters/iterm2.sh rename to swarmforge/scripts/terminal-adapters/iterm2.sh diff --git a/swarm-forge/swarmforge/scripts/terminal-adapters/none.sh b/swarmforge/scripts/terminal-adapters/none.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/terminal-adapters/none.sh rename to swarmforge/scripts/terminal-adapters/none.sh diff --git a/swarm-forge/swarmforge/scripts/terminal-adapters/terminal-app.sh b/swarmforge/scripts/terminal-adapters/terminal-app.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/terminal-adapters/terminal-app.sh rename to swarmforge/scripts/terminal-adapters/terminal-app.sh diff --git a/swarm-forge/swarmforge/scripts/terminal-adapters/windows-terminal.sh b/swarmforge/scripts/terminal-adapters/windows-terminal.sh similarity index 100% rename from swarm-forge/swarmforge/scripts/terminal-adapters/windows-terminal.sh rename to swarmforge/scripts/terminal-adapters/windows-terminal.sh diff --git a/swarm-forge/swarmforge/swarmforge.conf b/swarmforge/swarmforge.conf similarity index 100% rename from swarm-forge/swarmforge/swarmforge.conf rename to swarmforge/swarmforge.conf diff --git a/swarm-forge/test/swarmforge/handoff_test.clj b/test/swarmforge/handoff_test.clj similarity index 100% rename from swarm-forge/test/swarmforge/handoff_test.clj rename to test/swarmforge/handoff_test.clj diff --git a/swarm-forge/test/swarmforge/script_test.clj b/test/swarmforge/script_test.clj similarity index 100% rename from swarm-forge/test/swarmforge/script_test.clj rename to test/swarmforge/script_test.clj diff --git a/swarm-forge/tools/sf-queue b/tools/sf-queue similarity index 100% rename from swarm-forge/tools/sf-queue rename to tools/sf-queue diff --git a/swarm-forge/tools/sf-tokens b/tools/sf-tokens similarity index 100% rename from swarm-forge/tools/sf-tokens rename to tools/sf-tokens