OpenSwarm

Intrect-ioMIT活跃维护

用 Claude Code CLI 驱动的自主 AI 开发团队编排器,通过 Discord 指挥、Linear 集成和认知记忆,让多个智能体协作完成编码任务。

OpenSwarm — Autonomous AI dev team orchestrator powered by Claude Code CLI. Discord control, Linear integration, cognitive memory.

v0.24.4发布于 2026-09-29 09:23 UTC873star +1 / 7 天149fork同步于 2026-11-10 05:58 UTC

怎么上手

由 README 提炼,执行前请确认
npm install -g @intrect/openswarm
export OPENROUTER_API_KEY=…
openswarm review --path . --read-only
硬件要求按 README 说明

README 未说明显存或 GPU 要求;可接本地模型服务(Ollama、LM Studio),也可用云端 API 或已登录的 codex/claude CLI。

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

带确定性校验的智能体 CI/CD 合并门禁,自动审查并修复 PR 与本地改动

用 Claude Code CLI 驱动的自主 AI 开发团队编排器,通过 Discord 指挥、Linear 集成和认知记忆,让多个智能体协作完成编码任务。

核心能力

  • 审查 diff 后分组修复确认问题,再复审并跑确定性仓库检查
  • 支持 Codex/GPT、OpenRouter、Ollama/LM Studio 本地模型与 Claude Code
  • 提供 GitHub Action,按退出码 0/1/2 区分通过、拒绝与未运行
  • openswarm fix 自动检测 npm/Cargo/Python 检查并循环修复至通过
  • 按仓库累积任务结果作为长期记忆,供后续提示召回

容易踩的坑

需先配置一个可用 provider(OAuth 登录或 API key),否则门禁无法运行;CI 中需 fetch-depth: 0 才能取到 merge base 做 diff;在已有 config.yaml 的仓库重跑 init 会被拒绝,需加 --force。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v0.24.4
  1. v0.24.4最新正式版2026-09-29 · 2026-09-29 09:23 UTC

    Added

    • A review of content this deployment already reviewed is replayed from a durable store instead of paying for the reviewer again. src/automation/reviewVerdictStore.ts keys a verdict on (kind, base, sha256(content digest)), the digest being every changed path paired with its content hash, and replays the stored outcome on a hit — from both the plain openswarm review path (reviewCommand.ts) and the publication hook (publicationReviewHook.ts). Measured over the recorded history (530 records, 512 carrying a verdict): 68 byte-identical pairs, 15 of them same-mode (8 direct→direct, 7 pr→pr) and 10 of those repeating the same verdict — on the order of 10 of 512 reviews, at a measured ~$0.26 and 93s p50 per reviewer call. Proven across two separate processes: a cold 27.0s / 6-model-call review became a 1.58s replay with zero model calls, same verdict. The key carries the base ref and the review mode deliberately, because 15 of the 53 cross-mode repeats in that history flipped their verdict — a CLI review of a tree and a publication review of the same tree are different reviews. What is skipped is the reviewer call; the advisor pass still runs over the reused verdict, so a replay can tighten (approve→revise/reject) exactly as a live run would and the cache cannot fail open past an escalation.
    • The reuse survives a daemon restart. The verdict lives in its own publication_reviews table in the automation database rather than in the in-process reviewedPublications Set it replaces, which was empty after every restart — the failure census records 141 owner_process_exited and 157 shutdown_cancelled, each of which threw away a verdict already paid for. A store that cannot be opened does not suppress a review; the hook reviews instead.
    • openswarm review --max --harness-only runs a deterministic quality harness with no LLM cost. The new harness (src/verify/qualityHarness.ts) enumerates every tracked source file via the git index and scans each one, then runs the discovered typecheck/lint/test/build commands inside the existing isolated verify sandbox. It is fail-closed by construction: a file over the 512 KiB ceiling, one containing NUL bytes, an unreadable path, a symlinked source, or a path that escapes the repository root each become an explicit error finding rather than a silent skip, and a listing that scanned nothing is itself an error — so the gate cannot report "passed" over a subset it never read. Findings are folded into the audit run as a synthetic .openswarm/quality-harness area, which means the markdown report and the exit-code contract carry the evidence on every --max run, not only when an LLM area happened to notice something.

    Fixed

    • openswarm review --max no longer changes its verdict with --concurrency. The audit re-partitioned the source into reviewer areas until the fan-out saturated the pool (INT-2249), so the same files and the same reviewer produced 2 areas at concurrency 1 and 10 at concurrency 8 — and because aggregateAuditResults is worst-wins, the finer split could only turn an approve into a revise/reject. The audit's units of judgement now come from planAuditAreas, which is derived from --max-files-per-area alone (--concurrency is purely how many reviewers run at once), so a given file set gets one verdict. The finer, more parallel fan-out is still available, deterministically, by lowering --max-files-per-area; the --fix path keeps the pool-filling balanceAreasToConcurrency, where more areas only mean more parallel fix workers. The cost gate now prints the real agent-run count (the area count) and points at the granularity flag when the pool is under-filled.
    • A workflow execution can no longer be persisted in a state its DAG forbids. saveExecution now rejects a step marked completed without a completedAt, failed without an error, or advanced past a dependency that is still pending, running or failed — s
  2. v0.24.22026-09-20 · 2026-09-20 01:25 UTC
    查看更新说明

    Fixed

    • Reviewer salvage now preserves a real verdict (AGT-4484). When a reviewer exhausts its tool turns, the final no-tools turn explicitly requires Decision: approve, Decision: revise, or Decision: reject with concrete reasoning instead of returning a worker-status summary that the reviewer parser must discard.
  3. v0.24.12026-09-20 · 2026-09-20 00:46 UTC
    查看更新说明

    Added

    • Cost-capped GitHub Action reviews. openswarm review --model <id> is now exposed by the CLI and the composite action forwards its optional model input through the same reviewed call chain. The action refuses as gate-not-run when an older installed package lacks the option, rather than silently falling back to an uncontrolled default model. The dogfood workflow pins deepseek/deepseek-v4-flash.
    • Backfill for pre-publication parked branches (AGT-4124). openswarm drain-parks --path <repo> finds unowned NEEDS_HUMAN rows, creates or reuses their draft PRs, and records zero-ahead or missing-branch reasons with CAS-protected ledger updates. --dry-run performs no GitHub or ledger write.
    • Resource-aware test fan-out. Test parallelism now scales with available CPU and memory instead of unconditionally consuming the host.

    Changed

    • OpenSwarm is documented as an agentic CI/CD gate first. The README now leads with review → fix → re-review → deterministic verification and presents the Linear daemon as an optional orchestration layer.
    • Fleet supervision exposes thinking effort. The supervisor can configure reasoning effort for every role instead of treating it as an inaccessible model default.

    Fixed

    • Reproducible package installation on every supported platform. LanceDB is pinned to the last stable release whose declared macOS, Linux, and Windows optional native packages all exist in the registry, so npm ci no longer rejects the committed lockfile.
    • OpenRouter flash routing fails over to GLM. A failing or unavailable deepseek/deepseek-v4-flash review can promote to z-ai/glm-5.3-flash under the existing fallback policy.
    • Durable run state has stronger recovery evidence. Session transcripts, watchdog causes, staged memory promotion, write scopes, and parked publication records now survive the retries and handoffs that previously obscured them.
  4. v0.24.02026-09-09 · 2026-09-09 19:59 UTC
    查看更新说明

    Everything the loop published still had to get past a gate, and three of them were not looking. CI failed every pull request for a reason none of them caused, the reviewer saw 22% of what shipped, and a store that had been broken for nine days was reported once per recall instead of once.

    Fixed

    • One dead apt repository no longer fails every pull request (AGT-4274). apt-get update && apt-get install -y bubblewrap let any configured repository gate the sandbox install. The google-chrome repo the runner image ships served a mismatched index, update exited non-zero, the && short-circuited, and bubblewrap was never installed — every open PR died seven lines later at bwrap: command not found, Tests and Verify sandbox red on all four while main was green. set -e does not fire on a non-final command of an AND-OR list, so the step ran past the real cause instead of stopping at it and nothing in the error named apt. update failing is now a warning; the install is the gate and still fails closed, with bwrap --version catching an unpacked-but-unusable binary. The line existed in three places — ci.yml Tests, ci.yml verify-sandbox, and release.yml, so the release publish path carried the same mine — and is now one composite action.
    • Every publication is reviewed, not 22% of them (AGT-4278). Of nine published pull requests, two carried a reviewer verdict. Draft publications never reached the gate at all: publishParkedIfNeeded opens a draft PR and took no review hook, so the output of runs that stopped — the least finished work the daemon emits — was the only thing nobody reviewed. Both park sides now get the same reviewer, without the rollback a draft has no use for. And a review that dies no longer fails open silently: two PRs ended at openrouter timeout after 300000ms and were published anyway, leaving an unreviewed PR indistinguishable from a reviewed one. A publication with no verdict now says so on the PR, with the reason. Reviews are deduplicated per PR and head sha on the park path only — never on the approved path, where skipping one would disarm the rollback for exactly the changes a reviewer had already rejected.
    • A change that removes test cases says so on the pull request (AGT-4277). A loop-authored PR green on all eight checks deleted four passing tests; three mutations of the file they covered survive without them, one of which would dispatch a sub-task the user had explicitly dropped. No gate could see it — the coverage threshold is a repository-wide ratio, so four tests in one file move it by nothing, and the reviewer reads added code. The check is deterministic, notes rather than blocks (renames, merges and genuinely obsolete coverage are legitimate; a gate that refused them would be routed around), and runs before the review so it survives a reviewer that times out or throws.
    • An unopenable memory store is reported once, not on every recall (AGT-4267). Seven zero-byte manifests from a single interrupted write made every long-term recall throw; initDatabase logged the stack and rethrew, searchMemorySafe logged it again, and callers swallowed it — 95 identical stacks in five minutes, none of which said that recall was off. Failures are now tracked by phase (open / embed / query) through one rate limiter, so suppressing one kind cannot hide another; opening the store is memoized, which also removes the racing createTable calls a first run made under concurrency; and searchMemorySafe returns DB_INIT_FAILED rather than QUERY_FAILED for a store that never opened, which repoKnowledge renders straight into the agent's prompt. Not a latch: the outage was repaired externally and recall returned on the next call. Measured after deployment: 34 init errors per three minutes → 0, and 192 successful recalls in four minutes.
    • coordinationTools test asserts through chalk's colouring (AGT-4153). Green in CI, red on every developer machine.
  5. v0.23.02026-09-09 · 2026-09-09 17:23 UTC
    查看更新说明

    The autonomous loop was shipping pull requests that no LLM had read, and its heartbeat was leaving slots idle next to work it was willing to do. This release closes both, and puts a bound on the second so the first cannot be paid for with churn.

    Changed

    • The published PR gets reviewed, and the verdict counts (AGT-4270). publication.freshReview is now opt-out — only an explicit false disables it. It had been opt-in while the per-attempt reviewer was switched off in its favour, and no repository ever opted in, so between the two decisions the loop published work no reviewer had seen. When the reviewer asks for changes the publication is undone: the PR returns to draft, the run drops out of approved, the worktree is preserved and the task returns to the queue — the commits and the durable record stay, so the next attempt continues rather than starting over. A review that merely failed (no diff against the merge base, a crashed processor, a comment that could not be posted after an approval) says nothing about the code and undoes nothing.
    • A draft pull request is no longer read as delivery (AGT-4270). gh pr list reports a draft's state as OPEN, so the reconciler used to recover one as approved and close its issue. It now returns the run to the queue instead — provided the tracker card is still live, since re-running work needs a card the heartbeat can see (AGT-4094).
    • Heartbeat fills free slots instead of idling (AGT-4257). Linear Backlog is a work queue by default (autonomous.includeBacklog: true). Parks (NEEDS_HUMAN, including unanswered ask_human), RETRY_AT, and legacy backoff are lifted via idle_fill when an enabled project still wants the card — bounded by the number of free slots, so a saturated pool cannot churn its parks the way AGT-4155 did (re-claim, re-execute, re-park, once per cycle, observed at attempt 20). An answered ask_human is exempt from that budget: the operator's reply must not queue behind capacity. A terminal run reopens on Todo or an explicit dispatch, and on Backlog as idle fill — never on In Progress or In Review, which a human may own or a merge gate may be holding. Predicted file-scope overlap no longer Decision: defer under unknownScopeAdmission: admit (vela default) — worktrees isolate; serialize keeps the Codex-era hold.
    • Codex-era spawn caps removed (AGT-4255). unknownScopeAdmission defaults to admit, per-repo maxConcurrent no longer injects 1 or hard-caps at 10, and worker fan-out follows the candidate list.

    Fixed

    • Concurrent codex-responses reviewers no longer queue inside undici (AGT-4220). chatgpt.com negotiates h2, so Node's global fetch carried concurrent requests as streams over a couple of connections and the Nth reviewer waited for a stream slot before it was ever written to a socket — review --max failed every area at 300 s. A dedicated HTTP/1.1 dispatcher for Codex traffic buys back what a process boundary used to: queue time fell from a 17.30 s median to 0.01 s, and 16 areas at concurrency 16 returned verdicts with no timeouts.
    • .test_venv is ephemeral (AGT-4256). The venv regex missed dotted test venvs, so a publication/BS guard park idled the pool (AGT-3827). Resume treats those paths as non-human parks.
    • Mobile dashboard navigation and panels (AGT-4238). Threads no longer forces a 599 px layout viewport, the new-thread form stays inside its container, navigation is reachable on small screens, and the Orchestration panel can be scrolled to its end. Verified across 6 pages × 5 widths × 2 themes in a real browser.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Sponsored by Atlas Cloud npm version npm downloads license SWE-bench Lite GitHub Discussions

    Agentic CI/CD gate — review, fix, re-review, and deterministic verification for pull requests and local changes

    💬 Help shape OpenSwarm. Share feature ideas, vote on the roadmap, and ask questions in GitHub Discussions. The roadmap is built in the open — your feedback decides what ships next.


    OpenSwarm is an agentic CI/CD gate for the change path that matters: it reviews a committed or working-tree diff, can group and fix confirmed findings in isolated sandboxes, re-reviews the result, then requires deterministic repository checks before it publishes a PR. It runs with OpenAI Codex/GPT, any OpenRouter model, local open-source models (Ollama, LM Studio), or Claude Code (claude -p, opt-in) — with cost-aware routing measured on an L0–L6 benchmark ladder.

    Use it locally before a commit or from the included GitHub Action on a pull request. The Linear-backed autonomous daemon, notifications, and long-term repository memory remain available as an optional orchestration layer; they are not required to use the merge gate.

    Verified on real GitHub issues: the agentic harness solves SWE-bench Lite instances graded by the official harness. Hybrid mode — a frontier model diagnoses read-only, a lightweight model implements with a verification loop — resolved 3/3 attempted instances that every single lightweight model had failed, at a fraction of frontier-only cost. Workers also learn each repository over time: task outcomes are stored as per-repo knowledge and recalled into future prompts. (benchmark rubric & results)

    Sponsors

    OpenSwarm is proudly supported by Atlas Cloud — an enterprise AI infrastructure platform serving fast, stable LLM, image, and video APIs (partnered with OpenRouter and SGLang).

    As an official provider sponsor, Atlas Cloud ships as the built-in atlascloud adapter (OpenAI-compatible Chat Completions, ATLASCLOUD_API_KEY) and provides ongoing monthly API credits that keep the project's autonomous runs going. To run OpenSwarm on Atlas Cloud, grab a key at atlascloud.ai, set ATLASCLOUD_API_KEY, and select adapter: atlascloud.

    Quick Start: Review Gate

    npm install -g @intrect/openswarm
    export OPENROUTER_API_KEY=…              # or use an authenticated codex/claude/local provider
    openswarm review --path . --read-only    # review the current diff without mutation
    openswarm review --max --fix --path .    # fix confirmed findings, re-review, then verify
    

    For CI, use the GitHub Action. For a provider setup wizard, optional Linear connection, TUI chat, or autonomous daemon, run openswarm init and continue with Full Daemon Setup. Prefer wiring a provider by hand? You need one first: openswarm auth login (ChatGPT OAuth, used by codex/gpt), openswarm auth login --provider openrouter (or export OPENROUTER_API_KEY=…), or just have an authenticated claude on PATH. Check what's wired with openswarm auth status, and diagnose any gaps with openswarm doctor.

    What openswarm init sets up

    The wizard asks three questions, detects what you already have, and writes the config for you:

    1. AI provider (worker/reviewer) — it auto-detects existing auth and offers inline login:
      • codex-responses — ChatGPT subscription via OAuth (Codex models, native loop) — easiest start
      • codex — external codex CLI · openrouter — any model (API key/OAuth) · gpt — OpenAI OAuth
      • lmstudio / local — local servers, no account · claude — claude -p CLI (opt-in fallback)
    2. Task backend — local SQLite issue store (no account) or linear (OAuth browser login or API key, then an arrow-key team → project picker for this repo)
    3. Notification channel (optional) — none / discord / slack / telegram / webhook

    It then writes .env (secrets, chmod 600), config.yaml (validated), and — if you mapped a Linear project — openswarm.json (this repo → Linear team/project). Finally it prints next steps and can launch browser OAuth.

    Re-running in a repo that already has config.yaml is refused unless you pass --force, and init refuses to overwrite a config.yaml that symlinks into the daemon's global config. For CI / non-interactive use, openswarm init --yes writes a sample config only.

    TUI Chat Interface

    TUI keyboard shortcuts

    KeyAction
    TabSwitch tabs (Chat / Projects / Tasks / Stuck / Issues / Logs)
    EnterSend message
    Shift+EnterNewline
    iFocus input
    EscExit input focus
    Ctrl+CQuit

    Status bar shows: provider · model · message count · cumulative cost


    CLI Commands

    openswarm                        # TUI chat (default)
    openswarm chat [session]         # Simple readline chat
    openswarm resume                 # Reopen the most recent chat session (conversation + goal)
    openswarm start                  # Start full daemon (requires config.yaml)
    openswarm run "Fix the bug" -p ~/my-project   # Run a single task
    openswarm exec "Run tests" --local --pipeline # Execute via daemon
    openswarm exec --issue INT-123    # Deploy one Linear issue's pipeline async; await/answer elevate
    openswarm init                   # Interactive setup wizard (provider auth, Linear OAuth, config)
    openswarm provider               # Show/switch the active provider (interactive picker)
    openswarm provider claude        # Switch straight to a provider — a running daemon switches in place
    openswarm doctor                 # Diagnose environment (runtime, native deps, providers, ports)
    openswarm validate               # Validate config.yaml
    
    # Code review
    openswarm review                 # Review the working-tree changes
    openswarm review --max           # Full-codebase audit: fan reviewer subagents over areas
                                     #   → report at .openswarm/audit/ + PM-synthesized Linear
                                     #   issues by default (≤10 cohesive, master + sub-issues)
    openswarm review --max --fix     # after the audit, dependency-related findings are grouped;
                                     #   independent fix units run in isolated sandboxes, then
                                     #   a PR is published only after every re-review and trusted
                                     #   deterministic repository check passes
                                     #   add --in-place to edit the current working tree instead
    openswarm review --max --max-files-per-area 6   # finer fan-out — the partition is this knob
                                     #   alone; --concurrency only sets how many run at once
                                     # more --max flags: --no-linear (report only) · --issues-per-area
                                     #   (legacy spray) · --issues <id> (set parent) · --fallback
                                     #   <adapter> · --out <file> · --dry-run (print the plan)
    
    # CI / test gate auto-fix (npm / Cargo / Python auto-detected)
    openswarm fix                    # Run the checks (package.json scripts, or cargo check+test,
                                     #   or ruff/mypy/pytest), fan a fix-worker out over the
                                     #   failures, re-run until green
    openswarm fix --checks lint,test # only these checks · --concurrency <n> · --rounds <n> (default 3)
                                     # any language: put {"checks": {"test": "pytest -x"}} in openswarm.json
    
    # PR autopilot (on-demand — conflict → comments → CI; does not merge)
    openswarm pr status              # Snapshot: conflicts, CI, CHANGES_REQUESTED / critical comments
    openswarm pr status --json       # Machine-readable; exit 0 only when merge-ready
    openswarm pr fix                 # One-shot fix for the current branch's open PR (or --number N)
    openswarm pr review              # Re-apply reviewer feedback only (Claude, Codex, or CHANGES_REQUESTED) — no conflict/CI work
    openswarm pr review --fresh      # Run a brand-new code review of the PR diff and post it as a comment
    openswarm pr review --all        # Review every open PR in the repo instead of just one (combine with --fresh)
    openswarm pr watch               # Loop fix until merge-ready or --rounds exhausted (default 5)
    openswarm pr create              # Local fix → commit → push → gh pr create (from feature branch)
    openswarm pr create --no-fix --issue INT-123 --title "feat: …"  # skip local fix; set issue id
    
    # Code Registry & BS Detector
    openswarm check --scan           # Scan repo → register all entities
    openswarm check src/foo.ts       # File brief (entities, tests, risk)
    openswarm check --bs             # BS pattern scan (bad code smells)
    openswarm check --stats          # Registry statistics
    openswarm check --high-risk      # High-risk entities
    openswarm check --search "name"  # Full-text search
    openswarm annotate "funcName" --deprecate "reason"
    openswarm annotate "funcName" --tag "needs-refactor"
    openswarm annotate "funcName" --warn "error/security: SQL injection"
    

    openswarm review exit codes

    review is designed to work as a CI merge gate, and CI reads nothing but the exit code:

    ExitMeaning
    0The gate ran and did not reject (approve/revise), or there was nothing to review
    1The gate ran and the verdict is reject — with --fix, also when any area is left unresolved or deterministic verification did not pass
    2The gate did not run — no verdict was produced (provider usage limit, adapter failure, unparseable reviewer output). Never treat this as a pass

    Treat any non-zero exit as a failed check. The 1/2 split lets a workflow retry or alert differently when the gate could not run at all (e.g. a quota window exhausted — stderr names the cause and, when known, the reset time).

    Running the gate in CI

    A composite action wraps the whole flow — install, diff against the PR base, review, and map the exit code onto the job result:

    permissions:
      contents: read
      security-events: write   # only needed for the SARIF upload
    
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }   # the merge base has to be present to diff against
      - uses: actions/setup-node@v4
        with: { node-version: '22' }
      - id: review
        uses: unohee/OpenSwarm@main
        with:
          adapter: openrouter   # a hosted runner has no config; without this the CLI
                                # falls back to its `codex` default
          model: deepseek/deepseek-v4-flash  # optional explicit cost cap
        env:
          OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      - if: always() && steps.review.outputs.sarif-file != ''
        uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: ${{ steps.review.outputs.sarif-file }} }
    

    Inputs: path (which checkout to review), base (defaults to the merge base of the PR head and its base branch), adapter, model (optional reviewer model override), read-only, version, sarif-file, and fail-on-gate-not-run — the last defaults to true because a review that did not happen must not read as a pass.

    Outputs: decision, gate-ran, sarif-file.

    Reviewing pull requests safely

    The reviewer reads attacker-authored files with your provider credential in the environment. Two properties keep that from becoming code execution:

    read-only defaults to true, which denies the reviewer every mutating tool including bash. It is enforced per adapter, and an adapter that cannot enforce it refuses to run rather than quietly ignoring the flag:

    AdapterHow read-only is enforced
    openrouter, atlascloud, gpt, codex-responses, local/lmstudioThe agentic loop withholds the mutating, web, and MCP tools, and the executor refuses them if called anyway
    claude--permission-mode default with an allowlist of Read/Grep/Glob, instead of bypassPermissions
    codex--sandbox read-only instead of workspace-write
    anything elseRefused — spawnCli will not start a read-only run on an adapter that has not declared enforcement

    The reviewed checkout never becomes the working directory. OpenSwarm looks for its own config.yaml in the current directory first, so a config committed to the pull request would otherwise choose the run's adapter, model, and MCP servers. The action runs from the runner temp and points --path at the checkout instead.

    Run the action's code from a trusted ref. uses: unohee/OpenSwarm@main already does this — the action code comes from this repository, not from the pull request. It is only uses: ./ that is unsafe, because after checking out a pull request that path holds action.yml as the contributor wrote it, with your secrets in scope. If you self-host the action, check it out from your default branch into its own path and the pull request into another, then point path at the latter — see .github/workflows/review-gate.yml, which does exactly that to dogfood this repository.

    To run it automatically, the trigger is pull_request_target. A pull_request run from a fork gets no secrets, so the provider key would be empty and every fork PR would fail as gate-not-run.

    For scripting without the action, --json prints the verdict on stdout under a versioned schema (the human report is suppressed so openswarm review --json | jq works), and --sarif <file> writes SARIF 2.1.0 for code scanning. Findings are reported at warning: the verdict is what blocks, while individual follow-ups are advisory and some accompany an approve.

    .github/workflows/review-gate.yml in this repository dogfoods the action. It is workflow_dispatch only — the gate calls a paid model on every run, so enabling it for every pull request is left as an explicit choice.

    Deterministic verification

    Autonomous pipelines enable baseline-diff verification by default: OpenSwarm runs repository test/typecheck commands once, compares a failing head against the merge base, and gives the reviewer structured evidence so pre-existing failures do not block unrelated work. Add .openswarm/verify.yaml for repository-specific commands (see templates/verify.example.yaml), or let OpenSwarm discover standard Node, Python, Rust, and Go checks. Configure the behavior under autonomous.verify; the legacy guards.qualityGate whole-tree check is deprecated.

    The Linux sandbox

    On Linux, verification runs each command inside bubblewrap and fails closed when it cannot — running a worker's code unsandboxed to decide whether to trust it defeats the point. On macOS it uses the platform sandbox and needs no setup.

    Installing the package is not always enough, and CI is where that bites:

    EnvironmentWhat it takes
    GitHub Actions ubuntu-latestsudo apt-get install -y bubblewrap and sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0. Measured 2026-08-01: the image sets that restriction to 1, and with it set even bwrap --unshare-user fails at setting up uid map: Permission denied. This repository's own CI asserts the recipe so it cannot go stale.
    Docker, default seccomp--security-opt seccomp=unconfined; add --cap-add SYS_ADMIN if the runtime also drops the capability
    Debian/Ubuntu hostapt-get install -y bubblewrap, usually nothing else
    Alpineapk add bubblewrap

    When the sandbox is unavailable, OpenSwarm says which of these applies rather than reporting a bare failure: it runs bwrap to find out instead of guessing from sysctls, quotes bwrap's own error, and prints the matching fix.

    For crash recovery, fenced execution leases, outbox semantics, rollout modes, and repository admission policy, see Durable autonomous loop. For artifact-bound stage recovery and the opt-in off/shadow/active Recovery Advisor, see Recovery Advisor.

    openswarm exec options

    OptionDescription
    --path <path>Project path (default: cwd)
    --timeout <seconds>Timeout in seconds (default: 600)
    --localExecute locally without daemon
    --pipelineFull pipeline: worker + reviewer + tester + documenter
    --worker-onlyWorker only, no review
    -m, --model <model>Model override for worker
    --jsonEmit machine-readable JSON on stdout (progress logs go to stderr)

    Exit codes: 0 success · 1 failure · 2 timeout

    openswarm exec for a Linear issue (external orchestrator)

    exec --issue runs one Linear issue's worker pipeline asynchronously and hands the run to an external main agent (Claude Code, omp, codex, a script) that watches it, answers it when it stops for input, and lets it continue:

    openswarm exec --issue INT-123 --json
    # {"runId":"<uuid>","identifier":"INT-123","transport":"daemon","deployed":true}
    
    openswarm exec await <uuid> --timeout 3600 --json
    # {"state":"NEEDS_HUMAN","elevation":true,"verdict":"elevation",
    #  "reason":"operator_question","pendingQuestions":[{"correlationId":"hq-…",
    #  "questionClass":"clarification"}],"hint":"openswarm exec answer …"}
    
    openswarm exec answer <uuid> --correlation hq-… --text "use the staging DB" --json
    # {"resumed":"READY","transport":"daemon"}
    

    await prints the elevation JSON when the run parks (NEEDS_HUMAN, NEEDS_SPEC, NEEDS_ENV, NEEDS_RECONCILE) or finishes; its exit code is 0 terminal, 1 elevated, 2 still running (re-invoke it — the run keeps going). A deploy is asynchronous, so await keeps polling if the ledger row is not there yet: openswarm exec --issue … && openswarm exec await … waits through the gap. answer replies to the coordination board as actorRole: 'orchestrator' and resumes the ledger row; --correlation must belong to the run named on the command line, or it is refused rather than written against the wrong issue. Deploy and answer both record an exec hold so the daemon's idle_fill cannot silently re-run the parked task behind the orchestrator's back; the hold expires after 24 h of silence and is refreshed by every answer.

    status/await/answer need only the UUID, so they work with Linear unconfigured; --issue resolves the identifier through Linear. Deploying needs the repo's openswarm.json Linear mapping and the issue in a deployable state (Todo, Backlog, In Progress). A daemon that is unreachable is retried as a detached local child; a daemon that is up but refuses — a 403/401/503 on its own /api/stats probe, or an HTTP error or queued:0 on /api/work — is reported as-is and never routed around with a local child. If the daemon is up but refusing, add the repo to the daemon's autonomous.allowedProjects or check the daemon auth token.


    Full Daemon Setup

    For autonomous operation (Linear issue processing, Discord control, PR auto-improvement), you need a full config:

    Prerequisites

    • Node.js >= 22
    • At least one LLM provider:
      • OpenAI Codex — codex-responses (ChatGPT OAuth, native loop, no extra binary) is the smoothest start; codex delegates to the external Codex CLI. openswarm auth login handles the ChatGPT OAuth
      • OpenRouter — any model; OPENROUTER_API_KEY or openswarm auth login --provider openrouter
      • OpenAI GPT — openswarm auth login --provider gpt
      • Local — LM Studio (lmstudio, :1234) or Ollama (local, :11434), auto-detected, no auth
      • Claude Code CLI (claude -p) — opt-in fallback; an authenticated claude on PATH
    • Native build toolchain — better-sqlite3 and @lancedb/lancedb are native modules. Prebuilt binaries cover common platforms; if yours lacks one, npm install builds from source and needs python3 + a C/C++ toolchain (build-essential on Linux, Xcode Command Line Tools on macOS)
    • For autonomous mode only (optional): Linear — sign in with openswarm auth login --provider linear (OAuth PKCE) or use an API key + team ID; Discord bot token (message content intent); GitHub CLI (gh) for CI monitoring

    Configuration

    After the global install, run the wizard in the directory you want the daemon to manage — it writes everything for you:

    openswarm init      # writes config.yaml + .env (provider, task backend, notifications)
    openswarm doctor    # verify providers, native deps, ports
    

    See What openswarm init sets up for the prompts. Prefer to edit by hand? config.yaml supports ${VAR} / ${VAR:-default} substitution (resolved from .env) and is validated with Zod. A minimal .env (the wizard writes only what your choices need):

    LINEAR_API_KEY=your-linear-api-key      # or: openswarm auth login --provider linear
    LINEAR_TEAM_ID=your-linear-team-id
    DISCORD_TOKEN=your-discord-bot-token    # only if you chose the discord notifier
    DISCORD_CHANNEL_ID=your-channel-id
    

    Key configuration sections

    SectionDescription
    discordBot token, channel ID, webhook URL
    linearAPI key, team ID
    githubRepos list for CI monitoring
    agentsAgent definitions (name, projectPath, heartbeat interval)
    autonomousSchedule, pair mode, role models, decomposition settings (maxChildrenPerTask applies to both the runner and human /plan; dailyLimit paces the unsupervised runner only — AGT-4123)
    autonomous.includeBacklogTreat Linear Backlog as a work queue (default false: moving an issue to Todo is the ready signal; set true on a deployment that wants free slots to chew the Backlog)
    autonomous.unknownScopeAdmissionadmit (default): worktrees isolate — predicted file overlap does not defer. serialize: Codex-era fail-closed
    prProcessorPR auto-improvement schedule, retry limits, conflict resolver config

    CLI Adapter (Provider)

    adapter: codex   # codex · codex-responses · cc-router · cursor · gpt · openrouter · atlascloud · lmstudio · local · claude
    

    adapter accepts one of the registered values below (validated by Zod). For a ChatGPT subscription, codex-responses is the smoothest first-run choice — it runs OpenSwarm's native loop over the Responses API with no extra binary. Switch at runtime via Discord, e.g. !provider codex-responses / !provider openrouter.

    AdapterBackendModelsAuth
    codex-responsesOpenAI Responses API (native loop, no CLI binary)gpt-5.6-terra (default), gpt-5.6-sol, gpt-5.6-lunaChatGPT OAuth
    codexOpenAI Codex CLI (delegated)gpt-5-codex (default), o3, o4-miniChatGPT OAuth / codex CLI auth
    cc-routerLocal CC-Router Responses endpoint (native loop)Router's live model catalogExisting CC-Router account pool
    cursorCursor Agent CLI (delegated, sandbox enabled)Cursor account model catalogExisting cursor-agent login session
    gptOpenAI Chat APIgpt-4o (default), o3, …OAuth PKCE
    openrouterOpenRouter API (native agentic loop)any OpenRouter model — gpt-5, gemini-2.5, deepseek, glm, qwen, …OPENROUTER_API_KEY or OAuth PKCE
    atlascloudAtlas Cloud API (native agentic loop) · sponsorAtlas models — deepseek-v4-pro (default), qwen3.5-flash, …ATLASCLOUD_API_KEY
    lmstudioLM Studio (OpenAI-compatible, local)loaded LM Studio model (LMSTUDIO_MODEL)None
    localOllama (local, auto-detected)gemma, llama, qwen, mistral, …None
    ollama-cloudOllama cloud models (native agentic loop) — via a signed-in local server, or direct ollama.com with a keydeepseek-v4.1-flash (default), glm-5.3, kimi-k2.6, minimax-m3, gemma4:31bLocal Ollama sign-in, or OLLAMA_API_KEY

    Claude Code (claude -p) is supported as an opt-in fallback (and powers the claude -p chat path) — install the claude CLI and authenticate it; openswarm init and openswarm doctor detect it. It is a valid adapter: value, but opt-in: nothing falls back to it automatically. Switch to it when another provider runs out of quota with openswarm provider claude.

    reviewAdapter — a second opinion from a second provider
    adapter: codex-responses      # what the worker runs on
    reviewAdapter: openrouter     # what `openswarm review` and `openswarm review --max` run on
    

    Review is a second opinion, so running it on the provider that wrote the code is a correlated failure — and that provider's quota is the one already spent. reviewAdapter sets the reviewer's adapter for openswarm review (working-tree and --base diffs) and for openswarm review --max (the batch audit, including its fix/verify rounds and the claude fallback decision). Precedence: --adapter flag → OPENSWARM_REVIEW_ADAPTER → reviewAdapter → adapter; both commands print the winning source under --debug (Reviewer adapter: openrouter (config.reviewAdapter)). Omit it to review on adapter.

    The openrouter adapter runs OpenSwarm's own agentic tool loop (read/search/edit/bash with verification guards), enables ZDR (data_collection: deny) for non-OpenAI models, and applies Anthropic prompt caching automatically. Local backends are auto-detected on standard ports (Ollama :11434, LM Studio :1234); use lmstudio for a dedicated LM Studio endpoint (LMSTUDIO_BASE_URL, default http://localhost:1234).

    ollama-cloud reaches Ollama's cloud models over whichever transport you have. With no key set it uses the local server at :11434, which proxies cloud models under its own ollama signin — so no API key is needed. Set OLLAMA_API_KEY (and leave OLLAMA_CLOUD_BASE_URL unset) to call https://ollama.com directly instead. The two transports disagree about model ids: the direct API takes deepseek-v4.1-flash, while the local server requires deepseek-v4.1-flash:cloud; the adapter spells the id for the transport in use, so either form is accepted as configuration. OLLAMA_CLOUD_MODEL overrides the default. Note that cloud models are deliberately absent from the local server's model list, which is why the adapter carries its own curated list.

    Autonomous coordination and supervision

    Each autonomous run snapshots the current Claude Code instruction hierarchy (~/.claude/CLAUDE.md, user rules, repository CLAUDE.md/AGENTS.md, and matching .claude/rules) once and applies the same capsule to orchestrator, worker, reviewer, Codex, CC-Router, and Cursor. The dashboard shows the capsule digest and source/error counts, not the rule bodies.

    adapterRouting.primary must name the adapter the worker actually runs (adapter: at the top of the config, or roles.worker.adapter); a policy whose primary is some other adapter is ignored, and the fallbacks never engage. Role MCP grants and the coordination tools (coordination_read, coordination_peers, coordination_publish, coordination_thread_*, ask_human) additionally require an adapter that runs OpenSwarm's own tool loop — codex-responses, cc-router, gpt, openrouter, atlascloud, lmstudio, local. The delegated CLIs (codex, claude, cursor) bring their own tool loop, so those grants do not reach them; for interactive CLI use OpenSwarm logs a warning rather than pretending they applied. The daemon is stricter: a config with an autonomous section that names a delegated adapter anywhere (adapter, defaultRoles, projectAgents roles, adapterRouting primary or fallbacks, orchestrator, loopAdvisor) refuses to start unless autonomous.allowDelegatedAdapters: true accepts the missing fences on purpose.

    A configured coordinationBoardIssueId turns one project-scoped tracker issue into the durable agent board. Worker advice/delegation, Discord questions, adapter routes, periodic reviews, and MCP denials are visible through GET /api/coordination, SSE, and the AGENT COORDINATION dashboard panel. Tool arguments, prompts, credentials, and rule bodies are redacted or omitted.

    With autonomous.enabled: false, the runner still accepts explicit issue-board and openswarm work dispatches without selecting backlog work. Transient durable-admission deferrals remain queued across a hard restart: only rows recorded as explicit claim_deferred work are rebuilt, at their original RETRY_AT deadline. Operator waits, provider backoffs, failures, terminal tracker cards, and publication reconciliation are never promoted by this path.

    The transient inbox and the repository discussion board have separate jobs. /threads stores topics, messages, subscriptions, unread cursors, and CAS resolution in the automation SQLite database under the canonical Git repository cell, so sibling worktrees and daemon restarts share one history. Replies wake subscribed agents on their task-scoped inbox; /orchestration remains the live event/agent graph.

    autonomous:
      coordinationBoardIssueId: AGT-3993
      adapterRouting:
        primary: codex-responses
        fallbacks: [cc-router]   # `cursor` is a delegated CLI: add it only with allowDelegatedAdapters: true
        allowReasons: [quota, infra, capability]
      mcpPolicies:
        orchestrator:
          servers: [github, linear, cloudflare]
          writeTools: [linear__save_comment]
      periodicReviews:
        - { profile: hygiene, schedule: "43 */6 * * *" }
      # Frontier project supervisor. Events provide the fast path; cron reconciles
      # anything missed while the daemon was down.
      orchestrator:
        enabled: true
        schedule: "17 */2 * * *"
        eventDriven: true
        eventDebounceMs: 1000
        adapter: codex-responses
        model: gpt-5.6-sol
        reasoningEffort: high
        timeoutMs: 600000
        maxTurns: 12
    

    Every agent has a call sign — Magos Corvax-Vigilis, Adept Ferrus-Umbra — and messages are addressed to it. The name is derived from the repository, task, and role rather than randomly assigned, so it is stable across a restart or a retry and doubles as the agent's mailbox address; the worker and the reviewer on one task never share one. Call signs appear in the dashboard, in board comments, and in each agent's own prompt.

    The project supervisor is separate from worker provider switching: pin its adapter and model explicitly when it must remain on the frontier tier. Only native-loop adapters can receive the role-scoped MCP tools while also enforcing shellTools: false; delegated codex, claude, and cursor CLIs fail closed. External MCP servers are optional: with no mcpPolicies.orchestrator entry, or when discovery is temporarily unavailable, the supervisor still runs with only the repository-scoped coordination inbox, thread tools, and a native cache-first tracker bridge. The bridge reads the daemon heartbeat cache before any single- issue lookup, can save only an idempotent comment to an issue already linked on that repository's coordination board, and is available only to the orchestrator role. This lets the supervisor settle evidence-backed worker questions without copying OAuth state or granting every worker broad Linear access. No external tool is granted implicitly, and decisions requiring new business authority stay with the operator.

    External human-facing surfaces have a stricter global boundary than the role grant above. Slack, Discord, email, Notion, and other messaging/collaboration servers are identified from the configured server descriptor, endpoint/package identity, tool action, and MCP annotations; custom opaque aliases should set mcp.servers.<name>.surface: human. Only actions containing an explicit read, list, get, search, or fetch verb are exposed or dispatched. send, post, create, update, delete, unknown actions, and equivalent mutations fail closed even if a role includes their exact name in writeTools or destructiveTools. MCP annotations are untrusted hints: they may tighten the decision but cannot turn a mutating action into a read. GitHub, Linear, Cloudflare, database/server tools, and sandbox-local data tools keep their existing role-scoped write contract.

    Generic MCP HTTP/proxy tools are reclassified again at dispatch from their actual destination, method, and body arguments. An explicit GET, HEAD, or OPTIONS to Slack, Discord, Notion, Gmail, or a human-facing Microsoft Graph path remains readable; a write, dynamic destination, or ambiguous call fails before the MCP server is invoked. Concrete writes through a generic transport also require a write-declaring tool descriptor, the server to declare surface: devops, data, or sandbox, and (for autonomous roles) the same exact writeTools grant as any other mutation. Microsoft Graph device/directory paths remain DevOps; mail, message, calendar, chat, drive, and other human-facing paths do not. Specialized tools do not scan ordinary payload text, so a GitHub issue body that merely quotes a Slack URL is not mistaken for a network destination.

    For unattended deployments, enable the complete execution boundary explicitly:

    humanSurfaceReadOnly:
      enabled: true
      sandboxExecutor:
        enabled: true
        socketPath: /run/openswarm-sandbox/executor.sock
        allowedRoots: [/work]
        connectTimeoutMs: 1000
        maxRequestBytes: 65536
        maxOutputBytes: 524288
        maxTimeoutMs: 900000
        maxConcurrent: 8
    

    With this switch on, OpenSwarm does not attempt to classify arbitrary programs. It keeps compiler-spawning diagnostics disabled, refuses delegated CLI adapters before availability/model discovery or command construction, and exposes native bash only through the separately deployed companion after exact attestation. The main daemon never spawns that command. The sidecar has network_mode: none, no daemon config/env file/provider state/warehouse/HOME or host service sockets, and a minimal child environment. Its trusted server can register a /work checkout, but each command receives a new bwrap mount/PID namespace with only that inode-stable workspace writable, git metadata and linked dependencies read-only, /run hidden, and known sensitive workspace files overlaid. The sidecar TCB still sees the broad /work mount to perform registration and mask preflight; do not describe the TCB itself as secret-free. Use a native-loop adapter; local web chat remains available with file tools, read-only web access, and policy-filtered MCP tools. Approved typed DevOps/data writes keep their existing role grants. OpenSwarm-owned Discord, Slack, Telegram, and generic webhook notification/send paths are all disabled—there is no operator-control-plane exception. The default is false for compatibility; the MCP human-surface descriptor and dispatch checks still apply regardless. Once enabled, the boundary is monotonic for that process so an incidental config lookup cannot downgrade it; restart with enabled: false to disable it.

    Linux deployment readiness gate: strict mode does not turn an unsandboxed shell back on just to recover build throughput. Repository-local build/test execution is available only after the sidecar proves loopback works while no veth/default route/external TCP/UDP/DNS path exists, and proves its bwrap mount/PID namespace with a real command. The Unix protocol is one newline- delimited JSON frame per connection with hard request/response caps, exact-key schemas, private same-uid directory/socket checks, an executor boot generation, and an opaque inode-bound workspace token. It is not a durable job ledger: if a side-effecting RPC loses its response, OpenSwarm reports OUTCOME_UNKNOWN_DO_NOT_RETRY, stops the loop, preserves the worktree and parks the durable run for explicit inspection/redispatch instead of replaying it. Server/database mutations are safe only through explicitly surfaced, role- granted DevOps/data MCP tools. If the host cannot create the verification namespace (for example, bwrap is blocked by the container runtime) and no typed MCP grant is provisioned, the deployment is coordination/file-only and is blocked for autonomous development. Do not compensate by enabling native or delegated shell access: that would also restore the unclassifiable human-API write path. On such a host, first make the existing sandbox probe pass or add the narrowly scoped MCP server/tool grants, then re-run the build/test and zero-write checks.

    One sweep runs at a time per daemon and repository, concurrent daemons contend on a file lock, and shutdown aborts then drains an active supervisor call. An unchanged set of open board items is not sent to the model again. The deprecated orchestratorSchedule key is still accepted as a cron-only, daemon-provider compatible configuration, but new deployments should use orchestrator. The native-loop supervisor also receives its repository-cell coordination identity, so it can discover peers and create, join, or reply to durable threads without gaining shell access to a worktree.

    When cached tracker/dependency facts still leave a real tie, conflict cohort, or high-impact ordering question, orchestrators can open a durable priority council on an existing cross-task coordination thread. A proposal contains 2–8 options and the versioned cached evidence behind them; opening it never queries Linear. Eligibility is frozen from recently active independent peers, candidate-task participants may submit evidence but cannot vote, and each actor+task pair gets one equal-weight ranked ballot. Finalization is version-CAS guarded and records quorum, cross-task/cross-role participation, tally, cited evidence, expiry, and the deterministic taskId then optionId tie-break, independent of proposal array order. Only an orchestrator may open a council through agent tools; the authenticated operator HTTP route remains available for explicit intervention.

    The resulting signal is deliberately advisory. coordination_council_consume is orchestrator-only and can reorder only the existing option cohort's slots when the council and cached snapshot versions still match. Its authority contract explicitly forbids starting tasks, bypassing dependencies or file leases, merging, destructive tools, and tracker mutation. The HTTP API exposes list/read, operator proposal/evidence, and CAS finalization under /api/coordination/councils; it intentionally has no vote endpoint because a request body cannot establish an agent's actor/task identity. Ballots use the trusted agent-tool context instead.

    For automatic Decision Engine consumption, include scheduling_facts for every option (priority, topology/due fields, downstream count, blockers, and tracker state) and open with snapshot_version: auto. OpenSwarm stores a canonical sched-v1 digest, recomputes it from the already-fetched task cache on each heartbeat, CAS-consumes at most the newest matching finalized council, and then changes only those tasks' existing slots. Repository scope comes only from a task's explicit project path or the linear.projectId in that repository's openswarm.json; an absent or ambiguous mapping fails closed. A missing database, manual-only or no-quorum decision, stale facts, CAS race, partial cohort, cross-repository match, or invalid authority is a no-op that preserves deterministic ordering; none of these paths triggers another Linear request.

    Blocking questions are sent to the configured Discord channel as !answer <correlation-id> <answer>. Only users in DISCORD_ALLOWED_USERS can settle them. The asking run stops and reports rather than guessing a default, and the question stays open on the board until someone answers — the answer is addressed back to the call sign that raised it, so the next run of that agent reads it from its inbox. When Discord is not configured the tool says so instead of claiming the operator was paged.

    Per-role adapter overrides (each role may pick its own valid adapter + model):

    autonomous:
      defaultRoles:
        worker:
          adapter: codex-responses
          model: gpt-5.6-terra
        reviewer:
          adapter: openrouter
          model: anthropic/claude-sonnet-4
    

    Optional backlog grooming runs a read-only Planner over the fetched open queue states for a mapped project (Todo, In Progress, In Review, and Backlog) and compares them with the current repo. Keep mode: comment while validating recommendations; mode: apply can update drifted descriptions and move strongly stale issues to Done.

    autonomous:
      backlogGrooming:
        enabled: false
        cadenceHours: 24
        mode: comment
        plannerModel: gpt-5.6-terra
        maxIssues: 80
    

    Agent Roles

    autonomous:
      defaultRoles:
        worker:
          model: gpt-5.6-terra            # balanced default implementation
          escalateModel: gpt-5.6-sol      # frontier retry after a failed attempt
          escalateAfterIteration: 2
          timeoutMs: 1800000
        reviewer:
          model: gpt-5.6-sol              # correctness gate
          timeoutMs: 600000
        tester:
          enabled: false
          model: gpt-5.6-terra            # LLM fallback after deterministic verify
        documenter:
          enabled: false
          model: gpt-5.6-luna
        auditor:
          enabled: false
          model: gpt-5.6-sol
        skill-documenter:
          enabled: false
          model: gpt-5.6-luna
      jobProfiles:
        - name: light
          minMinutes: 1
          maxMinutes: 29
          effort: low
          roles:
            worker: gpt-5.6-luna
            reviewer: gpt-5.6-terra
        - name: heavy
          minMinutes: 30
          effort: high
          roles:
            worker: gpt-5.6-terra
            reviewer: gpt-5.6-sol
    

    The native Codex adapter uses Terra when no model is pinned. Draft analysis uses Luna because it runs for every task; decomposition and hard review stay on Sol.

    Running the daemon

    With the global install, the openswarm CLI manages the daemon directly — no repo or npm run scripts needed:

    openswarm start               # start the daemon in the background
    openswarm start --foreground  # run attached (logs stream to the terminal)
    openswarm status              # pid, uptime, log path
    openswarm stop                # stop the daemon
    openswarm dash                # open the web dashboard (:3847)
    openswarm cost --since 24h    # LLM spend by model (--by stage|task|project|adapter|day|hour, --json)
    

    Every model API call is appended to ~/.openswarm/usage/<UTC date>.jsonl with the provider's own metered price when it reports one (OpenRouter prices every response; subscription and local providers are recorded as unmetered). The same aggregate is served at GET /api/usage?since=24h&by=model.

    From source / development (contributors): clone the repo and use the npm run … scripts (npm run dev, npm start, npm run service:install for a macOS launchd service, docker compose up -d). See CONTRIBUTING.md.

    Run with Docker

    The repository ships a production image for the headless daemon (web dashboard on :3847, openswarm CLI on PATH). Published images live at ghcr.io/unohee/openswarm (tagged per release); building locally works the same way:

    # Pull a release, or build from the repo
    docker pull ghcr.io/unohee/openswarm:latest   # or: docker compose build
    
    cp config.example.yaml config.yaml            # edit adapter/projects/keys
    export OPENSWARM_WEB_TOKEN=$(openssl rand -hex 24)  # required to expose the dashboard
    docker compose up -d                          # normal daemon
    curl http://localhost:3847/api/health         # daemon health (token-less)
    

    Strict native-shell execution is an opt-in deployment. It adds the isolated companion and makes the daemon wait for its real health proof before startup:

    # Ubuntu/AppArmor hosts: install the repository-scoped companion profile.
    # This keeps AppArmor enforced; do not use apparmor=unconfined.
    sudo install -m 0644 deploy/apparmor/openswarm-sandbox-executor \
      /etc/apparmor.d/openswarm-sandbox-executor
    sudo apparmor_parser -r /etc/apparmor.d/openswarm-sandbox-executor
    
    sudo install -d -o 1001 -g 1001 -m 0700 sandbox-socket
    export OPENSWARM_IMAGE="openswarm:$(git rev-parse --short=12 HEAD)"
    export OPENSWARM_WORKSPACE="$(pwd)/workspace" # use the real absolute workspace root
    docker compose -f docker-compose.yml -f docker-compose.strict-sandbox.yml build
    docker compose -f docker-compose.yml -f docker-compose.strict-sandbox.yml up -d
    

    Set both humanSurfaceReadOnly.enabled and humanSurfaceReadOnly.sandboxExecutor.enabled to true in config.yaml. Before starting, confirm that OPENSWARM_WORKSPACE contains every configured /work/<repo> checkout. After the build, both services must resolve to the same OPENSWARM_IMAGE image ID; keep the prior immutable image tag for rollback. Do not rely on a pre-existing mutable openswarm:latest image.

    Without OPENSWARM_WEB_TOKEN the dashboard binds only inside the container — an unauthenticated all-interfaces bind is refused by design — so the published port answers nothing while the daemon itself keeps running. With the token set, browser/API access from the host sends it as the X-OpenSwarm-Token header (/api/health stays token-less).

    The compose file wires the persistent and local-data mounts that matter:

    MountPurpose
    ./config.yaml → /app/config.yamldaemon configuration (read-only)
    openswarm-state → /home/openswarm/.openswarmtask state, auth profiles, coordination board — must persist, and one container per state volume (two daemons sharing it would fight over locks and double-process issues)
    ./workspace → /workthe repositories the daemon works on; point autonomous.allowedProjects at /work/<repo>
    ./sandbox-socket → /run/openswarm-sandboxprivate uid-1001/mode-0700 Unix-socket directory; daemon read-only, sidecar read-write
    ../openswarm-warehouse → /warehouseagent-readable, Git-external local assets (read-only)
    ../openswarm-warehouse → /warehouse-rwoperator upload path used only by the authenticated /warehouse web UI

    Notes:

    • Provider CLIs are not baked in. The default codex-responses adapter runs OpenSwarm's own tool loop against OAuth state — log in on the host (openswarm auth login) and mount ~/.codex / reuse the state volume. For the delegated CLI adapters (claude, codex, cursor), derive your own image: FROM ghcr.io/unohee/openswarm + npm install -g <cli>.
    • Git identity: mount ~/.gitconfig or set GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL (and GH_TOKEN for gh) so worker commits and PRs attribute correctly.
    • Verify sandbox: bubblewrap is installed but fail-closed under Docker's default seccomp profile. Enabling it requires security_opt: [seccomp=unconfined] + cap_add: [SYS_ADMIN] (commented in docker-compose.yml) — weigh that against your threat model.
    • Strict shell companion: the optional compose override starts a root launcher only long enough for setpriv to enter uid/gid 1001. The non-root Node server retains ambient SYS_ADMIN, SETUID, read-only DAC_READ_SEARCH, and NET_ADMIN because bubblewrap 0.8 rejects capabilities at a non-root uid and resolves --bind-fd sources through /proc/self/fd: each execution uses SETUID to launch bwrap as uid 0, while DAC_READ_SEARCH lets that launcher traverse mode-0700 worktrees without granting writes. Every command receives its own network namespace; NET_ADMIN only raises that namespace's loopback interface so localhost test servers work, while two concurrent workspaces can bind the same port without seeing each other. It then immediately returns the requested command to uid 1001 with permitted/effective/inheritable/ambient capabilities cleared. SETGID is used only by the initial launcher and is not retained by Node. The production probe requires child uid 1001, zero active capabilities, isolated concurrent localhost listeners, and failed external TCP/UDP/DNS before the socket becomes ready. The Compose override requires the repository's openswarm-sandbox-executor AppArmor profile: Docker's default profile denies bubblewrap mounts and Ubuntu's global /usr/bin/bwrap profile strips the namespace setup capability. The scoped profile keeps AppArmor enforced and inherits /usr/bin/bwrap instead of transitioning to that global child profile. If it is missing or the real host still denies bwrap, the container stays unhealthy and strict bash remains unavailable. Do not add apparmor=unconfined as a workaround. .env, .env.*, .dev.vars, .envrc, .npmrc, .pypirc, .netrc, credential/key files, and secret directories are masked inside command namespaces even while empty; only .env.example, .env.sample, and .env.template are intentional examples.
    • Strict deterministic verification: disposable HEAD/base Git sandboxes are created beneath the configured /work root and their commands use the same attested companion. A missing socket, root mismatch, or contract failure becomes a blocking security result; the main daemon never falls back to its own bwrap or unsandboxed shell.
    • Local asset warehouse: create ../openswarm-warehouse/INDEX.md, then open /warehouse in the dashboard to browse, download, or upload. Agents are prompted to inspect /warehouse/INDEX.md before asking for gitignored data. See docs/WAREHOUSE.md.

    Architecture

    Agent-oriented module map, admission gates, and landmines: ARCHITECTURE.md.

                             ┌──────────────────────────┐
                             │       Linear API          │
                             │   (issues, state, memory) │
                             └─────────────┬────────────┘
                                           │
                     ┌─────────────────────┼─────────────────────┐
                     │                     │                     │
                     v                     v                     v
      ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐
      │ AutonomousRunner │  │  DecisionEngine  │  │  TaskScheduler   │
      │ (heartbeat loop) │─>│  (scope guard)   │─>│  (queue + slots) │
      └────────┬─────────┘  └──────────────────┘  └────────┬─────────┘
               │                                            │
               v                                            v
      ┌──────────────────────────────────────────────────────────────┐
      │                      PairPipeline                            │
      │  ┌────────┐   ┌──────────┐   ┌────────┐   ┌─────────────┐  │
      │  │ Worker │──>│ Reviewer │──>│ Tester │──>│ Documenter  │  │
      │  │(Adapter│<──│(Adapter) │   │(Adapter│   │  (Adapter)  │  │
      │  └───┬────┘   └──────────┘   └────────┘   └─────────────┘  │
      │      │  ↕ StuckDetector                                      │
      │  ┌───┴────────────────────────────────────────────────────┐  │
      │  │ Adapters: Codex | GPT | OpenRouter | Local (Ollama)   │  │
      │  └────────────────────────────────────────────────────────┘  │
      └──────────────────────────────────────────────────────────────┘
               │                     │                     │
               v                     v                     v
      ┌──────────────┐  ┌──────────────────┐  ┌──────────────────┐
      │  Discord Bot │  │  Memory (LanceDB │  │  Knowledge Graph │
      │  (commands)  │  │  + Xenova E5)    │  │  (code analysis) │
      └──────────────┘  └──────────────────┘  └────────┬─────────┘
                                                        │
                                               ┌────────┴─────────┐
                                               │  Code Registry   │
                                               │  (SQLite + FTS5) │
                                               │  + BS Detector   │
                                               └──────────────────┘
    

    Features

    • Multi-Provider Adapters — Pluggable adapter system: OpenAI Codex/GPT, OpenRouter (any model, native agentic loop), local models (Ollama, LM Studio), and Claude Code (claude -p, opt-in) with runtime provider switching
    • Code Registry — SQLite-backed entity registry tracking every function/class/type across 8 languages, with complexity scoring, test mapping, and risk assessment
    • BS Detector — Built-in static analysis engine that detects bad code patterns (empty catch, hardcoded secrets, as any, etc.) with pipeline guard integration
    • Autonomous Pipeline — Cron-driven heartbeat fetches Linear issues, runs Worker/Reviewer pair loops, and updates issue state automatically
    • Worker/Reviewer Pairs — Multi-iteration code generation with automated review, testing, and documentation stages
    • Codebase Audit (review --max) — fans reviewer subagents out over directory-shaped areas (partitioned by --max-files-per-area; --concurrency only sets how many run at once, so one file set gets one verdict), aggregates a deduped verdict into a markdown report, and synthesizes ≤10 cohesive Linear issues via a PM agent. Both review modes consult repository-local prior review logs; resolved/stale findings are not repeated, and byte-identical duplicate follow-ups are suppressed while unresolved issues remain visible. A review of content this deployment already reviewed is replayed from a durable (kind, base, content digest) store instead of re-paying for the reviewer, and that store survives a daemon restart. --fix groups findings by repository dependency closure, injects the package manager/manifests/verification contract and repo knowledge, runs only independent fix units concurrently in isolated sandboxes, and promotes disjoint in-scope diffs into an audit worktree. It publishes the PR only when every area re-approves and trusted deterministic verification passes; unavailable dependencies/checks fail closed. --in-place keeps edits in the current working tree but uses the same gates. Language-agnostic; codex usage-limit aware with automatic claude fallback
    • CI / test gate auto-fix (openswarm fix) — runs the project's objective checks (lint / typecheck / build / test), groups the failures by file into areas, fans a fix-worker out over each, then re-runs the checks and repeats until green (or the round budget). Deterministic convergence — unlike the review fix pass, it verifies its own work. Multi-language: auto-detects npm scripts, Cargo.toml (cargo check/test, clippy on request), and Python tooling (ruff/mypy/pytest, gated on the repo's config); any other toolchain via a "checks" map in openswarm.json
    • PR autopilot (openswarm pr) — on-demand surface over the daemon's PRProcessor + commitAndCreatePR. status reports conflicts / review feedback / CI; fix runs one autopilot pass (conflict → comments → CI); review re-applies reviewer feedback only, skipping conflict/CI work — recognizes Claude, Codex, and any formal CHANGES_REQUESTED review; review --fresh instead runs a brand-new code review of the PR's current diff (the same reviewer openswarm review uses) and posts the verdict as a PR comment, independent of any existing feedback; review --all reviews every open PR in the repo sequentially (combine with --fresh) instead of just the current branch's PR or --number; watch loops until merge-ready; create publishes the current feature branch (local fix → commit → push → gh pr create). Never merges or enables auto-merge.
    • Decision Engine — Scope validation, priority-based task selection, and workflow mapping
    • Cognitive Memory — LanceDB vector store with Xenova/multilingual-e5-base embeddings for long-term recall across sessions
    • Repo Knowledge Loop — workers learn each repository over time: task outcomes (success patterns, review-rejection pitfalls) are stored per-repo and recalled into the next worker prompt
    • SWE-bench Verified — the agentic harness solves real SWE-bench Lite issues, graded by the official harness; hybrid mode (frontier diagnosis + lightweight implementer) resolved 3/3 attempted instances (benchmarks/RUBRIC.md)
    • Knowledge Graph — Static code analysis, dependency mapping, impact analysis, and file-level conflict detection across concurrent tasks
    • Discord Control — Full command interface for monitoring, task dispatch, scheduling, provider switching, and pair session management
    • Rich TUI Chat — Claude Code inspired terminal interface with tabs, streaming responses, and geek-themed loading messages
    • Dynamic Scheduling — Cron-based job scheduler with Discord management commands
    • PR Auto-Improvement — Monitors open PRs, auto-fixes CI failures, auto-resolves merge conflicts, and retries until all checks pass
    • Long-Running Monitors — Track external processes (training jobs, batch tasks) and report completion
    • Web Dashboard — Real-time pipeline stages, cost tracking, worktree status, and live logs on port 3847
    • Failure Safety — Provider quota holds, bounded retry backoff, durable leases, and repository conflict fencing without artificial throughput caps
    • i18n — English and Korean locale support

    How It Works

    Linear (Todo / In Progress / In Review / Backlog)
      → Fetch assigned issues
      → filterAlreadyProcessed (idle_fill parks/backoff when slots are free)
      → DecisionEngine filters & prioritizes (still skips Done/Canceled, parent/EPIC, unresolved deps)
      → detectSafeCandidateIds (`admit` does not defer on predicted file overlap)
      → Resolve project path via projectMapper
      → PairPipeline.run()
        → Worker generates code (via the configured adapter)
        → Reviewer evaluates (APPROVE/REVISE/REJECT)
        → Loop up to N iterations
        → Optional: Tester → Documenter stages
      → Update Linear issue state (Done/Blocked)
      → Report to Discord
      → Save to cognitive memory
    

    Memory System

    Hybrid retrieval: 0.60 × similarity + 0.25 × importance + 0.15 × recency

    Memory types: belief · strategy · user_model · system_pattern · constraint

    Background: decay, consolidation, contradiction detection, distillation.

    Embeddings run locally via @huggingface/transformers (ONNX, no external service). The default is Xenova/multilingual-e5-base (768d, int8), stored text is embedded as a passage: and searches as a query: per the E5 asymmetric convention. Weights are cached in ~/.openswarm/models so reinstalling OpenSwarm does not discard them.

    VariablePurpose
    OPENSWARM_EMBEDDING_MODELHugging Face repo id. Models outside the known table must also set OPENSWARM_EMBEDDING_DIM.
    OPENSWARM_EMBEDDING_DIMVector dimension. Required for unknown models — a wrong value silently produces an unsearchable table.
    OPENSWARM_EMBEDDING_DTYPEONNX weight variant: q8 (default), q4, q4f16, fp16, fp32.
    OPENSWARM_MODEL_CACHE_DIROverride the weight cache location.

    Changing any of these invalidates every stored vector: the store records an embedding signat