kitdocs · github

Skill: agent-pipeline

raw markdown skills/agent-pipeline/SKILL.md

The user writes tickets in Linear. Cyrus on the always-on machine hands each one to Claude Code, and the result comes back as a PR, a commit or a deploy, depending on the repo's rule. Set-up is in workflows/agent-pipeline.md. This skill is the operator's manual.

The shape (fill in for your setup)

Piece Value
Linear workspace https://linear.app/<workspace>: one team <KEY>, one project per repo (free plan: 2 teams, unlimited projects)
Routing project name → repo, via projectKeys in ~/.cyrus/config.json
Per-repo rule written in each repo's CLAUDE.md: PR-and-stop / commit to develop / agent deploys
Runner service (launchd/systemd) on port 3456, public https://<agent-host>.<domain> via Cloudflare Tunnel
Config ~/.cyrus/config.json (routing + OAuth tokens) · ~/.cyrus/.env (secrets)
Logs ~/.cyrus/cyrus.log · per ticket ~/.cyrus/logs/<KEY-n>/
Claude the machine's own claude login; usage counts against the user's plan

Secrets rule: never cat config.json or .env. Print key names only (cut -d= -f1 ~/.cyrus/.env), and read tokens straight into a variable (see references/linear-api.md).

Quick reference

Want to… Do
Create a ticket and start the agent issueCreate with projectId + delegateId = the agent's app user (references/linear-api.md). Delegate set on create → the session starts in the same second
Hand an existing ticket over issueUpdate(delegateId). Agents live in delegate, not assignee
Check it started curl localhost:3456/status → busy; grep <KEY-n> ~/.cyrus/cyrus.log; ~/.cyrus/worktrees/<KEY-n> exists. First thought ≈10 s, real work ≈2 min
Watch it finish gh pr list --repo <owner>/<repo> --search <key-n>; summary comment on the ticket
Send it back reply in the ticket thread (same session, same PR)
Close a ticket with no PR a commit on the default branch with Fixes <KEY-n> (verify; not 100% reliable) or set state Done
Re-run a ticket that errored re-delegating does nothing; reply in the thread or file a new ticket
Diagnose "didn't start" references/cyrus.md → Diagnosing
API returns 403 do it in the Linear UI (rename/delete team, team labels)

Adding a repo (~2 min)

  1. gh repo view <owner>/<repo> resolves. Project name = repo name title-cased (my-app → My App). State the name you chose. projectKeys must match it exactly.
  2. cyrus self-add-repo https://github.com/<owner>/<repo>.git (clones and hot-reloads).
  3. Create the Linear project with that name in team <KEY> (projectCreate).
  4. Set projectKeys and delete the auto-added routingLabels (labels beat projects): bash jq '.repositories |= map(if .name=="<repo>" then del(.routingLabels) | . + {projectKeys:["<Project Name>"]} else . end)' \ ~/.cyrus/config.json > /tmp/c.json && mv /tmp/c.json ~/.cyrus/config.json
  5. If the repo has no CLAUDE.md with a deploy rule, the first ticket should add one. It is the agent's only briefing besides the ticket.

Writing a good ticket

Title = the change. Description = what to change, then Done when: with 2–4 checkable lines (including which test or browser flow must still pass), then what not to touch. Say "deploy" only if the user wants it live. For apps with real users, say "no schema change" or "docs/tests only" when that is the intent. One small, checkable change per ticket. Multi-hour phases handed to an unattended agent failed on usage limits and restarts.

Common mistakes