@coralai/sps-cli
v0.51.16
Published
SPS CLI — AI-driven development pipeline orchestrator
Maintainers
Readme
SPS CLI — AI Agent Harness & Development Pipeline
中文文档:README-CN.md
v0.51.3
SPS (Smart Pipeline System) drives a Claude Code worker through task cards — code, commit, push, QA, merge, all automated. Three modes:
| Mode | Command | When |
|---|---|---|
| Harness | sps agent | Zero-config — one-shot or multi-turn chat with Claude. No project, no PM. |
| Pipeline | sps tick <project> | Automated card-driven workflow with YAML-configurable stages. |
| Console | sps console | Web UI — kanban, logs, workers, projects, chat (since v0.44). |
The headline feature in v0.51 is the Wiki Knowledge Base — opt-in per project, structured cross-linked pages (modules / concepts / decisions / lessons / sources), 5-layer retrieval auto-injected into worker prompts. See doc-28 and ATTRIBUTION.md.
Table of contents
- Install & setup
- Harness mode (
sps agent) - Console mode (
sps console) - Pipeline mode (
sps tick) - Card lifecycle
- Memory + Wiki
- Skills
- Command reference
- Project config (conf)
- Project layout
- Architecture
- Troubleshooting
Install & setup
npm install -g @coralai/sps-cli # latest 0.51.x
sps setup # interactive wizard (must run once)sps setup:
- Creates
~/.coral/directory tree (projects/,memory/{user,agents}/). - Copies bundled skills →
~/.coral/skills/. - Asks for
GITLAB_URL/GITLAB_TOKEN/MATRIX_*(optional) → writes~/.coral/env. - Symlinks user skills →
~/.claude/skills/. - Installs
@agentclientprotocol/claude-agent-acpglobally.
Re-run safe with sps setup --force (keeps existing values as defaults). After upgrading sps-cli later, run sps skill sync --force to pull updated skill SOPs (default sync is non-destructive — won't overwrite existing skills).
Prerequisites: Node ≥ 18; an Anthropic API key (or Claude Pro / Max subscription); claude CLI in PATH.
Harness mode (sps agent)
Direct one-shot or multi-turn chat with Claude. No project, no PM, no Git.
# One-shot
sps agent "Explain this repo"
sps agent --output summary.md "Summarize the architecture"
# Multi-turn (daemon-backed, persistent sessions)
sps agent --chat # interactive REPL
sps agent --chat --name reviewer # named session, resume later
sps agent status # list active sessions
sps agent close --name reviewer
# Profile + context files
sps agent --profile reviewer "Review this module" --context src/auth.ts --context src/auth.test.ts
sps agent --system "You are a release engineer" "Plan the v0.52 cut"
# Verbose
sps agent --verbose "Why did this build fail?"--profile <name>: looks up ~/.coral/skills/dev-worker/references/<name>.md, injects as system prompt. (Different from sps skill add — that's for project-level skill linking.)
Built-in agent: claude only (Codex / Gemini support removed in v0.38). Workers communicate via ACP JSON-RPC over stdio with claude-agent-acp.
Agent skills auto-loaded by Claude Code: ~/.claude/skills/ is scanned by claude itself — including sps-pipeline, sps-memory, wiki-update, and the 24 dev/persona skills. Skill descriptions trigger lazy load; no SPS prompt injection needed for harness mode.
Daemon cwd caveat: sps console and sps agent --chat start a session daemon (~/.coral/sessions/daemon.sock) that captures process.cwd() at startup and uses it as the default working directory for all chat workers. To switch the chat's working directory, restart the daemon: sps agent daemon stop && sps agent daemon start from the desired cwd.
Console mode (sps console)
Local web UI bundled into the binary. Single-instance guard via ~/.coral/console.lock.
sps console # opens http://127.0.0.1:4311
sps console --port 5000
sps console --no-open # don't auto-open browser
sps console --kill # stop running console
sps console --dev # vite dev server (development)Pages:
| Path | Purpose |
|---|---|
| /projects | List all projects with status |
| /projects/new | Create project (form has Wiki toggle, v0.51+) |
| /projects/<n> | Pipeline editor + conf editor + delete |
| /board | Kanban (per-column scrolling, v0.51.1+) |
| /workers | Aggregate worker dashboard across projects |
| /logs | Live SSE log viewer |
| /skills | User-level skill management |
| /system | Global settings + daemon status |
| /chat | Agent chat (multi-session, persistent) |
Tech: Hono server on 127.0.0.1:4311, chokidar watchers pushing SSE to React 19 + Vite + Tailwind v4 + shadcn/ui frontend. Design system: Pastel Neubrutalism, locked in console/DESIGN.md.
Pipeline mode (sps tick)
Fully automated card-driven workflow. One worker, one card at a time, serial. Each card walks one or more YAML-defined stages (e.g. develop → review → Done); failure halts pipeline until you remove the NEEDS-FIX label.
Create a project
sps project init my-app
# or use Console /projects/new — has a Wiki toggle (v0.51+)Asks for: project dir, merge branch, max workers, ACK timeout, optional GitLab remote, optional Matrix room.
Generates:
~/.coral/projects/my-app/
├── conf # mode 600 — your active config
├── conf.example # full reference (read-only docs)
├── pipelines/
│ ├── project.yaml # default 1-stage pipeline (develop → Done)
│ └── sample.yaml.example # heavily-commented YAML reference
└── pipeline_order.json # active pipeline pointerIn the target repo (PROJECT_DIR):
.claude/CLAUDE.md # worker rules (auto-installed)
.claude/skills/ # symlinked from ~/.coral/skills/
.claude/settings.local.json # Claude Code local config
wiki/ # if WIKI_ENABLED — see doc-28
ATTRIBUTION.md # if WIKI_ENABLEDRun
sps tick my-app # foreground tick loop
sps pipeline start my-app # alias
sps pipeline stop my-app # graceful stop (alias: sps stop my-app)
sps stop --all # stop all running ticks
sps status # all projectsPipeline YAML
~/.coral/projects/<n>/pipelines/project.yaml — single source of truth for stages.
mode: project
git: true # false = non-code project, no git ops
stages:
- name: develop
profile: fullstack
on_complete: "move_card Review"
on_fail: { action: "label NEEDS-FIX", halt: true }
- name: review
profile: reviewer
on_complete: "move_card Done"
on_fail: { action: "label REVIEW-FAILED", halt: true }Critical rules:
mode: projectfor state-machine pipelines;mode: stepsfor one-shot custom (usesps pipeline run <name>).- Each stage's
on_completemust point to the next stage's target state. - Last stage's
on_complete: "move_card Done". - Don't write
agent:field — it's silently ignored (v0.38+ Claude is the only worker). triggerandcard_stateare auto-derived per stage.
Field reference: see ~/.coral/projects/<n>/pipelines/sample.yaml.example (auto-generated, comment-rich) or doc-17.
Card lifecycle
Backlog → Todo → Inprogress → [QA / Review] → Done
↑↓ ↓ fail
Planning NEEDS-FIX (halt)
(manual park, v0.51.9+)v0.51.10: caller-aware default state.
sps card add(CLI / agent / API default) → Backlog(自动跑)- Console "新卡片" 表单(人在 UI 操作) → Planning(暂存,等用户拖到 Backlog)
CLI 用户想暂存:sps card add ... --draft。Console 用户想立即跑:勾"立即派发执行"。
卡片严格按 seq 排序;不再有 pipeline_order.json。
Default states (configurable via YAML pm.card_states).
sps card add <p> "Title" "Description"
sps card add <p> "T" "D" --skills python,backend --labels feature
sps card dashboard <p> # CLI table
# console: /board?project=<n>
sps card mark-started <p> <seq> # called by Claude Code UserPromptSubmit hook
sps card mark-complete <p> <seq> # called by Claude Code Stop hook
sps reset <p> # reset all non-Done cards
sps reset <p> --card 5,6,7
sps reset <p> --all # full reset incl. Done + worktrees + branchesCard label vocabulary
| Label | Meaning | Set by |
|---|---|---|
| AI-PIPELINE | Required to enter pipeline | User on creation |
| STARTED-<stage> | ACK signal — Claude received the prompt | UserPromptSubmit hook |
| COMPLETED-<stage> | Worker finished a stage | Stop hook |
| CLAIMED | StageEngine reserved a worker slot | Engine |
| NEEDS-FIX | Worker failed; pipeline halted | Engine |
| BLOCKED | External dep; pipeline skips | User |
| WAITING-CONFIRMATION | Worker waiting on user input | Engine |
| STALE-RUNTIME | Inprogress > timeout | MonitorEngine |
| ACK-TIMEOUT | Claude never ACK'd within WORKER_ACK_TIMEOUT_S | MonitorEngine |
| skill:<name> | Force-load specific skill | User |
| conflict:<domain> | Serial-with-others-in-same-domain | User |
The active stage writes a per-slot marker file at ~/.coral/projects/<p>/runtime/worker-<slot>-current.json (v0.50.21+). Stop hook reads it to detect which card the worker just finished.
Memory + Wiki
Two complementary persistence systems, both auto-injected into worker prompts.
| | Memory | Wiki (v0.51+) |
|---|---|---|
| Path | ~/.coral/memory/{user,agents,projects/<p>}/ | <repo>/wiki/ (per-project, in repo) |
| Format | Flat markdown + YAML frontmatter | 5 page types with zod-validated frontmatter |
| Cross-link | None (flat index) | [[type/Title]] wikilinks |
| Auto-inject | knowledge section of prompt | wikiContext section (5-layer retrieval) |
| Opt-in | Always on (toggle via ENABLE_MEMORY=false) | Per-project (WIKI_ENABLED=true) |
| Best for | Personal prefs, ad-hoc decisions, gotchas | Structured project knowledge: modules, concepts, decisions, lessons |
Memory CLI
sps memory list <p> # show project memory index
sps memory list # global view (user + agents)
sps memory context <p> --card <seq> # preview prompt injection
sps memory add <p> --type convention --name "API uses camelCase" \
--description "REST endpoints use camelCase" --body "..."Types: convention (no decay), decision (slow), lesson (30 days), reference (no decay).
Wiki CLI (when WIKI_ENABLED=true)
sps wiki init <p> # scaffold wiki/ (auto on project init if toggled on)
sps wiki update <p> # show source diff
sps wiki update <p> --finalize # flush manifest after worker writes pages
sps wiki check <p> # lint: orphan / dead-link / fm-gap / stale
sps wiki list <p> --type lesson --tag pipeline
sps wiki get <p> lessons/Stop-Hook-Race
sps wiki status <p> # source ↔ manifest ↔ pages diff
sps wiki add <p> ~/notes.md --category transcripts
sps wiki read <p> "<query>" # preview the 5-layer retrievalThe 5-layer retrieval: hot.md / index summary / pinned / skill-tag / BM25F keyword. Type priority: lesson = 3, decision = 3, concept = 2, module = 1, source = 1. Token budget capped at ~2000.
Worker SOP: skills/wiki-update/SKILL.md (300 lines, single source of truth).
Skills
User-level skills live in ~/.coral/skills/ (28 bundled, copied from npm package on sps setup). Symlinked into ~/.claude/skills/ so Claude Code auto-loads them.
sps skill list # what's available + project status
sps skill add <name> --project <p> # symlink into <repo>/.claude/skills/
sps skill remove <name> --project <p>
sps skill freeze <name> --project <p> # symlink → real copy (allow project edits)
sps skill unfreeze <name> --project <p> # back to symlink
sps skill sync # ① bundled (npm pkg) → ~/.coral/skills/
# ② ~/.coral/skills/ → ~/.claude/skills/
sps skill sync --force # ⭐ overwrite existing user skills (after sps-cli upgrade)Bundled skills (v0.51.3):
- Dev (23):
frontend,frontend-developer,backend,backend-architect,typescript,golang,rust,python,java,kotlin,swift,mobile,database,database-optimizer,qa-tester,security-engineer,architecture-decision-records,coding-standards,debugging-workflow,devops,devops-automator,git-workflow,code-reviewer - Worker profiles (3):
dev-worker,tax-worker,reviewer(referenced via--profile) - SPS-specific (5):
sps-pipeline,sps-memory,wiki-update
Command reference
# Setup & projects
sps setup [--force]
sps project init <name>
sps project doctor <name> [--fix] [--json] [--reset-state] [--skip-remote]
sps doctor <name> --fix # alias
# Pipeline
sps tick <project> [--json]
sps pipeline start|stop|status|reset|workers|board|card|logs|list|run|use [project] [args]
sps pipeline run <name> "<prompt>" # for mode: steps pipelines
sps pipeline tick <project> # one-off StageEngine pass
sps scheduler tick <project> # dormant since v0.51.9 (kept for tick orchestrator)
sps qa tick <project> # QA → Done finalization
sps monitor tick <project> # health probe (ACK timeout, stale)
sps pm scan <project> # rebuild card index from disk
# Cards
sps card add <p> "title" ["description"] [--skills a,b] [--labels x,y]
sps card dashboard <p>
sps card mark-started <p> [seq] [--stage <name>]
sps card mark-complete <p> <seq> [--stage <name>]
# Worker
sps worker ps <project>
sps worker dashboard <project>
sps worker kill <project> <seq>
sps worker launch <project> <seq>
# Status / logs
sps status [--json]
sps stop <project> [--all]
sps reset <project> [--all] [--card N,N,N]
sps logs [project] [--err] [--lines N] [--no-follow]
# Memory
sps memory list [project] [--agent <id>]
sps memory context <project> [--card <seq>] [--agent <id>]
sps memory add <project> --type <T> --name "title" [--body "content"]
# Wiki (v0.51+)
sps wiki init <p>
sps wiki update <p> [--finalize] [--json]
sps wiki read <p> "<query>" [--skills a,b] [--pinned id1,id2] [--budget N]
sps wiki check <p> [--json] [--fix]
sps wiki add <p> <file> [--category <name>] [--no-ingest]
sps wiki list <p> [--type T] [--tag T] [--json]
sps wiki get <p> <pageId> [--json]
sps wiki status <p> [--json]
# Skill
sps skill list [--project <p>]
sps skill add <name> [--project <p>]
sps skill remove <name> [--project <p>]
sps skill freeze <name> [--project <p>]
sps skill unfreeze <name> [--project <p>]
sps skill sync [--force]
# Console
sps console [--port N] [--host H] [--no-open] [--dev] [--kill]
# Agent
sps agent "<prompt>" [--profile <p>] [--system "..."] [--context file] [--output file] [--verbose]
sps agent --chat [--name <session>]
sps agent status|close|list|add [args]
sps agent daemon start|stop|status
# Hooks (called by Claude Code, not by users)
sps hook stop
sps hook user-prompt-submit
# ACP control (for advanced debugging)
sps acp <ensure|run|prompt|status|stop|pending|respond> <project> [args]Add --help after any command to see its specific usage. Add --json for structured output where supported.
Project config (conf)
Live at ~/.coral/projects/<name>/conf (shell export VAR="value" syntax, mode 600). Full field reference (with comments) auto-generated at ~/.coral/projects/<name>/conf.example.
| Field | Default | Notes |
|---|---|---|
| PROJECT_NAME | (required) | Internal id |
| PROJECT_DIR | (required) | Absolute path to repo |
| GITLAB_PROJECT | — | user/repo (optional, for GitLab API) |
| GITLAB_PROJECT_ID | — | Numeric ID (GitLab only; auto-resolved from path on first MR) |
| GITLAB_MERGE_BRANCH | main | Worker pushes here |
| PM_TOOL | markdown | Only markdown supported as of v0.42. Cards live in ~/.coral/projects/<n>/cards/<state>/<seq>.md |
| PIPELINE_LABEL | AI-PIPELINE | Required label on cards to enter pipeline |
| MR_MODE | none | none (push direct) / create (open MR; needs GITLAB_PROJECT_ID) |
| WORKER_TRANSPORT | acp-sdk | Fixed; do not change |
| MAX_CONCURRENT_WORKERS | 1 | Slot count; cards still serial within a project |
| MAX_ACTIONS_PER_TICK | 3 | New tasks claimable per tick |
| INPROGRESS_TIMEOUT_HOURS | 2 | After this, MonitorEngine flags STALE-RUNTIME |
| WORKER_ACK_TIMEOUT_S | 300 | Wait for STARTED- label after dispatch (5min, raised in v0.50.24) |
| WORKER_ACK_MAX_RETRIES | 1 | ACK timeout retry count |
| MONITOR_AUTO_QA | true | Auto-advance to QA on stale runtime |
| CONFLICT_DEFAULT | serial | Fallback for cards without conflict: label |
| MATRIX_ROOM_ID | — | Project-level Matrix override |
| WORKTREE_DIR | ~/.coral/worktrees/<p> | Worker scratch space |
| DEFAULT_WORKER_SKILLS | — | Comma-separated; fallback when no profile: and no card.skills |
| ENABLE_MEMORY | true | false skips memory write instructions in prompt |
| WIKI_ENABLED | unset (off) | v0.51+: true enables wiki context injection + reminder |
| COMPLETION_SIGNAL | done | Word the Stop hook listens for |
Global credentials at ~/.coral/env: GITLAB_URL, GITLAB_TOKEN, GITLAB_SSH_HOST, GITLAB_SSH_PORT, MATRIX_HOMESERVER, MATRIX_ACCESS_TOKEN, MATRIX_ROOM_ID. Set via sps setup or vim.
Project layout
~/.coral/ # User-global state
├── env # Global credentials (mode 600)
├── skills/ # User-level skills (synced from npm)
├── memory/{user,agents,projects}/ # 3-layer memory store
├── projects/<name>/ # Per-project state
│ ├── conf # Project config (mode 600)
│ ├── conf.example # Field reference (auto-generated)
│ ├── pipelines/{project,*}.yaml # Pipeline definitions
│ ├── pipeline_order.json # Active pipeline pointer
│ ├── runtime/state.json # Worker slot + active card state
│ ├── runtime/worker-<slot>-current.json # Per-slot card marker (v0.50.21+)
│ ├── runtime/tick.lock # Tick lock
│ ├── runtime/acp-state.json # ACP session state
│ ├── cards/<state>/<seq>.md # Card files (markdown PM backend)
│ ├── cards/seq.txt # Sequence counter
│ ├── logs/ # Per-tick logs
│ └── pm_meta/ # Card index
├── sessions/ # Agent daemon (chat sessions)
│ ├── daemon.sock daemon.pid
│ └── chat-sessions/<id>.json # Persisted chat sessions
├── console.lock # Single-instance guard for console
└── worktrees/<project>/<seq>/ # Worker worktree per active cardIn the target repo (PROJECT_DIR):
.claude/
├── CLAUDE.md # Worker rules (project-specific + SPS-injected)
├── settings.local.json # Claude Code local config
├── skills/ # Symlinked from ~/.coral/skills/
└── hooks/{start,stop}.sh # Lifecycle hooks (call into sps)
wiki/ # If WIKI_ENABLED — see docs/design/28-wiki-system.md
ATTRIBUTION.md # If WIKI_ENABLEDArchitecture
4-layer service architecture (v0.50+):
Delivery (commands/, console/routes/) Thin parameter parsing + I/O orchestration
↓
Service (services/) ProjectService / ChatService / PipelineService /
SkillService / WikiService — Result<T> + DomainEvent
↓
Domain (engines/) SchedulerEngine / StageEngine / MonitorEngine /
CloseoutEngine / EventHandler — pipeline logic
↓
Infrastructure WorkerManager (single worker), ACPWorkerRuntime,
(manager/, providers/, daemon/) sessionDaemon, TaskBackend, RepoBackendEngines:
- SchedulerEngine — dormant since v0.51.9 (cards go directly to Backlog on add; Planning is a manual park). Class kept as a no-op for the tick orchestrator's stable interface.
- StageEngine — drives card through stages; builds prompt (skill + projectRules + memory + wikiContext + task description + wikiUpdateReminder); kicks worker via ACP.
- MonitorEngine — ACK timeout detection, stale runtime, auto-QA promotion.
- CloseoutEngine + EventHandler — finalize completed cards.
Single-worker is intentional: v0.37.2 deleted multi-worker concurrency code. Don't propose "add a parallel mode" — the architecture relies on serial execution for state coherence. For higher throughput, run multiple projects in parallel.
For deep dives:
- doc-27: Service Layer Architecture — current architecture
- doc-26: Console Architecture — console internals
- doc-28: Wiki System — wiki design
- doc-13: Development Guardrails — hard rules for contributors
- doc-17: Pipeline Configuration — YAML field semantics
- docs/design/ — full design tree (most v0.15-v0.32 docs are marked HISTORICAL)
Troubleshooting
sps doctor <project> --fix # ★ first thing to try
sps logs <project> --err # stderr / errors only
sps reset <project> --card <seq> # nuke a stuck card
sps reset <project> --all # full project reset
# Worker / daemon issues
sps worker ps <project>
sps agent daemon status # is the chat daemon up?
sps agent daemon stop && sps agent daemon start # restart (clears stale cwd)
# Wiki issues
sps wiki check <project>
sps wiki status <project>Common issues:
| Symptom | Cause / fix |
|---|---|
| Pipeline halted with NEEDS-FIX | Open the failed card, fix the issue, remove the label. Console makes this 2 clicks. |
| Worker not starting | sps worker ps, then sps logs --err. Often Claude API key missing or claude-agent-acp adapter not installed (sps setup reinstalls). |
| Cards stuck in Planning | Need AI-PIPELINE label. sps card add applies it automatically; if added externally, add manually. |
| ACK timeout on every card | Claude cold-start is slow with many skill / memory files. Raise WORKER_ACK_TIMEOUT_S (default 300s as of v0.50.24). |
| Console shows stale data | SSE may have dropped; reload page; if persistent, sps console --kill && sps console. |
| Wiki context not injecting | Verify WIKI_ENABLED=true in conf and wiki/WIKI.md exists. StageEngine logs a warning if conf says yes but scaffold is missing. |
| New skill SOP not pulling after upgrade | sps skill sync --force (default sync skips existing skills). |
| Daemon chat using wrong cwd | Daemon captures cwd at startup. sps agent daemon stop && cd <repo> && sps agent daemon start. |
License & attribution
MIT, see LICENSE.
The Wiki system (v0.51+) borrows ~70% from claude-obsidian (MIT) — three-layer architecture, manifest delta tracking, hot cache, ingest workflow, contradiction callouts, wikilinks. SPS-specific 30%: 5 page types, sources={card,commit,path}, 5-layer reader, sps wiki check exit gate. Mental model from Karpathy's "LLM Wiki" gist.
Full attribution: ATTRIBUTION.md.
