Open-source swarm-native coding agent orchestrator. Fork of rlm-cli extended with parallel coding agent threads in isolated git worktrees.
Published: npm install -g swarm-code / npx swarm-code
Repo: https://github.com/kingjulio8238/swarm-code
# Install deps
npm install
# Development (Swarm mode)
npx tsx src/main.ts --dir ./my-project "add error handling"
# Development (Interactive mode)
npx tsx src/main.ts --dir ./my-project
# Development (MCP server)
npx tsx src/main.ts mcp --dir ./my-project
# Development (RLM text mode)
npx tsx src/main.ts run --file data.txt "analyze this"
# Build
npm run build- Node.js >= 20
- Python 3.x (for the REPL runtime — checked at startup with a clear error if missing)
- npm (not pnpm — this project uses package-lock.json)
npm install # Install dependencies
npm run build # TypeScript compile + copy runtime.py to dist/
npm test # Run all 405 tests (vitest)
npm run test:watch # Watch mode
npm run lint # Biome check (lint + format + import sorting)
npm run lint:fix # Auto-fix lint issues
npx tsc --noEmit # Typecheck onlyAlways run these three checks — they match what CI enforces:
npm run lint # Biome (lint + formatting)
npx tsc --noEmit # TypeScript typecheck
npm test # All tests passGitHub Actions runs on every push to main and every PR (.github/workflows/test.yml):
| Job | What it does |
|---|---|
| Lint | biome check --reporter=github src/ tests/ |
| Typecheck | tsc --noEmit |
| Test | vitest run on Node 20 + 22, with Python 3.12 |
| Build | npm run build (runs after lint+typecheck+test pass) |
Concurrency group cancels superseded runs on the same branch. Test matrix uses fail-fast: false so both Node versions always run.
- Framework: Vitest 4.x (ESM-only)
- Test timeout: 30s per test, 15s per hook (vitest.config.ts)
- Structure:
tests/unit/for isolated logic,tests/integration/for real git repos + mock agent - Mock agent:
src/agents/mock.ts— self-registers, writes real files in worktrees, supports__FAIL__trigger for failure paths - Temp repos:
createTempGitRepo()/cleanupTempRepo()fromtests/fixtures/helpers.ts— creates real git repos in os.tmpdir - Fake timers: Use
vi.useFakeTimers()+vi.advanceTimersByTime()for TTL, decay, and timestamp tests — neversetTimeoutwith real waits - No flaky tests: All 405 tests are deterministic. If a test depends on timing, it must use fake timers.
- Tool: Biome 2.x (not ESLint/Prettier)
- Config:
biome.json— tabs, 120 line width, double quotes, semicolons - Auto-fix:
npm run lint:fixfixes most issues. For "suggested" (unsafe) fixes:npx biome check --write --unsafe src/ tests/ - Disabled rules:
noExplicitAny,noNonNullAssertion,noParameterAssign,noControlCharactersInRegex(intentional ANSI stripping),noImplicitAnyLet,noForEach,noAssignInExpressions - Warnings:
noUnusedVariables,noUnusedImports(warn, not error)
# Bump version in package.json
npm version patch|minor|major
# Publish (prepublishOnly runs build automatically)
npm publish
# Tag the release
git push --tagsPackage name is swarm-code on npm. Bin entries: swarm-code (primary) and swarm (alias). The files field in package.json whitelists only dist/, bin/, and runtime.py — no src/tests/config leak into the tarball.
src/main.ts— CLI entry point, routes to swarm/run/interactive/viewer/benchmarksrc/swarm.ts— Swarm mode: scans repo, sets up threads, runs RLM loop with orchestrator promptsrc/interactive-swarm.ts— Interactive REPL mode with session persistence and live thread monitoringsrc/core/rlm.ts— Core RLM loop (Algorithm 1 from arXiv:2512.24601)src/core/repl.ts— Python REPL bridge (line-delimited JSON over stdin/stdout). Checks for Python 3 at startup.src/core/runtime.py— Python runtime with thread(), async_thread(), merge_threads()src/agents/— Agent backends (opencode, claude-code, codex, aider, direct-llm, mock)src/agents/provider.ts— AgentProvider interface + registry. Agents self-register on import.src/routing/model-router.ts— Auto model/agent selection based on task complexity + named slots + episodic memory + failure tracking (exponential decay)src/threads/manager.ts— Thread lifecycle + concurrency (AsyncSemaphore) + subthread caching + episode recordingsrc/threads/cache.ts— Subthread cache with optional disk persistence and TTL expirysrc/memory/episodic.ts— Episodic memory: persists successful strategies, trigram-based recall, aggregate stats per agentsrc/hooks/runner.ts— Lifecycle hooks (post_thread, post_merge, post_session). Deterministic verification — success silent, errors surfacedsrc/worktree/— Git worktree CRUD + mergesrc/compression/— Result compression with episode quality filtering (success-only output)src/prompts/orchestrator.ts— Swarm orchestrator system prompt with DAG composition examplessrc/viewer.ts— Trajectory TUI viewer with swarm thread DAG visualization, timing bars, cost breakdownssrc/mcp/— MCP server: exposes swarm as tools for Claude Code, Cursor, etc. (server, tools, session)src/ui/— CLI UI components (onboarding wizard, spinner, dashboard, session summary)src/env.ts— Env var loader. Must be imported BEFORE pi-ai. Loads from shell > .env > ~/.swarm/credentialsaction/— GitHub Actions composite action (entrypoint, trigger parsing, security, PR creation)
Python REPL primitives:
llm_query(sub_context, instruction)— lightweight LLM callthread(task, context, agent, model, files)— spawn coding agent in worktreeasync_thread(...)— async version for asyncio.gather()merge_threads()— merge completed thread branchesFINAL(answer)— return result
JSON protocol between Python and TypeScript:
thread_request/thread_result— thread spawn/completionmerge_request/merge_result— branch mergingllm_query/llm_result— sub-queries (inherited from rlm-cli)
@mariozechner/pi-ai— Core LLM API library (getModels, getProviders, completeSimple). Used in swarm.ts, cli.ts, interactive.ts, rlm.ts, direct-llm.ts. NOT a leftover — essential.@modelcontextprotocol/sdk— MCP server protocolzod— Schema validation for MCP tool inputs
swarm_config.yaml at project root. Key settings:
max_threads: concurrent thread limit (default: 5)default_agent: agent backend (default: opencode). Options: opencode, claude-code, codex, aider, direct-llmauto_model_selection: enable auto-routing (default: false). CLI:--auto-routecompression_strategy: structured | diff-only | truncate | llm-summarymodel_slot_execution/search/reasoning/planning: per-slot model overrides (empty = auto-select)episodic_memory_enabled: enable cross-session strategy learning (default: false)thread_cache_persist: enable disk persistence for subthread cache (default: false)
- Episode quality: Compression filters agent output to only successful operations — failed attempts, stack traces, retries stripped automatically
- Subthread caching: Identical threads (same task+files+agent+model) cached in-memory with optional disk persistence and TTL expiry; second call returns instantly
- Named model slots: Tasks auto-classified into execution/search/reasoning/planning; each slot has preferred agents and optional model overrides
- Episodic memory: Persists successful thread strategies to disk; trigram-based similarity recall informs agent/model selection in future sessions
- DAG composition: Thread results compose via Python variable persistence (T1+T2 → T3); orchestrator prompt teaches multi-stage pipelines and failure re-routing
- Failure tracking: FailureTracker class uses exponential-decay weighting to penalize recently-failed agent/model pairs in routing decisions
- Interactive mode: Session-persistent REPL with /threads, /merge, /reject, /dag, /budget commands and SIGINT handling (single=cancel task, double=exit)
- GitHub Action: Composite action triggered by
@swarmin issue comments or workflow_dispatch. Security: author association check, fork PR rejection, $50 budget hard cap. Creates PRs and posts result comments. - MCP server: Exposes 6 tools (swarm_run, swarm_thread, swarm_status, swarm_merge, swarm_cancel, swarm_cleanup) over stdio transport. Per-directory sessions with lazy-init ThreadManager/WorktreeManager. Claude Code:
claude mcp add swarm-code -- npx swarm-code mcp
- env.ts import order:
src/env.tsmust be imported before any module that reads env vars (pi-ai reads them at import time). All entry points (cli.ts, swarm.ts, interactive.ts, interactive-swarm.ts) do this correctly with dynamic imports. - Mock agent in tests: Integration tests that need the agent registry must
import "../../src/agents/mock.js"before importing session/manager modules. The mock agent self-registers on import. - Module-level state:
src/mcp/session.tsuses a globalMap<string, SwarmSession>keyed by absolute path. Tests must callcleanupAllSessions()in afterEach to avoid cross-test contamination. - CRLF line endings: The bin shim (
bin/swarm.mjs) must use LF line endings or the shebang breaks on Unix. If you edit it on Windows, check withfile bin/swarm.mjs. - AsyncSemaphore is exported:
src/threads/manager.tsexportsAsyncSemaphore(used directly in tests). Don't make it private again. biome.jsonschema: Uses local reference (./node_modules/@biomejs/biome/configuration_schema.json), not a URL. This avoids 404s when the remote schema isn't published for the exact version.