95% of Syrus's merged pull requests were written by Syrus itself. Read the methodology behind the merged-PR claim.
Watch the product screencast or open the direct video: WebM · MP4.
Bis dat qui cito dat. He gives twice who gives quickly. — Publilius Syrus
Syrus is an open-source, self-hosted automation harness for developers: turn issues, chats, and video walkthroughs into tracked pull requests while keeping your repositories, credentials, checks, transcripts, review policy, and merge queue under your control. It runs coding agents in isolated workspaces, rebases dependent work, opens reviewed PRs, and records the full workflow so a team can run many agent-authored changes against the same codebase without turning the process into a black box.
The fastest developer/self-hoster path is Docker Compose. On a fresh machine, start with the Docker Compose guide to install a container runtime and verify Compose is available. Once Docker Compose is ready, clone the repo and let the installer start the web app and worker:
git clone https://github.com/tkadauke/syrus.git
cd syrus
./install.sh --dockerOpen http://localhost:3000. The first account becomes the admin, then the
first-run wizard walks through GitHub credentials, agent credentials, a
repository, and a guided chat that lands the first pull request. The installer
pulls the public ghcr.io/tkadauke/syrus-backend image, generates local
secrets, and stores data in Docker volumes.
Prefer a no-terminal local app? Download the signed macOS desktop app:
Syrus.dmg.
It drives the same Docker install, bundles the web UI in a native window, and
keeps the syrus CLI current.
Docs: Getting started · Docker Compose · Desktop app · Deployment
Desktop app users already have the CLI: it is installed, updated, and signed in automatically. On Linux servers or CI machines, download the archive for your platform from the Releases page:
# Linux arm64 shown; pick the matching release and architecture.
curl -LO https://github.com/tkadauke/syrus/releases/download/v0.4.0/syrus_v0.4.0_linux_arm64.tar.gz
tar -xzf syrus_v0.4.0_linux_arm64.tar.gz
install -d ~/.local/bin && install syrus_v0.4.0_linux_arm64/syrus ~/.local/bin/syrus
syrus login # enter your instance URL + an API token from the web UI's Credentials pageRun syrus with no arguments for terminal chat, or syrus inbox to review
work. Full reference: CLI docs.
- Chat that ships code. Describe what you want in a Syrus chat and it proposes the work — Jobs and Epics — for you to confirm. Chat reads the repo to plan; implementation always runs in isolated workspaces, never in chat.
- Epics for big changes. A feature or initiative becomes an Epic: a dependency-ordered stack of smaller Jobs that Syrus implements, rebases against each other, and lands in order (optionally all-or-nothing through a merge train). This is the path from a customer ticket to a merged solution.
- A deterministic pipeline. Every change runs the same steps — prepare, implement, run your graders, summarize, write a reviewer test plan, open a PR — and PR feedback, failing CI checks, and transient errors feed back to the agent automatically.
- A landing queue with a human gate. Approve a PR and Syrus rebases it, re-runs required checks, and merges it — serialized so dependent work lands in order. Nothing merges to your main branch without approval.
- Concurrency without corruption. Every Job gets its own workspace and Syrus rebases branches automatically (force-push with lease), so many changes can be in flight on one repository at once.
- Team-aware. Multi-user with per-user encrypted credentials, Job ownership and claims, an admin API, and a spending dashboard that breaks cost down by person, Epic, and repository.
Work can also enter other ways: label a GitHub issue, attach a recurring cron prompt to a repository, or create a one-off Job from a prompt. Everything runs on polling — Syrus reaches out to GitHub on a schedule, with no inbound webhooks to configure.
Everything below is for running Syrus from source, hacking on it, or deploying it to production. If you just want to use Syrus, the Quickstart above is all you need.
The full from-nothing dev setup on a Mac with Homebrew. Every command is
copy-pasteable, and bin/setup is idempotent, so re-running is safe. You'll
end up with Ruby 3.4.10, Node + npm, Go, libvips, the MySQL client libraries,
and the Claude Code CLI. Local dev uses SQLite — you do not run a MySQL
server and need no master key; MySQL client libs only appear so the
production mysql2 gem can compile.
Fast path — one command. The installer does every step below (Xcode CLT,
Homebrew, deps, Claude CLI, rbenv + Ruby, bin/setup, the syrus CLI on
your PATH):
git clone git@github.com:tkadauke/syrus.git # no SSH key? gh repo clone tkadauke/syrus
cd syrus
./install.sh --bare-metal # add --start to launch and open the browserThen bin/dev and open http://localhost:3000 — the first account
becomes the admin. Prefer to do it by hand, or hit a snag? The manual steps
follow; the installer runs exactly these.
Manual walkthrough (the same steps, by hand)
xcode-select --install || true
if ! command -v brew >/dev/null; then
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# Apple Silicon path shown; on Intel, brew lives at /usr/local.
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"brew update
# rbenv/ruby-build: Ruby. node: JS + Claude CLI. go: builds the Syrus CLI.
# vips: image processing. mysql: client libs so the mysql2 gem compiles.
brew install rbenv ruby-build node go vips mysql
brew install openssl@3 readline libyaml # libraries Ruby links against
# The worker shells out to `claude` to run Jobs and chats.
npm install -g @anthropic-ai/claude-codeIf
bundle installlater fails to buildmysql2:bundle config set --local build.mysql2 "--with-mysql-config=$(brew --prefix mysql)/bin/mysql_config"and re-runbin/setup.
echo 'eval "$(rbenv init - zsh)"' >> ~/.zshrc
eval "$(rbenv init - zsh)"
rbenv install 3.4.10 --skip-existing
rbenv global 3.4.10
ruby -v # ruby 3.4.10git clone git@github.com:tkadauke/syrus.git # no SSH key? gh repo clone tkadauke/syrus
cd syrusbin/setup # gems + JS deps, build the Go CLI, prepare the SQLite DBs
bin/dev # web + worker + tailwind + JS watch, on port 3000Open http://localhost:3000. The first account becomes the admin, and
the first-run wizard walks you through GitHub credentials (a classic PAT with
repo for private repositories or public_repo for public-only use, plus the
optional workflow scope only when agents must edit GitHub Actions workflow
files) and the GitHub App, the agent, a repository, and a guided first Epic.
Fine-grained PATs remain supported through repository-specific validation. The
Configure agent step handles installed agent-provider plugins such as
Claude, Codex, Antigravity, and Muse.
bin/dev # foreman: web (rails s) + worker (bin/jobs) + tailwind + JS watch
bin/rspec # Ruby test suite (local coverage off by default)
npm run test:react # React/Vitest suite + TypeScript typecheck
bin/test # Ruby and React suites together
bin/test-docker # integration tests against the Docker image (isolated stack)Use COVERAGE=true bin/rspec to generate coverage/lcov.info locally.
CI enables Ruby coverage by default.
bin/test-docker brings up a throwaway Compose stack (its own project,
volume, and host port) and asserts the database, file uploads, the worker
draining jobs, the dev toolchain, and the MCP sidecar boot. Pass
SYRUS_IMAGE=… to test a specific tag.
./install.sh --docker pulls the prebuilt image. To build it yourself — to
change Syrus source or add OS packages your repos' build/grader commands need
— use bin/compose-up, and set EXTRA_APT_PACKAGES for extra apt packages.
Details and the registry BuildKit cache flags are in
Docker Compose deployment.
bin/publish-image publishes the host architecture by default; pass
--multi-arch for both linux/amd64 and linux/arm64.
bin/setup --install-cli # builds cli/bin/syrus and installs it on PATH
# or, from cli/: make install PREFIX=~/.local
npm --prefix desktop install
npm --prefix desktop run dev # desktop app, local development
npm --prefix desktop run build # packaged app in desktop/outMaintainers cut releases from CI — Actions → "Release", pick a version
bump, and the pipeline builds, signs, and publishes the CLI, the macOS desktop
app, and the backend image atomically (see docs/releasing.md).
The bin/release* scripts are local build/verify tools only:
bin/release v0.0.0-local --desktop # build desktop artifacts locally, no publish
bin/publish-image X.Y.Z # build + test + push the image (local/fork)
bin/release-notes v0.4.0 # preview Claude-written notesProduction is driven by environment variables:
SYRUS_APP_HOST— public app host for URL generation and mailer links.SYRUS_ALLOWED_HOSTS— optional comma-separated extra hostnames;SYRUS_APP_HOSTis always allowed.SYRUS_ASSUME_SSL/SYRUS_FORCE_SSL— TLS behavior for proxied deployments (defaulttrue;/upis exempt).SYRUS_GITHUB_REPO— optional: this installation's ownowner/repo; enables build-revision links (degrades to no link when unset).SYRUS_BUG_REPORT_OWNER— optional: GitHub owner/org for in-app bug reports (expects an active<owner>/syrusrepo); leave it blank and the bug-report button just won't error when clicked.SYRUS_MAILER_FROM— sender address for application mail.SMTP_*— SMTP settings; withoutSMTP_ADDRESS, Rails keeps its default delivery.
Production uses MySQL and requires RAILS_MASTER_KEY (or the three Active
Record encryption keys). Migrations must be valid from an empty database.
See the deployment docs for
Kubernetes and Docker Compose specifics.
| Choice | Decision |
|---|---|
| Stack | Rails 8 + Solid Queue (MySQL or single-host SQLite in prod, SQLite in dev/test) · React + TypeScript via Vite · Go CLI |
| Trigger model | External polling for GitHub issues, PR feedback, CI failures, merge state, and scheduled tasks — no inbound webhooks |
| Auth | Multi-user; first signup = admin, then invite-only |
| Credentials | Per-user, encrypted at rest (GitHub token, agent-provider credentials, admin API token) |
| Workers | Separate container from the web app |
| Deploy | Kubernetes or Docker Compose |
Security posture. Syrus assumes trusted users operating on trusted
repositories. Agent runs execute in worker-managed per-Workflow workspaces
under SYRUS_DATA_ROOT — this keeps the agent out of your operator checkout,
but it is not a hardened sandbox for untrusted code. Run Syrus on
infrastructure you control, register repositories whose code and setup
commands you're willing to execute, scope GitHub tokens narrowly, and review
generated PRs before merging.
The MVP deliberately excludes inbound GitHub delivery, hosted multi-tenant sandboxing, and out-of-band human escalation.
CLAUDE.md is the in-repo guide for coding agents working on Syrus itself;
ROADMAP.md tracks milestones.
- Skip prepare. The
syrus-skip-preparelabel on a source issue starts a Job at implementation, bypassing broken prepare commands. - Scheduled tasks. Cron tasks use five-field UTC expressions treated as hourly windows (the minute field is a per-task offset so tasks with the same schedule don't all fire on one tick).
- Credentials. Users replace GitHub and agent credentials from My credentials; admins generate, rotate, or revoke API tokens there too. Rotating invalidates the old token immediately.
Named after Publilius Syrus, the 1st-century-BCE Roman writer whose Sententiae — a collection of one-line maxims — were schoolbook material for over a millennium and seeded a surprising number of phrases still in everyday use. He was a writer, the same job the LLM does inside this harness, and his output outlived him by two thousand years. That's the aspiration: small, durable text that compounds.
