def index
@deals = policy_scope(Deal).paginate(cursor: params[:cursor])
render json: {
data: @deals,
next: @deals.next_cursor,
}
end// PRODUCT — FEATURED
SWARM
> Agent Development Environment
A desktop IDE for coding agents. Run 1–4 Claude Code or Codex agents in parallel Git worktrees, watch each one in a live PTY, review the diff with per-line comments, then merge or open the PR — all in one window.
// 02 — LIVE
Every task plans before it codes.
A task is born pending, with no worktree — creating one costs neither disk nor money. Start creates the worktree, the planner writes the plan and exits, and only then does on_exit bring up the coder. No non-empty plan, no coder.
// 03 — REVIEW
Attempts side by side, as tabs.
The screen is a tree of splits written into the URL. Any surface becomes a tab — the agent, a terminal, the chat, the diff, the preview, a file, or another attempt at the same prompt. That is how two different CLIs on one prompt end up next to each other.
?panes=agent;(diff|preview) · ; splits · | stacks · , tabs · () nests
def index scope = policy_scope(Deal).order(:id) @deals = scope.after(params[:cursor]).limit(25) render json: DealSerializer.wrap(@deals) end
def index
paginator = CursorPaginator.new(
scope: policy_scope(Deal),
cursor: params[:cursor],
per: 25,
)
render json: paginator.page
enddef index
@deals = DealQuery
.for(current_user)
.cursor_page(params[:cursor])
render json: @deals
end// 04 — CAPABILITIES
An environment, not a wrapper around one CLI.
Eight things it does, all on your machine.
Planner, then coder
The handoff is a PTY phase, not a job: the planner runs in the same pane, writes the plan and exits, and on_exit starts the coder pointed at it. “The planner failed” never turns into “code in the dark”.
Claude Code and Codex
Two adapters behind one map — 1 to 4 agents in parallel, each in its own worktree and branch. A new CLI is a map entry plus a class; the validation and the form follow from there.
Real PTYs
PTY.spawn per pane, registered in memory by (task, pane), streamed base64 over ActionCable. Stop escalates HUP → TERM → KILL, and scrollback flushes to disk every 5s so an abrupt death loses at most 5 seconds.
Panes live in the URL
The layout is a tree of splits serialized into the query string. Switching tabs is reordering, closing is removing, splitting is inserting — every action is a link, so reload, back button and bookmarks all just work.
Diff review that talks back
Committed, uncommitted and untracked against merge-base, parsed server-side. Comment on any file:line and the comment goes back to the agent as an instruction.
PR with real evidence
The body is written server-side by a headless agent from the real diff, the original prompt and the actual check results — “no check command” and “never ran” stay distinct from a real result. The golden path is recorded in headless Chrome and embedded as a GIF.
Preview and Design Mode
The worktree's app boots in a PTY behind a proxy whose port detection does not rely on the stack honoring $PORT. Design Mode annotates the live screen like Figma comments — the element's live state is serialized from the DOM and re-rendered with the user's session, not screenshotted.
Loops with guards
Turn, Goal, Time and Proactive, all behind the same non-negotiable guards: cost ceiling, attempt ceiling, global kill switch, judgment timeout, HMAC-SHA256 over the raw webhook body. Trello (bidirectional), Linear and Jira on the tracker side.
// 05 — INSIDE
What happens when you press Start.
A pending task has no worktree. Start creates it, the planner hands off to the coder in the same PTY, and everything the agent produces streams back through a single Puma process — the registry lives in memory, so WEB_CONCURRENCY is forbidden by design.
// 06 — STACK
Built on.
// 07 — MILESTONES
What is already in.
Everything below is shipped and running — this is the tool as it exists, not a plan.
- 01
Orchestrator
Isolated worktrees and branches, live PTY streaming, diff review, merge / discard / PR.
- 02
Compare
N attempts at the same prompt reviewed side by side, per-line comments flowing back into the agent.
- 03
Workspace
Splittable panes serialized into the URL, with the explorer, editor, preview, chat and any file as draggable tabs.
- 04
Two CLIs, one planner
Claude Code and Codex adapters, and a planner phase every task goes through before any code is written.
- 05
PR with evidence
Body written by a headless agent from the real diff and real check results; golden path recorded in headless Chrome as an inline GIF.
- 06
Design Mode
Annotate the running app like a Figma comment — the element is serialized from the live DOM and re-rendered with the user's session.
- 07
Loops and trackers
Turn, Goal, Time and Proactive behind cost, attempt and kill-switch guards, plus Trello, Linear and Jira integrations.
- 08
Desktop
Tauri 2 window on a fixed port with its own process group; WebView2 on Windows, with Rails running inside WSL.
// 08 — STORY
How it started.
I wanted an IDE for coding agents, not a wrapper around one. Register a local repo, fire a prompt, and 1 to 4 agents go at it in parallel — each in its own Git worktree and branch, each in a live PTY, with the file explorer, the editor, the running app, the chat and the diff all in the same window.
It is a Rails 8 app on Hotwire and SQLite, single-process by design: the PTY registry lives in Puma's memory, so WEB_CONCURRENCY is forbidden — two processes mean two registries and a UI showing an empty terminal for an agent that is very much running. Tauri 2 wraps it as a native window; on Windows that is WebView2 with Rails running inside WSL.
One rule ended up running through the whole thing: unknown must never become a value. A model missing from the price table pays the most expensive row. An unreadable transcript returns :unknown and stops the loop instead of counting as zero spent. And a prompt that assembles evidence has to tell the model where the hole is — because a prompt without evidence does not answer “I don't know”, it answers with a plausible invention.
// 09 — TRY IT
Point it at a repo and press Start.
Swarm runs on your machine, against your local repos. The Claude Code plugin ports the same fan-out into the CLI.