Skip to content

Introduction

License: FSL-1.1-MIT

Documentation: https://yorch.github.io/auto-swe/

A durable, governed multi-agent workflow platform for engineering and non-engineering teams. Workflows are versioned JSON DAGs executed on Temporal; agents run inside isolated Docker workspaces, with human approval gates, security scanning, and cost control applied to every run.

Its flagship use case — and what the default template ships for — is ticket in, reviewed and tested pull request out. That flow is an ordinary workflow template built from the same node types any team can author, not privileged runtime code, so it is a starting point rather than the boundary.

Teams drive all of it from the Slack channel teammate: a channel-resident assistant with its own memory and persona that answers questions with repo and run context, and also starts, watches, and gates the workflows themselves.

  1. Submit a work request — POST a ticket ID (Jira, Linear, GitHub Issues, etc.) and description to the API
  2. Agent implements — An LLM agent clones the target repo into an ephemeral Docker sandbox, writes code and tests, and iterates until tests go green (TDD loop, max 5 iterations)
  3. Review network runs — Three parallel review agents (Security Auditor, Domain Logic, Performance) inspect the diff and can request fixes
  4. PR opens — A pull request is created on GitHub with the implementation
  5. CI self-heals — If pipeline checks fail, the agent wakes up, reads the logs, and pushes a fix
  6. Human merges — The workflow waits (up to 7 days) for a human to merge the PR, then commits learnings to semantic memory (pgvector) for future runs. A repository can opt into native auto-merge for low-risk changes (docs/pr-evaluation.md); it is off by default

All execution is durable via Temporal.io — workflows survive crashes, restarts, and API rate limits.

Other automations — dependency sweeps, release-note generation, scheduled audits, PRD decomposition — are the same engine with a different DAG, authored on the visual template editor or in natural language. See docs/product-overview.md for the full capability map and docs/channel-assistant.md for the Slack teammate.

CLI / API
│ POST /api/v1/work-requests
▼
Fastify Gateway ──────────────────▶ Temporal Server
│ │
│ PostgreSQL 18 + pgvector │ Task Queue
│ (state, memory, tokens) ▼
│ Temporal Worker
│ │
│ │ RunnableWorkflow (generic interpreter over a JSON WorkflowSpec)
│ │ walks step / set / cond / signal / terminate / fanOut nodes
│ │ └── dispatches to activities below
│ │
│ ├── validateContext (Context Validator agent)
│ ├── planDecomposition (split work request into Subtask[])
│ ├── executeImplementation (Implementer agent + DinD TDD loop;
│ │ takes optional Subtask for per-branch fan-out)
│ ├── runLint / Typecheck / Tests / Build / VulnScan / PerfBench (quality gates)
│ ├── executeGateFixImplementation (fix-loop for failed gates)
│ ├── runReviewNetwork (Security / Domain / Performance agents)
│ ├── executeReviewFixImplementation
│ ├── mergeBranches (fast-forward subtask branches into the feature branch)
│ ├── createOrUpdatePullRequest (GitHub API)
│ ├── fetchCILogs + executeCIFixImplementation (self-healing on CI failures)
│ ├── ⏳ await humanMergeSignal
│ └── commitToMemory (pgvector lesson embedding)
│
└── POST /api/v1/webhooks/git (GitHub merge webhook → humanMergeSignal)
POST /api/v1/webhooks/ci (CI check_run webhook → ciPipelineSignal)

For multi-repo epics, EpicOrchestratorWorkflow decomposes the request into per-repo child RunnableWorkflows using the Planner agent and runs them with dependency-graph scheduling. Each child runs the team’s configured workflow spec (default: ticket-to-merge@v1). See docs/architecture.md for the spec schema, node types, and step catalog.

Layer Technology
HTTP API Fastify 5.12 + Zod 4 validation
Orchestration Temporal 1.31 (server + admin-tools + ui) + @temporalio/* SDK 1.24
Agents Mastra 1.73 + Vercel AI SDK 7 (default claude-opus-5-5)
Database PostgreSQL 18 + pgvector (Prisma 7.10)
Embeddings OpenAI text-embedding-3-large (1536d)
Workspace isolation Docker-in-Docker
Observability OpenTelemetry → Grafana LGTM (grafana/otel-lgtm:0.34.0)
Web dashboard Next.js 16 + React 19 + Tailwind CSS 4 + TanStack Query 5
Language TypeScript 7 (strict mode, Yarn 4.18 monorepo)
Tests / Lint+Format Vitest 4 / Biome 2.5
  • Node.js ≥ 26.0.0
  • Yarn 4 via corepack (npm install -g corepack && corepack enable) — Node 26 no longer bundles corepack
  • Docker + Docker Compose
Terminal window
# 1. Install dependencies
npm install -g corepack && corepack enable && yarn install
# 2. Configure environment
yarn env:setup init
# Creates .env from .env.example and generates the required secrets —
# CONFIG_ENCRYPTION_KEY, BETTER_AUTH_SECRET, JWT_SECRET, SEED_ADMIN_PASSWORD
# (and GARAGE_RPC_SECRET for the bundled object store). After pulling a change to
# .env.example, `yarn env:setup sync` carries your values over; `yarn env:setup check`
# validates the file.
# Optionally GITHUB_TOKEN / GITHUB_WEBHOOK_SECRET as bootstrap fallbacks.
# LLM provider keys and model picks are NOT env vars — add them via the
# dashboard at /models after starting the gateway+web. See
# docs/model-configuration.md for the bootstrap flow.
# 3. Start infrastructure (Postgres, Temporal + UI, Garage)
# Garage starts only when COMPOSE_PROFILES includes objectstore (set by default in .env.example).
yarn docker:infra:up
# 4. Set up the database
# db:deploy (`prisma migrate deploy`) applies the committed migrations verbatim.
# Not db:migrate: `migrate dev` reads the hand-written HNSW/CHECK DDL as drift.
yarn db:deploy && yarn db:generate && yarn db:seed
# 5. Start the gateway and dashboard (two terminals)
yarn dev:gateway # Terminal 1 → http://localhost:8080
yarn dev:web # Terminal 2 → http://localhost:3000
# 6. Sign in as admin@auto-swe.local and add model credentials at
# /models (anthropic for the agents, openai for embeddings).
# The worker refuses to start until they exist.
# 7. Start the worker
yarn dev:worker # Terminal 3

The full walkthrough, through connecting a repository and starting a first run, is in docs/quickstart.md.

Temporal Web UI is available at http://localhost:8233 (local dev only: it sits behind the temporal-ui Compose profile, which yarn docker:* and just enable and production does not).

For production deployment, see docs/deployment.md — end-to-end runbook covering env vars, DB + Temporal setup, image build, service layout, smoke test, day-2 ops, backup, and a hardening checklist. Upgrading a deployment that ran earlier code: read docs/upgrade-notes.md for fixed defects that need you to rotate a credential or clean up logs.

Four equivalent entry points — pick the one that fits the workflow:

  1. Web dashboard (recommended) — open http://localhost:3000, sign in, and click + New request. Pick a workflow template (for example the default, ticket-to-merge), fill the inputs it asks for, and run it. The run appears in Active runs immediately.

  2. Slack — ask the channel teammate in a channel it is installed in, or use the slash command. It also posts run progress and HITL prompts back into the channel. See docs/slack-app-setup.md.

  3. CLI (auto-swe) — export AUTO_SWE_TOKEN (mint one at Settings → API tokens) and run the CLI’s workflows subcommands. See packages/cli/README.md.

  4. Raw HTTP — useful for scripting / CI. Use a PAT (mint one at Settings → API tokens) as the bearer:

    Terminal window
    TOKEN=<your-PAT-from-Settings → API tokens>
    curl -X POST http://localhost:8080/api/v1/work-requests \
    -H "Authorization: Bearer $TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{
    "externalTicketId": "JIRA-42",
    "description": "Add a GET /health endpoint that returns { status: ok }",
    "repoIds": ["<repo-uuid>"],
    "budgetTier": "STANDARD"
    }'

budgetTier controls the LLM token budget: STANDARD (2M/500K tokens), LARGE (8M/2M), EPIC (20M/5M). The workflow is terminated with BUDGET_EXCEEDED if the limit is breached.

For multi-repo changes, use Epics (the Epics type under Requests in the dashboard, or POST /api/v1/epics) — the Planner agent decomposes the brief into per-repo child runs.

Terminal window
# Dashboard — KPIs, recent activity, "needs attention" queue
open http://localhost:3000
# Full run history with filters
open http://localhost:3000/runs
# Temporal Web UI — real-time workflow state, history, signals
open http://localhost:8233

Or via the API:

Terminal window
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/v1/workflows
curl -H "Authorization: Bearer $TOKEN" 'http://localhost:8080/api/v1/workflow-runs?status=RUNNING'
Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
TEMPORAL_ADDRESS Yes Temporal server address (default: localhost:7233)
CONFIG_ENCRYPTION_KEY Yes AES-256-GCM key (base64-encoded 32 bytes) for encrypting provider_credentials.api_key_ciphertext. Generate with openssl rand -base64 32.
GITHUB_TOKEN Bootstrap⁵ GitHub PAT with repo scope — env var is a bootstrap fallback; the DB value set at /admin/integrations → GitHub takes precedence
GITHUB_WEBHOOK_SECRET Bootstrap⁵ Secret for verifying GitHub webhook signatures — same DB-primary rule as GITHUB_TOKEN
JWT_SECRET Yes¹ Secret for HS256 JWTs (used when JWT_PRIVATE_KEY_PATH is unset — default for Docker Compose)
JWT_PRIVATE_KEY_PATH Optional¹ Path to RSA private key. Setting this switches JWT signing to RS256
JWT_PUBLIC_KEY_PATH Optional¹ Path to RSA public key. Required when using RS256
BETTER_AUTH_URL Prod² Gateway base URL used as the OAuth callback origin
BETTER_AUTH_SECRET Yes² ≥32-char secret for signing better-auth session cookies; yarn db:seed needs it too
SEED_ADMIN_PASSWORD Seed Password for the seeded admin user; yarn db:seed refuses to run without it
SEED_ADMIN_EMAIL Optional Override for the seeded admin email (default: admin@auto-swe.local)
PORT Optional Gateway HTTP port (default: 8080)
CORS_ORIGIN Optional Comma-separated browser origins; first entry is the better-auth client origin
PUBLIC_URL Optional Public base URL of the gateway used for the Slack OAuth callback
DEFAULT_TEAM_SLUG Optional Slug new better-auth sign-ups join automatically (default: default)
NEXT_PUBLIC_API_URL Web Gateway URL the web bundle calls (default: http://localhost:8080)
NEXT_PUBLIC_APP_VERSION Web Version label shown in the login page footer
NEXT_PUBLIC_SUPPORT_URL / NEXT_PUBLIC_SUPPORT_EMAIL / NEXT_PUBLIC_SUPPORT_SLACK Web (optional) Support contact shown on the sign-in, error and not-found screens and in the sidebar; omit all to hide it (see docs/configuration.md §8)
RESEND_API_KEY Optional³ Resend HTTP API key for magic-link email delivery
SMTP_HOST / SMTP_PORT Optional³ SMTP transport for magic-link email (alternative to Resend)
SMTP_USER / SMTP_PASS Optional³ SMTP auth credentials (omit for unauthenticated relays)
AUTH_FROM_EMAIL Optional³ From address for magic-link / verification emails
GITHUB_CLIENT_ID Optional⁴ GitHub OAuth client id (enables “Continue with GitHub”)
GITHUB_CLIENT_SECRET Optional⁴ GitHub OAuth client secret
GOOGLE_CLIENT_ID Optional⁴ Google OAuth client id (enables “Continue with Google”)
GOOGLE_CLIENT_SECRET Optional⁴ Google OAuth client secret
SLACK_CLIENT_ID Optional Slack OAuth app credentials
SLACK_CLIENT_SECRET Optional Slack OAuth app credentials
SLACK_SIGNING_SECRET Optional For verifying Slack interactive webhook signatures
SLACK_BOT_TOKEN Optional Bot token (xoxb-…) for posting run notifications
BRANCH_PREFIX Optional Git branch prefix (default: auto)
GITHUB_URL Optional Override for GitHub Enterprise Server
GITHUB_API_URL Optional Override for GitHub Enterprise Server API
OTEL_EXPORTER_OTLP_ENDPOINT Optional OTLP/gRPC endpoint (:4317) for traces, metrics + logs (set when running yarn docker:app:up)
ARTIFACT_S3_* Optional S3-compatible artifact store; falls back to Postgres-inline when unset. yarn docker:infra:up ships a Garage container at localhost:9000 that provisions its key and bucket on first boot, or point it at AWS S3 / R2 / B2 instead (see .env.example)

¹ JWT auth has two modes: HS256 (default — set JWT_SECRET) or RS256 (set JWT_PRIVATE_KEY_PATH + JWT_PUBLIC_KEY_PATH). ² Required everywhere except yarn dev:gateway, which sets NODE_ENV=development and may fall back to a dev-only placeholder. The seed’s better-auth step and every Docker image run without that, and refuse the placeholder. ³ Magic-link email transport. Choose one: SMTP (SMTP_* + AUTH_FROM_EMAIL) or Resend (RESEND_API_KEY + AUTH_FROM_EMAIL). Without either, links print to gateway stdout (dev only). ⁴ OAuth providers — the matching login button is hidden when its env vars are unset. See docs/oauth-setup.md for the full setup. ⁵ GitHub credentials are DB-primary: configure them at /admin/integrations → GitHub after first boot (resolveGitHubConfig() falls back to the env vars only when no DB row exists). One of the two must be configured somewhere for the worker/webhooks to function; GitHub App auth is also available (see docs/github-app-setup.md).

Provider API keys (Anthropic, OpenAI, Google, OpenAI-compatible) and per-role model selection are NOT env vars — they live in the database and are managed at /models. See docs/model-configuration.md for the bootstrap flow and day-2 operations.

See .env.example for the full annotated template, including LLM provider selection, per-model price overrides, and embedding configuration.

Terminal window
yarn build # Build all packages
yarn test # Run all tests (Vitest)
yarn lint # Lint + format check (Biome)
yarn lint:fix # Auto-fix safe lint issues + format
yarn docs:check # Fail on stale doc claims or broken doc links
yarn migrations:check # Apply migrations to a throwaway Postgres (needs Docker) and diff against schema.prisma
yarn db:deploy # Apply the committed Prisma migrations
yarn db:migrate # Create a new migration from a schema.prisma change (dev only)
yarn db:generate # Regenerate Prisma client
yarn db:seed # Seed admin user + sample repository
yarn dev:gateway # Gateway in watch mode
yarn dev:worker # Worker in watch mode
yarn dev:web # Next.js dashboard (port 3000)
yarn docker:infra:up # Start infra services (postgres + temporal + temporal-ui + garage). Garage starts only when COMPOSE_PROFILES includes objectstore. Observability (Grafana/OTel) starts with yarn docker:app:up.
yarn docker:infra:down # Stop infra services
yarn docker:app:up # Start everything (infra + app)
yarn docker:app:down # Stop everything
yarn docker:app:logs # Tail logs (infra + app)
yarn docker:app:build # Rebuild app images

With just installed, just infra-up, just dev-up, just prod-up (and the matching -down/-logs/-ps recipes; just --list) wrap the same compose stacks.

packages/
├── shared/ # Prisma schema, DB client, shared types, workflow engine (spec + interpreter)
├── gateway/ # Fastify 5.x HTTP API (auth, RBAC, routes, webhooks)
├── worker/ # Temporal worker, Mastra agents, activities
├── web/ # Next.js 16 web dashboard (App Router, React Flow template editor)
├── cli/ # auto-swe binary — thin REST client over the gateway (+ local bundle authoring)
└── sdk/ # @auto-swe/sdk — bundle authoring SDK (defineAgent/Skill/Template, signBundle)

See AGENTS.md for full conventions, critical implementation notes, and design decisions.

Decision Rationale
Docker, or Kubernetes pods Docker needs no cluster; WORKSPACE_BACKEND=kubernetes runs agent workspaces as pods
Temporal.io for orchestration Durable execution — workflows survive crashes and wait days for human signals
Human-governed merges By default nothing merges a PR; the one opt-in path is per-repository native auto-merge, see docs/pr-evaluation.md
PAT or GitHub App PAT for simplicity; GitHub App (short-lived installation tokens) for production — see docs/github-app-setup.md
pgvector for agent memory Semantic similarity search surfaces relevant past lessons into agent context
Mastra + Vercel AI SDK Mastra agents bind models through the AI SDK provider adapters; getModel(key, ctx) picks the provider from DB config, so agent code never imports a provider directly

© 2026 Jorge Barnaby

Source-available under FSL-1.1-MIT

Source on GitHub

Built with Astro and Starlight