Crow manages AI-powered development sessions. It runs as a background daemon (crowd) with a browser-based UI, orchestrating git worktrees, Claude Code instances, and GitHub/GitLab/Jira issue tracking. Each session pairs a git worktree, a tmux-backed Claude Code terminal (streamed to xterm.js in your browser), and ticket metadata — all tracked in a persistent store.
Note: Crow began as a native macOS (AppKit) app. As of ADR 0009 and ADR 0010, that app was retired:
crowdis the sole authority and every UI is a pure client. The browser is the primary UI; an optional thin desktop window (Tauri) over the same web UI is available if you prefer a native window. The daemon still runs on a macOS host because it drivesgit,tmux, and Claude Code locally.
flowchart TB
subgraph clients["Clients (pure, no privileged state)"]
WEB["Web UI — browser or Tauri window<br/>web UI + xterm.js"]
CLI["crow CLI"]
end
subgraph daemon["crowd — the sole authority"]
HTTP["HTTP + WebSocket server<br/>/rpc · /terminal · web + login"]
ENGINE["CrowEngine<br/>SessionService · spawn / lifecycle"]
BOARDS["IssueTracker · AllowListService<br/>JobScheduler · auto-respond / -review"]
HUB["EventHub — server push"]
STORE[("store.json")]
end
subgraph host["Host + backends"]
TMUX["tmux cockpit"]
AGENTS["Coding agents<br/>Claude Code · OpenCode · Cursor · Codex"]
GIT["git worktrees"]
PROV["GitHub · GitLab · Jira · Corveil"]
end
WEB -- "WebSocket: /rpc + /terminal" --> HTTP
CLI -- "Unix socket JSON-RPC" --> ENGINE
HTTP --> ENGINE
ENGINE --> STORE
ENGINE --> TMUX
ENGINE --> GIT
TMUX --> AGENTS
ENGINE --> BOARDS
BOARDS --> PROV
BOARDS --> HUB
HUB -. "push: changed" .-> WEB
crowd is the single source of truth — the only store writer, the only spawner, and the owner of terminal + agent lifecycle. Every UI is a pure client: it subscribes to crowd's state over the /rpc + /terminal WebSocket surface, sends JSON-RPC, and renders. The web UI is the same either way — a browser tab or the Tauri desktop window, which just wraps that web UI in a native window and can spawn crowd as a sidecar on launch. Multiple clients (browser tabs, the desktop window, the crow CLI, any future UI) attach to one running system at once. Full detail in docs/architecture.md.
crowd is the only process you run, and it drives git, tmux, and the coding agents on the host — so it needs a Unix-like host:
- macOS 14.0+ (Sonoma or later), or Linux (x86_64 or arm64)
- A Swift 6 toolchain — bundled with Xcode Command Line Tools on macOS, or installed from swift.org/install on Linux
- A modern web browser for the UI
The optional native desktop app (Tauri) is macOS-only today; on Linux, use the browser UI. On Linux the terminal is streamed to the browser over a WebSocket (the macOS-native terminal surface compiles away).
| Tool | Version | Purpose | Install |
|---|---|---|---|
| Swift | 6.0+ | Compiler — Xcode CLT (macOS) or the swift.org toolchain (Linux) | xcode-select --install · swift.org/install |
| Rust | 1.77+ (arm64) | Compiler for the optional desktop app (macOS) | rustup.rs |
| Node | 18+ | Only for npm run tauri dev (optional) |
brew install node |
| Tool | Purpose | Install |
|---|---|---|
gh |
GitHub CLI — issue tracking, PR status, project boards | brew install gh |
git |
Worktree management | Ships with Xcode CLT |
claude |
Claude Code — AI coding assistant | claude.ai/download |
tmux |
Terminal backend for managed sessions (≥ 3.3) | brew install tmux |
glab |
GitLab CLI (optional, for GitLab repos) | brew install glab |
acli |
Atlassian CLI (optional, for Jira task tracking) | developer.atlassian.com/cloud/acli |
Install commands above are macOS/Homebrew; on Linux use your distribution's package manager (e.g.
apt install git tmux;gh/glabhave their own apt repos).gitships with Xcode CLT on macOS.claudeis the default coding agent — OpenCode, Cursor, Codex, and Antigravity are also supported and selectable per session (Settings → General, orcrow agents set); install whichever agents you use.
# 1. Clone
git clone https://github.com/corveil/crow.git
cd crow
# 2. Build the `crow` CLI and the `crowd` daemon (Swift toolchain only).
# `make build` also builds the optional native desktop app — see "Desktop app" below.
make daemon
# 3. Authenticate GitHub CLI — the write `project` scope is required
gh auth login
gh auth refresh -s project,read:org,repo
# 4. Configure your development root + workspaces
.build/debug/crow setup
# 5. Run the daemon — it serves the web UI
.build/debug/crowdcrowd prints HTTP/WS listening on http://127.0.0.1:8787 on startup — open that URL in your browser. The first screen guides you through any remaining setup.
For local daemon development, make daemon-run runs crowd serving the frozen web UI baked into the compiled bundle — the same asset source as make run. Web UI edits (index.html/app.css/app.js) need a rebuild to be picked up:
make daemon-run # stable daemon at http://127.0.0.1:8787
bash scripts/daemon-run.sh --watch # ...and rebuild + restart crowd on Swift or web-asset changes--watch restarts the daemon on every change (Swift can't hot-swap), so leave it off when you want a daemon that stays up across edits.
Note: The required GitHub scope is the write
projectscope —read:projectis insufficient because Crow updates ticket status via theupdateProjectV2ItemFieldValueGraphQL mutation. See docs/getting-started.md for details.
The Manager terminal and the /crow-workspace skill call bare crow ..., so a build you can only launch by full path will break those workflows. Install the binaries so they're invokable from anywhere:
make install # symlinks crow + crowd into ~/.local/binIf ~/.local/bin isn't already on your PATH, add this to ~/.zshrc (then restart your shell):
export PATH="$HOME/.local/bin:$PATH"Use a different directory with BINDIR, e.g. make install BINDIR=/usr/local/bin.
make install creates symlinks into .build/debug/, so a later make build updates them in place — no need to re-run it. Re-run make install only when you switch to a release build (make daemon CONFIG=release && make install CONFIG=release) or after make clean (which removes .build/ and leaves the symlinks dangling until the next build). Remove the symlinks with make uninstall.
crowd binds 127.0.0.1:8787 by default, so it's reachable only from the machine it runs on. To reach it from another device, front it with an HTTPS reverse proxy (e.g. tailscale serve) and set a web password under Settings → Web Access or with crow web-password set. Non-loopback requests are blocked until a password is set and the connection is HTTPS (CROW-593).
The password and the AI gateways are local-only surfaces: they're settable from a local browser or the crow CLI (which talks over the Unix socket), and refused for remote web clients — a remote session must not be able to change the password gating remote access, or read gateway credentials. See CLI Reference → Gateway Commands.
Prefer a native window to a browser tab? crow-desktop/ is a thin Tauri shell that opens a "Crow" window pointed at the same web UI. It doesn't reimplement anything — crowd stays the sole authority; the window is just another pure client. Requires the Rust arm64 toolchain (see Build Dependencies).
make build # crow CLI + crowd daemon (Swift) AND the Crow desktop app (Tauri)
make run # build, then open the Crow windowmake run is the modern equivalent of the old make && ./.build/debug/CrowApp. On launch the window looks for a crowd already listening on 127.0.0.1:8787:
- Found (and it identifies as crowd) → it reuses that daemon and leaves it running when you quit the window.
- None → it spawns its own
crowdfrom.build/debug/crowdand stops that one on quit.
Once built, the binary is self-contained — run it directly without make:
crow-desktop/src-tauri/target/debug/CrowToolchain note: a plain terminal can run under Rosetta (x86_64) and shadow the arm64 Rust with an old x86_64 one.
make app/make runpin the Homebrew + rustup arm64 paths for you; if you invokecargoornpmdirectly, prefixPATH="/opt/homebrew/bin:$HOME/.cargo/bin:$PATH".
The make run window spawns crowd as a sidecar that serves the web UI from the compiled bundle (frozen assets), so web/UI edits (index.html/app.css/app.js) need a make daemon rebuild to show up — the same asset source across every dev path. The rebuild re-copies the assets into the bundle and crowd reads them per request, so a plain ⌘R picks them up (no daemon restart needed for web-only edits; a Swift change does need a restart, since Swift can't hot-swap).
Run a standalone crowd separately only when you want a daemon that outlives the window or is shared by several clients (a browser tab + the window at once). Because the window reuses a crowd already on :8787 and leaves it running on quit, they compose cleanly:
# Terminal 1 — a stable daemon, web served from the compiled bundle
make daemon-run
# Terminal 2 — the window attaches to it (reuses :8787, doesn't own its lifecycle)
make run # or, once built: crow-desktop/src-tauri/target/debug/CrowQuitting the window leaves your crowd running. daemon-run --watch rebuilds and restarts it on Swift or web-asset edits — the window keeps its :8787 target, so just ⌘R once it's back up. (--watch always restarts; Swift can't hot-swap, and even a web edit tears the daemon down — the same reason the Tauri dev loop churns.) For a web-only tweak you can skip the churn: a manual make daemon against the already-running daemon just re-copies the assets, which it serves on the next ⌘R with no restart.
CROW_HTTP_PORT=NNNN— match a crowd started on a non-default port so the window reuses it instead of spawning a second daemon on 8787 (which would contend on the same store + tmux cockpit).CROWD_BIN=/path/to/crowd— override whichcrowdbinary the window spawns when none is already running.
When you're changing the desktop shell itself (crow-desktop/src-tauri/), use Tauri's dev loop, which recompiles and relaunches the Rust on save:
cd crow-desktop
PATH="/opt/homebrew/bin:$HOME/.cargo/bin:$PATH" npm run tauri devHandy for Rust/window work, but each relaunch re-runs the launch logic and tears down a crowd it spawned — so it churns the daemon. When you're iterating on crowd or the web UI (not the Rust shell), prefer plain make run (or the make daemon-run + make run split above).
- Getting Started — Clone, build, authenticate, and run
- CLI Reference — Every
crowsubcommand and its flags, with examples and gotchas - CLI (generated) — The same surface generated from the commands themselves; regenerate with
make docs - Architecture — Packages, key components, data flow
- Configuration — File locations, workspace config, directory layout, session lifecycle
- Automation — Auto-create, auto-respond, auto-complete, and the Settings → Automation tab
- Troubleshooting — Build and runtime errors
The left rail groups your work:
- Tickets — Assigned issues grouped by project board status (Backlog, Ready, In Progress, In Review, Done in last 24h). Click a status to filter.
- Manager — A persistent Claude Code terminal for orchestrating work. Use
/crow-workspacehere to create new sessions. Launches in--permission-mode autoby default so orchestration commands (crow,gh,git) run without per-call approval; opt out via Settings → Automation → Manager Terminal. - Active Sessions — One per work context. Shows repo, branch, issue/PR badges with pipeline and review status.
- Completed Sessions — Sessions whose PRs have been merged or issues closed.
Right-click a session (or long-press / tap the ⋮ button on touch devices) for its actions — rename, delete, copy links, and more.
In the Manager tab, tell Claude Code what you want to work on:
/crow-workspace https://github.com/org/repo/issues/123
Or use natural language:
/crow-workspace "add authentication to the acme-api API"
This will:
- Create a git worktree with a feature branch
- Create a session with ticket metadata
- Launch Claude Code in plan mode with the issue context
- Auto-assign the issue and set its project status to "In Progress"
- Pipeline view showing issues by project board status
- Click a status to filter the list
- "Start Working" button creates a workspace directly from an issue
- Issues linked to active sessions show a navigation button
- Scriptable from the CLI:
crow list-tickets,crow work-on-issue,crow batch-work-on-issues,crow start-review, andcrow quick-actiondrive the same actions as the board buttons (see the CLI Reference)
Per ADR 0005, a workspace's
Task Backend (where tickets live) is chosen independently of its Code
Backend (where code + PRs live). You can track work in Jira while keeping
code and pull requests on GitHub — the task side runs through acli, the PR
side still runs through gh.
Prerequisite — authenticate acli:
# Install: https://developer.atlassian.com/cloud/acli/guides/install-acli/
acli jira auth login
acli jira auth status # should print "✓ Authenticated"Configure a Jira-task / GitHub-code workspace (Settings → Workspaces → edit a workspace):
- Code Backend →
GitHub(code + PRs stay on GitHub). - Task Backend →
Jira(offered only whenacliis installed + authenticated; an inline hint tells you the fix when it isn't). - Atlassian Site (e.g.
acme.atlassian.net) — used to build…/browse/KEYlinks. - Project Key (e.g.
PROJ) — default project for created tickets. - My-tickets JQL (optional) — defaults to
assignee = currentUser() AND statusCategory != Done.
Settings persist to the workspace entry (~/.claude/workspace-repos.json keys:
taskProvider, jiraProjectKey, jiraJQL, jiraSite). Existing GitHub/GitLab
workspaces are unaffected — when no Task Backend is set, it follows the Code
Backend (GitHub code ⇒ GitHub issues, as before).
- Pipeline checks (passing/failing/pending)
- Review status (approved/changes requested/needs review)
- Merge readiness (mergeable/conflicting/merged)
- Purple badge with checkmark for merged PRs
- Sessions automatically move to "Completed" when their linked PR is merged or issue is closed
- Checked every 60 seconds during the issue polling cycle
- Requires positive evidence the session was worked, so an unrelated PR merge can't flip an idle session
Crow can drive a ticket from assignment to merged with minimal manual steps. Toggles live under Settings → Automation; full walkthrough in docs/automation.md.
- Auto-create workspace when an issue assigned to you is labeled
crow:auto - Auto-suggest opening a PR if a session completes with no PR linked
- Auto-start review sessions for opted-in workspaces when a PR becomes reviewable
- Auto-respond to changes-requested reviews and failed CI checks (off by default)
- Auto-merge Crow-authored PRs labeled
crow:mergeviagh pr merge --auto --squash(off by default; only acts on PRs whose commits carry aCrow-Session:trailer matching a known session). Crow lazily creates thecrow:mergelabel on first observation; to pre-seed it manually:gh label create crow:merge --color 0E8A16 --description "Crow: enable auto-merge once mergeable" - Scriptable —
crow automation get|setdrives every toggle on the tab: the five auto-permission modes, remote control, commit attribution, both label watchers, and the three auto-respond toggles. Same config as the UI, live within a board poll, nocrowdrestart. The tab's ticket/review board filters areAppConfig.defaultsfields and belong tocrow defaults set(CLI reference)
- Multi-select with batch Start Review
- Bulk delete sessions
- Filter projects out via
excludeReviewRepos - Quick action buttons on the session detail header (open PR, mark in review, copy branch)
- Move completed sessions back to active
- xterm.js terminal surface in the browser, streamed from tmux over a WebSocket (
/terminal) - tmux-backed managed terminals — each session is a tmux window on a shared server (the "cockpit"), so per-session shells stay alive across UI navigation and across browser reconnects. Requires
tmux ≥ 3.3(brew install tmux); without it, managed terminals don't render. See docs/architecture.md#terminal-backends. - Rename tabs from the UI or via
crow rename-terminal - tmux maintenance from the CLI as well as Settings → About:
crow restart-manager,crow restart-tmux-server,crow reload-tmux-config,crow launch-agent,crow retry-readiness, pluscrow open-in-vscode/crow open-terminalfor the session's worktree on the host. See docs/cli-reference.md.
- A workspace maps a folder under your dev root to a forge (GitHub or GitLab), a ticket source (GitHub, GitLab, Jira, or Corveil), the repos it always lists or auto-reviews, and free-text instructions appended to its session prompts
- Manage from Settings → Workspaces or from the CLI with
crow workspace list|get|add|edit|remove— both write the same config, and an open browser tab picks up a CLI change within a couple of seconds - Renaming or removing a workspace is guarded: sessions are tied to it only by their worktree path and jobs only by its name, so both refuse while references exist and report what
--forcewould orphan. See docs/cli-reference.md.
- Ten event categories — task complete, agent waiting, review requested, changes requested, CI failing, plus the five automation events Crow emits when it acts on your behalf
- Cascading control: a master mute, global sound / system-notification toggles, then per-event toggles and a sound picked from 14 built-in sounds
- Manage from Settings → Notifications or from the CLI with
crow notifications get|set— both write the same config, and an open browser tab picks up a CLI change within a couple of seconds
- On startup, scans git worktrees across all repos
- Worktrees not tracked in the store are automatically recovered as sessions
- Fetches ticket metadata and PR links from GitHub for recovered sessions
- Deleting a session on a protected branch (main, master, develop) only removes the session metadata — the repo folder and branch are preserved
- The delete confirmation dialog reflects this, showing "Remove Session" instead of "Delete Everything"
- Create the package under
Packages/ - Add it to the root
Package.swiftdependencies and target (or to a package that a root target already pulls in) - Import in the targets that need it
make test # or: swift test --package-path Packages/<name>Tests use the Swift Testing framework (@Test macros). Test files live under Packages/*/Tests/.
We welcome contributions! See CONTRIBUTING.md for guidelines on reporting bugs, suggesting features, and submitting pull requests.
Apache 2.0 — see LICENSE for details.