SPS CLI — AI Agent Harness & Development Pipeline

中文文档:README-CN.md
OpenAI daemon agent: configuration, security, recovery, and operations
v0.59.0
SPS (Smart Pipeline System) drives a Claude Code worker through task cards — code, commit, push, QA, merge, all automated. Three modes:
| 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 — voice-first home, kanban, logs, projects, chat, memory, plugins, system (config / processes / doctor / audit). |
The headline of v0.59 is a redesigned Console: a voice-first home (speak or type to a live agent, with an animated intro and a morphing voice-orb ↔ text-input), Doubao (Volcengine) large-model TTS for speech output (remote API, configured via SPS_DOUBAO_* in ~/.coral/env), a unified System page (config / processes / doctor / audit), and a consistent Pastel-Neubrutalism theme with light/dark switching. The Wiki Knowledge Base (opt-in per project, 5-layer retrieval auto-injected into worker prompts) remains — see doc-28 and ATTRIBUTION.md.
Table of contents
Install & setup
npm install -g @coralai/sps-cli
sps setup
sps setup:
- Creates the
~/.coral/ directory tree (projects/, memory/, …).
- Copies bundled skills →
~/.coral/skills/ (the single skills source; the global ~/.claude/skills dir is no longer used — setup also prunes legacy link pollution there).
- Asks for
GITLAB_URL / GITLAB_TOKEN / MATRIX_* (optional) → writes ~/.coral/env, with a commented reference of optional keys (memory / voice TTS / daemon sandbox & concurrency gate) at the end — the same file the Console System page edits visually.
- Pins the workspaces root
SPS_WORKSPACES_ROOT (default ~/coral-workspaces).
Re-run safe with sps setup --force (keeps existing values as defaults).
Prerequisites: Node ≥ 18 (≥ 22 recommended — code-graph & memory index use node:sqlite); for the claude backend a logged-in claude CLI (or API key / subscription); for the openai backend codex login (subscription) or endpoints registered in ~/.coral/agent-providers.json.
Upgrading a stale install: clean reinstall recommended
Installs that are many versions behind (especially pre-0.6x / ACP-era) accumulate retired config keys, old-schema state files, and legacy symlinks that cause hard-to-debug oddities. Prefer a full clean reinstall over an in-place upgrade:
pm2 delete all 2>/dev/null
sps console --kill 2>/dev/null
sps agent daemon stop 2>/dev/null
npm rm -g @coralai/sps-cli
mv ~/.coral ~/.coral.bak-$(date +%m%d)
rm -rf ~/coral-workspaces
rm -rf ~/.claude/skills
npm i -g @coralai/sps-cli && sps setup
Keep-list before wiping (copy back from the backup as needed): claude CLI credentials (~/.claude/, don't delete the dir), codex subscription auth (~/.codex/auth.json; re-run codex login if expired), your memory store (memory/ → ~/.coral/memory/), custom skills (bundled ones reinstall automatically), and any hand-filled secrets from the old env — transcribe valid keys into the new template rather than copying the whole file (old templates contain retired keys).
Version discipline after any upgrade: CLI / console / daemon must run the same version — upgrading the npm package does not restart running processes. Run sps agent daemon restart (check for in-flight work first), restart the console, and hard-refresh the browser. Platforms embedding sps (e.g. coral-platform) upgrade their own dependency and restart their own process.
Deployment (server / from source)
For running sps-cli as long-lived services (Console web UI + IM gateway + pipeline) on a server, deploy from source. An AI or operator can follow the steps below end to end.
npm install -g @coralai/sps-cli gives you the sps CLI only. To actually run it, also provide:
Model / subscription config lives outside the package (secrets, per machine): the official subscription (claude login) works out of the box; third-party endpoints go in ~/.coral/game-platform/providers.json; the worker's default model in ~/.coral/agents/smartarrange.json (optional).
Verify the box is ready:
sps project init demo
sps doctor demo --fix
Per-feature extras (only if used): IM gateway → ~/.coral/im/config.json; remote Console → SPS_CONSOLE_TOKEN.
Dependencies
- Node ≥ 22 and npm (the code-graph feature imports
node:sqlite — DatabaseSync — which requires Node ≥ 22; the rest of the CLI runs on ≥ 18).
- git.
- Claude auth for workers: either
ANTHROPIC_API_KEY in the environment, or a logged-in claude CLI (Pro / Max subscription). sps setup installs the worker transport @agentclientprotocol/claude-agent-acp globally.
- No native/compiled dependencies —
@colbymchenry/codegraph and the rest are pure JS; a plain npm install is enough.
1. Clone, install, build
git clone <repo-url> sps-cli && cd sps-cli
npm install
npm run build
sps setup
npm run build runs both halves and is the only correct build command:
build:cli → rm -rf dist && tsc (compiles src/ → dist/).
build:console → cd console && npm install && vite build, then copies console/dist → dist/console-assets. The console has its own node_modules; this step installs it for you — you do not run a separate install in console/.
⚠️ Never run npm run build:cli alone. Its rm -rf dist wipes dist/console-assets, so the Console web UI breaks with a 500 / missing index.html. Always use the full npm run build.
Expose the binary, or invoke dist/main.js directly:
npm link
node dist/main.js <command>
2. Run the services
Console (web UI):
sps console
SPS_CONSOLE_TOKEN=$(openssl rand -hex 24) sps console --host 0.0.0.0 --port 4321 --no-open
SPS_CONSOLE_TOKEN gates access. When binding to 0.0.0.0, always set it — without a token the UI is unauthenticated on the network. The startup banner prints the tokenized URL.
IM gateway (sps im) — inbound + outbound bots for Telegram / DingTalk (Stream) / Feishu-Lark / Slack / Discord / Matrix, with in-chat project switching:
sps im
Configure channels the easy way in the Console → Plugins → Channel page (left = channel list, right = settings; it writes the file for you). Or edit ~/.coral/im/config.json directly:
{
"console": { "url": "http://localhost:4321", "token": "<SPS_CONSOLE_TOKEN>", "agentKind": "claude" },
"adapters": [
{ "kind": "telegram", "token": "<bot-token>", "allowedChatIds": [123456789] }
]
}
console.url + token bridge IM plain-text messages to project-agent chat. After changing the config, restart sps im for it to take effect. (Feishu is the only adapter needing a public callback; the rest work without inbound ports.)
Pipeline:
sps tick my-app
3. Keep the services alive
sps console, sps im, and sps tick are foreground processes. Use nohup or a systemd unit for persistence:
SPS_CONSOLE_TOKEN=<hex> nohup node dist/main.js console --host 0.0.0.0 --port 4321 --no-open > ~/console.log 2>&1 &
nohup node dist/main.js im > ~/im.log 2>&1 &
For a systemd --user service, point ExecStart=node /abs/path/sps-cli/dist/main.js console --host 0.0.0.0 --port 4321 --no-open and set Environment=SPS_CONSOLE_TOKEN=....
4. Upgrading
git pull && npm install && npm run build
sps skill sync --force
Newly added Console API routes (e.g. /api/channels) only take effect after the console process restarts — rebuild alone is not enough.
Harness mode (sps agent)
Direct one-shot or multi-turn chat with Claude. No project, no PM, no Git.
sps agent "Explain this repo"
sps agent --output summary.md "Summarize the architecture"
sps agent --chat
sps agent --chat --name reviewer
sps agent status
sps agent close --name reviewer
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"
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
sps console --port 5000
sps console --no-open
sps console --kill
sps console --dev
Pages:
/projects | List all projects with status |
/projects/new | Create project (Wiki toggle + worker-model picker, v0.58.3+) |
/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 |
/plugins | Model endpoints + IM channels + memory backend config (v0.58+) |
/system | Global settings + daemon status |
/chat | Agent chat (multi-session; per-session model picker, v0.58.3+) |
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.
Model selection (v0.58.3+): the worker/chat model is chosen per project / per session at creation (dropdown of configured endpoints); leaving it unset uses the global default (~/.coral/agents/smartarrange.json). Project picks are written to the repo's .claude/settings.local.json; session picks are injected per-session. sps-cli does no global model env injection — the global config is only the fallback default.
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
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 pointer
In 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_ENABLED
Run
sps tick my-app
sps pipeline start my-app
sps pipeline stop my-app
sps stop --all
sps status
Pipeline YAML
~/.coral/projects/<n>/pipelines/project.yaml — single source of truth for stages.
mode: project
git: true
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: project for state-machine pipelines; mode: steps for one-shot custom (use sps pipeline run <name>).
- Each stage's
on_complete must 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).
trigger and card_state are 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>
sps card mark-started <p> <seq>
sps card mark-complete <p> <seq>
sps reset <p>
sps reset <p> --card 5,6,7
sps reset <p> --all
Card label vocabulary
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.
| 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
⚠️ Under reconstruction (v2). The old sps memory list/add/search/context/ingest commands and read_memory/append_memory/recall MCP tools have been removed. The new local memory system (sps memory recall/save/read/...) is being rebuilt — see docs/design/memory-v2.md.
Wiki CLI (when WIKI_ENABLED=true)
sps wiki init <p>
sps wiki update <p>
sps wiki update <p> --finalize
sps wiki check <p>
sps wiki list <p> --type lesson --tag pipeline
sps wiki get <p> lessons/Stop-Hook-Race
sps wiki status <p>
sps wiki add <p> ~/notes.md --category transcripts
sps wiki read <p> "<query>"
The 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
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
sps skill sync --force
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
Agent persona & config (Output Style)
Each agent (chat / worker) gets its persona/role from an Output Style, injected per-agent — separate from the shared base, model, and execution rules. See the design doc.
Platforms (e.g. gameforge) built on sps-cli follow these rules — they only fill agent-config.json with their own outputStyle after projects.create (and pass skipDefaultAgentConfig: true to skip the generic default).
Command reference
sps setup [--force]
sps project init <name>
sps project doctor <name> [--fix] [--json] [--reset-state] [--skip-remote]
sps doctor <name> --fix
sps tick <project> [--json]
sps pipeline start|stop|status|reset|workers|board|card|logs|list|run|use [project] [args]
sps pipeline run <name> "<prompt>"
sps pipeline tick <project>
sps scheduler tick <project>
sps qa tick <project>
sps monitor tick <project>
sps pm scan <project>
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>]
sps worker ps <project>
sps worker dashboard <project>
sps worker kill <project> <seq>
sps worker launch <project> <seq>
sps status [--json]
sps stop <project> [--all]
sps reset <project> [--all] [--card N,N,N]
sps logs [project] [--err] [--lines N] [--no-follow]
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]
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]
sps console [--port N] [--host H] [--no-open] [--dev] [--kill]
sps agent "<prompt>" [--profile <p>] [--system "..."] [--context file] [--output file] [--verbose]
sps agent --chat [--name <session>]
sps agent status|close [args]
sps agent daemon start|stop|status
sps hook stop
sps hook user-prompt-submit
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.
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.
Speech output (TTS) — Doubao (Volcengine)
The Console voice home speaks via Doubao (Volcengine) large-model TTS (remote API, zero client dependencies: the browser only hits the Console domain; the backend proxies Volcengine and the key never leaves the server). Configure it in ~/.coral/env on the machine running sps console:
SPS_DOUBAO_API_KEY | ✅ | Volcengine Speech API key (new console single-header X-Api-Key auth, ark-… form) |
SPS_DOUBAO_SPEAKER | ✅ | A 2.0 voice id (suffix _uranus_bigtts), e.g. zh_female_vv_uranus_bigtts (female), zh_male_yangguangqingnian_uranus_bigtts (male) |
SPS_DOUBAO_RESOURCE_ID | no | defaults to seed-tts-2.0 |
SPS_DOUBAO_ENDPOINT | no | defaults to https://openspeech.bytedance.com/api/v3/plan/tts/unidirectional |
SPS_DOUBAO_API_KEY=ark-xxxxxxxx-...
SPS_DOUBAO_SPEAKER=zh_female_vv_uranus_bigtts
If unset, speech falls back to the browser Web Speech API. Restart with sps console --stop then start again to apply. Deploying on another machine only needs this block repeated there — no local model to install.
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 card
In 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_ENABLED
Architecture
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, RepoBackend
Engines:
- 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:
Troubleshooting
sps doctor <project> --fix
sps logs <project> --err
sps reset <project> --card <seq>
sps reset <project> --all
sps worker ps <project>
sps agent daemon status
sps agent daemon stop && sps agent daemon start
sps wiki check <project>
sps wiki status <project>
Common issues:
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.