Skip to content

Crow

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: crowd is 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 drives git, tmux, and Claude Code locally.

Architecture at a glance

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
Loading

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.

Prerequisites

System Requirements

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).

Build Dependencies

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

Runtime Dependencies

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/glab have their own apt repos). git ships with Xcode CLT on macOS. claude is the default coding agent — OpenCode, Cursor, Codex, and Antigravity are also supported and selectable per session (Settings → General, or crow agents set); install whichever agents you use.

Quick Start

# 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/crowd

crowd 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 project scope — read:project is insufficient because Crow updates ticket status via the updateProjectV2ItemFieldValue GraphQL mutation. See docs/getting-started.md for details.

Install (put crow + crowd on your PATH)

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/bin

If ~/.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.

Remote access

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.

Desktop app (native window over crowd)

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 window

make 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 crowd from .build/debug/crowd and stops that one on quit.

Once built, the binary is self-contained — run it directly without make:

crow-desktop/src-tauri/target/debug/Crow

Toolchain note: a plain terminal can run under Rosetta (x86_64) and shadow the arm64 Rust with an old x86_64 one. make app/make run pin the Homebrew + rustup arm64 paths for you; if you invoke cargo or npm directly, prefix PATH="/opt/homebrew/bin:$HOME/.cargo/bin:$PATH".

Iterating with the window open

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/Crow

Quitting 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 which crowd binary the window spawns when none is already running.

npm run tauri dev (editing the Tauri shell)

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 dev

Handy 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).

Documentation

  • Getting Started — Clone, build, authenticate, and run
  • CLI Reference — Every crow subcommand 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

Usage

The Web UI

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-workspace here to create new sessions. Launches in --permission-mode auto by 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.

Creating a Session

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:

  1. Create a git worktree with a feature branch
  2. Create a session with ticket metadata
  3. Launch Claude Code in plan mode with the issue context
  4. Auto-assign the issue and set its project status to "In Progress"

Features

Ticket Board

  • 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, and crow quick-action drive the same actions as the board buttons (see the CLI Reference)

Jira tasks + GitHub code (cross-backend workspaces)

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 BackendGitHub (code + PRs stay on GitHub).
  • Task BackendJira (offered only when acli is installed + authenticated; an inline hint tells you the fix when it isn't).
  • Atlassian Site (e.g. acme.atlassian.net) — used to build …/browse/KEY links.
  • 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).

PR Status Tracking

  • Pipeline checks (passing/failing/pending)
  • Review status (approved/changes requested/needs review)
  • Merge readiness (mergeable/conflicting/merged)
  • Purple badge with checkmark for merged PRs

Auto-Complete

  • 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

Automation Suite

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:merge via gh pr merge --auto --squash (off by default; only acts on PRs whose commits carry a Crow-Session: trailer matching a known session). Crow lazily creates the crow:merge label on first observation; to pre-seed it manually: gh label create crow:merge --color 0E8A16 --description "Crow: enable auto-merge once mergeable"
  • Scriptablecrow automation get|set drives 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, no crowd restart. The tab's ticket/review board filters are AppConfig.defaults fields and belong to crow defaults set (CLI reference)

Review Board

  • 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

Terminals

  • 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, plus crow open-in-vscode / crow open-terminal for the session's worktree on the host. See docs/cli-reference.md.

Workspaces

  • 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 --force would orphan. See docs/cli-reference.md.

Notifications

  • 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

Orphan Recovery

  • 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

Safe Deletion

  • 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"

Development

Adding a New Package

  1. Create the package under Packages/
  2. Add it to the root Package.swift dependencies and target (or to a package that a root target already pulls in)
  3. Import in the targets that need it

Testing

make test     # or: swift test --package-path Packages/<name>

Tests use the Swift Testing framework (@Test macros). Test files live under Packages/*/Tests/.

Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines on reporting bugs, suggesting features, and submitting pull requests.

License

Apache 2.0 — see LICENSE for details.

About

Native macOS session manager for AI-powered development — orchestrates git worktrees, Claude Code, and GitHub/GitLab issues in an embedded terminal.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

15 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages