Complete Command Reference
Every command follows the pattern /spexso-<verb>. Commands accept arguments after the command name.
/spexso-setup
Phase: Setup | Creates: CLAUDE.md, labels issues | For: tech lead / developer
Interactive project onboarding. Scans the codebase, asks questions one at a time, generates a rich CLAUDE.md, and triages existing GitLab issues. Makes no assumptions — every decision is confirmed with the user. Safe to re-run.
Preflight check
/spexso-setup performs a preflight plugin check — it recommends installing the sap-skills plugin when missing (advisory, never blocking). Further plugins are recommended per detected stack only (cds-mcp for CAP, ui5 for UI5, and — only when a legacy test tree is detected — the one-off ui5-modernization toolkit), because every wired MCP server spends context in every session. The generated CLAUDE.md enforces Flexso standards, including a TypeScript-first policy for all new code.
/spexso-setup
# What happens:
# 1. Scans: package.json, project structure, test config, mta.yaml, existing CLAUDE.md
# 2. Presents detected stack summary — user confirms or corrects
# 3. Asks convention questions one at a time (purpose, architecture, naming, testing, target branch, etc.)
# 4. Generates CLAUDE.md — shows content, iterates until approved, writes file
# 5. If open issues exist: proposes labels for unlabeled issues, suggests closing stale ones
# 6. Runs npx spexso sync to refresh .spexso/index.json/spexso-cicd-init
Adds the Flexso-standard CI/CD pipeline to the current project: generates .gitlab-ci.yml (quality gate on every MR, 3-tier DEV/TST/PRD deploy with tag-based releases), installs commit-and-tag-version, copies .versionrc.json + the two version-updater scripts into scripts/, and writes a CICD-SETUP.md checklist (RELEASE_TOKEN, protected v* tags, release how-to). Requires mta.yaml in the repo root. Also reachable via the CI/CD question in /spexso-setup.
It asks how the pipeline should be managed — central-managed (a short .gitlab-ci.yml that includes the shared CI template on a pinned major ref, so central fixes reach the product automatically) or project-managed (the full pipeline copied into the repo) — and records the answer under cicd in .spexso/config.json. It also aligns the gate's TEST_COMMAND / STATIC_CHECKS with testCommand / staticChecks from that same config, so CI runs exactly what the builder and /spexso-finish run. See CI/CD design. See CI/CD design.
/spexso-report
Phase: Intake | Creates: GitLab issue | For: anyone on the team
Zero-friction issue reporting. The reporter just describes the problem or idea in natural language. Claude analyzes the description, auto-classifies it (bug, feature, or enhancement), estimates the size (XS--XL), and creates a structured GitLab issue in stage::opportunity using the appropriate template.
/spexso-report The leave request form crashes when the manager tries to
approve a request for an employee who has transferred departments
mid-cycle. It shows a 500 error from the SF OData API.
# What happens:
# 1. Claude analyzes the description
# 2. Auto-classifies: type::bug (crash + error code = bug signal)
# 3. Auto-sizes: size::s (single API call path, likely missing null check)
# 4. Asks 2-3 clarifying questions if needed:
# "Which BTP subaccount? Can you share the error log? Reproducible?"
# 5. Structures into bug template (steps, expected, actual, environment)
# 6. Writes the structured bug report to a temp file, then runs:
# npx spexso issue create \
# --title "Bug: 500 error on leave approval for transferred employees" \
# --label "type::bug,size::s,platform::sf,stage::opportunity" \
# --description-file "$BODY_FILE"
# 7. Updates .spexso/index.json
# 8. Prints: "Issue #51 created (bug, size S). Assigned to backlog."Auto-Classification Logic
| Signal in description | Classification | Template used |
|---|---|---|
| Error, crash, broken, doesn't work, 500, exception, regression | Bug | spec-lite.md (always lite — bugs need speed) |
| Add, new, build, create, integrate, connect, extend | Feature | spec-lite.md or spec-full.md based on size |
| Improve, change, update, better, faster, optimize, refactor | Enhancement | spec-lite.md or spec-full.md based on size |
Designed for functional consultants + sales
This command is specifically designed so that non-developers can report issues from Claude Code without knowing GitLab labels or templates. A functional consultant on a customer call can say "the user sees a blank screen when clicking the dashboard tile after SAP roles were changed" and get a properly structured bug report in GitLab within seconds.
/spexso-tinder
Phase: Discovery | Creates: research notes + enhancement issues
Competitive intelligence meets feature discovery. Searches the web and SAP ecosystem for similar products, extracts their killer features, generates a comparison matrix against your project, and auto-creates enhancement issues for the best ideas.
/spexso-tinder employee leave management
# What happens:
# 1. Spawns spexso-researcher subagent
# 2. Researcher runs parallel web searches:
# a) General: "employee leave management SaaS features 2026"
# b) SAP Store: "leave management SAP BTP extension"
# c) SAP Community: "SuccessFactors leave request extension"
# d) BTP Discovery Center: related services and use cases
# 3. Extracts killer features from top 5-8 competing products
# 4. Reads current project spec/code to understand our capabilities
# 5. Generates comparison table:
# | Feature | Us | Competitor A | Competitor B |
# | Multi-level approval | Y | Y | N |
# | AI absence forecast | N | N | Y <- killer |
# | Team calendar view | N | Y | Y <- gap |
# 6. Identifies our gaps and their killer features we're missing
# 7. Fetches existing GitLab issues — skips features already tracked
# 8. For each high-value gap not yet tracked: auto-creates enhancement issue
# npx spexso issue create --title "Enhancement: AI absence forecasting" \
# --label "type::enhancement,stage::opportunity,source::tinder"
# 9. Saves full research report to docs/research/tinder-{date}.md
# 10. Syncs research report to GitLab wiki under "Research" section
# 11. Prints summary: "Found 3 killer features. Created 2 issues, 1 skipped (duplicate)."Token budget warning
This command is intentionally expensive (~15-20K tokens due to web searches). It should be run infrequently — during planning cycles, before demos, or when exploring new product directions. Not during daily development. The research report is cached locally so it can be referenced without re-running.
/spexso-kickstart
Phase: Discovery | Creates: epic + milestone + sliced issues + MR
Kickstarts a new project or a large traject in an existing one. Where /spexso-brainstorm specs one issue, kickstart turns a whole traject into a marathon-ready backlog. It interviews the engineer breadth-first per .spexso/rules/interview.md (plus two kickstart branches: principles/anti-goals and roles/authorisation), proposes a split into vertical tracer-bullet slices with blocking edges, and only writes after the engineer approves the breakdown.
/spexso-kickstart Verlofbeheer voor SuccessFactors
# What happens:
# 1. Reads GLOSSARY.md, .spexso/constitution.md, the open backlog, and (existing project) the code
# 2. Pins the destination — what "done" means at the end of the traject
# 3. Breadth-first interview in frontier rounds (≤ 4 questions, recommended answer first)
# 4. Proposes slices: vertical, demoable, ≤ size L, minimal blocking edges — iterated to approval
# 5. Extra rounds for the first wave (slices without blockers), only for branches still open
# 6. Writes, in order:
# npx spexso milestone create "<name>" → spexso/<name>
# npx spexso issue create --label "type::epic" ... → epic, NO stage:: label
# npx spexso issue create --label "stage::spec,..." ... → first wave, full spec
# npx spexso issue create --label "stage::opportunity,..." → the rest, short body
# npx spexso link <blocker> <slice> --type blocks / <slice> <epic> --type relates
# npx spexso sync
# 7. Branch spexso/kickstart-<slug>: GLOSSARY.md + .spexso/constitution.md
# (validated by npx spexso constitution) → npx spexso pr create
# 8. Reports epic, milestone, first wave, MR — next: merge the MR, then
# /spexso-marathon --milestone "<name>"On a failed write it stops and reports what exists — no rollback, no resume (a blind re-run would duplicate issues). See Project of traject kickstarten.
/spexso-brainstorm
Phase: Discovery | Creates: GitLab issue
Refines a rough idea into a structured spec through interactive questioning. The interview follows the shared rulebook .spexso/rules/interview.md (tunable via interview.local.md): Claude looks up the facts itself (the issue, GLOSSARY.md, the code), then asks the frontier — the open decisions whose prerequisites are settled — in rounds of at most 4 questions, each with its recommended answer first. It guards the domain language against GLOSSARY.md and records new terms in the spec's ## Glossary section. Can also accept an existing issue ID to refine an issue already in the backlog.
# New idea — creates a new issue
/spexso-brainstorm Employee leave request extension for SuccessFactors
# Refine existing issue — updates the existing issue with a full spec
/spexso-brainstorm 45
# Load an approved design: a /spexso-prototype folder (or a Claude Design export)
/spexso-brainstorm 72 --design docs/design/issue-72
# What happens:
# 1. Reads the issue, GLOSSARY.md and the relevant code — never asks what the repo answers
# 2. Interviews in frontier rounds (≤ 4 questions, recommended answer first) until the
# coverage checklist is covered: users, SAP system, data model, integrations, UI,
# edge cases, out of scope, local startup, demo — then asks one confirmation question
# 3. Challenges terms that conflict with GLOSSARY.md, sharpens vague ones
# 4. Dependency check: reads the specs of related backlog issues and the code, and
# looks for proof in both directions (does a candidate create an entity/service/
# API/screen this spec needs that does not exist yet — or the reverse?). Only a
# proven blocker becomes a question, with its evidence and "blocks" recommended,
# all in one round; no proof, no question. Related issues are linked silently;
# shared files alone are no dependency (the marathon's fence handles those)
# 5. Proposes alternatives the developer may not have considered (as round options)
# 6. Generates a spec (lite or full based on estimated size)
# Full spec includes: ## Local development + ## Demo sections
# Dependencies section is filled in from step 4; ## Glossary holds the new terms
# 7. Writes the spec to a temp file, then runs:
# npx spexso issue create --title "..." --label "stage::spec,size::m" --description-file "$SPEC_FILE"
# (or updates the existing issue if an ID was provided: the reporter's text stays on
# top under "## Original report", the spec follows under "# Spec"; a re-brainstorm
# replaces only what is below "# Spec")
# 8. Creates the links (always from blocker to dependent):
# For each confirmed blocker: npx spexso link {blocker-iid} {dependent-iid} --type blocks
# (posted from the BLOCKER's side; GitLab materialises the inverse — avoids
# the is_blocked_by 404-but-success bug, gitlab#271168).
# On GitLab CE (no blocks links) this becomes a "Blocked by #n" line in the
# dependent's description + a relates_to link ("emulated": true).
# For each related issue (no question): npx spexso link {this-iid} {related-iid} --type relates.
# These links are read by /spexso-marathon (ready-set) and /spexso-start
# (blocker check), and cached in .spexso/index.json by npx spexso sync.
# 9. Issue moves to stage::spec
# 10. Updates .spexso/index.json/spexso-start <issue-id>
Phase: Setup | Creates: worktree + branch | Single issue only — for backlog runs use /spexso-marathon
Sets up an isolated workspace for a specific GitLab issue. Creates a git worktree, checks out a new branch, pulls the full spec from GitLab, and asks the developer which execution mode to use. Only accepts issues in stage::spec or later — issues still in stage::opportunity are blocked with a helpful message directing the user to complete the brainstorm step first.
Preflight check
/spexso-start performs a preflight plugin check — it recommends installing the sap-skills plugin when missing (advisory, never blocking).
/spexso-start 42 # ask which mode
/spexso-start 42 --yolo # autonomous within this issue (does NOT chain)
/spexso-start 42 --pilot # guided (default for most work)
/spexso-start 42 --copilot # every step needs approval
/spexso-start 42 --base journey/7 # branch worktree off journey/7 instead of origin/{targetBranch}
/spexso-start 42 --setup-only # claim issue + create worktree, then stop (no planning)
/spexso-start 42 --yolo --autopick # online runner: atomic branch claim (see Auto-pick)
# What happens:
# 1. Runs: npx spexso issue view 42 -> the ONLY tracker fetch: spec content,
# stage, assignee AND typed links (blockedBy) come from this one response
# 2. Checks stage label — blocks if stage::opportunity
# ("Issue #42 is in stage::opportunity. Run /spexso-brainstorm first.")
# 3. Checks for open blockers via the blockedBy entries from step 1:
# - --yolo + open blockers → hard abort (mirrors marathon picker behaviour)
# - pilot/copilot + open blockers → warn, list blockers, suggest /spexso-start <blocker-id>,
# ask "Continue anyway? (y/N)"
# 4. Determines size from labels (XS/S/M/L/XL)
# 5. Creates: git worktree add .spexso/worktrees/issue-42 -b spexso/issue-42 origin/{targetBranch}
# (after git fetch: never off the local HEAD, so an unpushed docs commit cannot ride along)
# (with --base <ref>: git worktree add ... -b spexso/issue-42 <ref>)
# then npm ci in the worktree when it has a package-lock.json: its own
# node_modules, so a missing module is a real failure, never "environmental"
# 6. Changes into the worktree directory
# 7. Runs: npx spexso stage 42 build (single-value stage transition)
# With --setup-only: stop here — issue claimed, worktree ready, no planning.
# 8. Asks (or reads from flag): "Which mode? yolo / pilot / copilot"
# 9. Proceeds to /spexso-plan automatically--yolo is per-issue, not a marathon
/spexso-start 42 --yolo runs only issue #42 autonomously and stops. To loop the whole backlog, use /spexso-marathon.
Orchestration flags
--base and --setup-only exist for orchestration layers built on top of spexso (e.g. parallel journey runners that fan a set of issues out over a shared integration branch). Both are no-ops when absent — the solo flow is unchanged. Their delivery-side counterpart is /spexso-finish --no-merge.
/spexso-marathon
Phase: Implementation | Loops Setup → Delivery | Dependency-aware ordering
Runs an autonomous loop across the GitLab backlog. Each iteration picks the next ready issue and delegates the build cycle (start → plan → build → review → MR creation) to a fresh spexso-issue-runner subagent — keeping the orchestrator's context flat regardless of backlog size. Integration happens in the orchestrator's merge train: /spexso-finish --train-merge rebases the issue onto the target branch and runs the full suite on the rebased code before merging. Stops on backlog empty, /spexso-stop, --max reached, deadlock, or 3 consecutive failed issues (circuit breaker).
With parallel.budget > 1 in .spexso/config.json (the parallel.budget / parallel.sizeScores / parallel.hotspots defaults live on the Storage page), the loop becomes wave-based: the window is filled in strict picker order up to a size-score budget (computed by npx spexso window — with the default scores, budget 6 fits three M issues, or one XL solo), a plan-wave of read-only planner-scouts computes each candidate issue's file footprint up front, a wave-cut (npx spexso waves, the same deterministic planner the build uses for tasks) groups only file-disjoint issues together, and the wave's runners are batch-spawned in one message. Overlapping issues are sequenced into later waves, never built concurrently — and the merge train stays strictly serial, so merge order remains deterministic. The budget balances load, not duration: a mixed wave still waits for its slowest runner before the train departs.
The picker is dependency-aware: an issue is ready only when none of its blockers is still open. A blocker is resolved once it is closed or — by default — merged (stage::ship / stage::operate: its code is on the target branch, even while a tester still holds the issue open). Set "blockerResolvedAt": "closed" in .spexso/config.json to wait for the close instead. Blockers come from native blocks links and from Blocked by #n lines in the issue description — the form GitLab CE (no blocks links, a paid tier) and GitHub use. Within the ready-set, ordering is priority desc, then created_at asc — size as a tiebreaker has been removed.
Two flags scope the run instead of the whole backlog. --milestone limits the candidates to one milestone (GitLab/GitHub milestone title, Azure iteration path) — the bare name of a marathon also matches, so --milestone "Escalations" finds issues in spexso/Escalations — and keeps the picker order. --issues 45,47,46 runs exactly those issues and makes the list the sort key — blockers still gate, so a listed issue waits for its open blocker (a later-listed blocker runs first; a blocker outside the list ends in the deadlock summary). Listed issues that cannot be queued show up under Not queued with their reason. Both flags combine with each other and with --size, --max, --preview and parallel.budget; re-running the same command after an interruption picks up exactly the remainder, since processed issues leave stage::spec.
/spexso-marathon # auto-pick, no limit
/spexso-marathon 47 # start with #47, then auto-pick
/spexso-marathon --issues 45,47,46 # exactly these, in this order (blockers still gate), then stop
/spexso-marathon --milestone "Escalations" # only this marathon (spexso/Escalations), picker order
/spexso-marathon --max 5 # stop after 5 attempts (any processed outcome counts)
/spexso-marathon --size xs,s # optional size filter (applied before the window fills — also constrains waves)
/spexso-marathon --preview # print the computed queue order and exit (read-only)
/spexso-marathon --preview --deep # + scout the first window, print the real wave-cut
/spexso-marathon --autopick # online runner: only auto-pick issues, MRs queued for auto-merge (see Auto-pick)
# What happens:
# 1. npx spexso sync
# 2. Pre-flight summary: Ready / Blocked / Not queued counts
# 3. If --preview: simulate the full picker run, print the ordered queue with
# per-issue rationale, exit without locking anything.
# With --deep: also scout the first window (budget-based fill, same
# rules as the loop) and print the wave-cut of that window.
# Costs planner tokens; the plan files land in .spexso/plans/ with a
# base-SHA + footprint frontmatter and are REUSED by the next real run
# (staleness-checked: footprint vs git diff since base, via npx spexso fence).
# Still read-only in the tracker: no notes, no locks, no labels.
# 4. Loop (per wave — with parallel.budget 1, a wave = one issue;
# npx spexso breaker reset and npx spexso marathon-run start run once
# before the first wave):
# a. Check .spexso/stop file → graceful exit (between waves, never mid-wave)
# b. Check needs::conflict-resolution labels → warn but continue
# c. Window: picked issues + budget/sizeScores through npx spexso window
# (never hand-computed). The first pick always enters (even over
# budget → solo); the window closes at the first issue that does not
# fit — never search past it for a smaller filler.
# --max counts ATTEMPTS: remaining = --max minus processed summaries
# (completed, conflict, skipped, failed all count) — a predictable
# budget for an overnight run. Window issues are mutually distinct
# and pre-selected, which is what makes the wave's concurrent
# /spexso-start claims race-free.
# d. If ready-set empty AND blocked-set non-empty → print deadlock summary, exit with summary
# e. Plan-wave (only for multi-issue windows): batch-spawn read-only
# spexso-planner scouts, one per issue — each writes its plan to
# .spexso/plans/issue-{id}.md and returns only the file footprint.
# Pre-plans are reused across waves unless the merge train touched
# their footprint (then: re-scout).
# A scout self-assesses the spec before planning and may DECLINE a
# clearly unplannable issue (no testable acceptance criteria /
# ambiguous scope) with plannable:false + reason — the issue gets
# needs::attention + a note and is excluded for the rest of the run.
# Neutral for the breaker and --max: it never became an attempt.
# Single-issue windows have no scout (no self-assessment) — the
# sequential path relies on the 3-strike rail instead.
# f. Wave-cut (only for multi-issue windows): footprints through npx spexso waves
# ({tasks, hotspots} form) → only file-disjoint issues share a wave;
# overlappers go to later waves. parallel.hotspots collide across
# paths (any two package.json touches never share a wave).
# g. Batch-spawn Task(subagent_type=spexso-issue-runner, ...) — ALL in ONE
# message: each runner internally runs /spexso-start, /spexso-plan
# (--pre-plan when scouted), /spexso-build, /spexso-review,
# /spexso-finish --train in an isolated context —
# MR created, NOTHING merged, worktree kept.
# Runner writes one JSON line to .spexso/marathon-log/{id}.jsonl
# via npx spexso marathon-log start/write (clock-stamped times).
# Runner returns ONLY a JSON summary string back to the orchestrator
# (status ready_to_merge, with mr_id + changed_files — the latter
# computed mechanically via npx spexso changed-files in the worktree).
# h. Merge train — the orchestrator integrates, one issue at a time, in
# wave order. Fence-check first (npx spexso fence): the runner's
# ACTUAL changed files vs what this train already merged (+ hotspots);
# an issue that left its predicted footprint is deferred to the end
# of the train once, then attempted anyway (rebase gate = backstop).
# Then: /spexso-finish --train-merge {id} --mr {mr_id}
# rebase onto targetBranch → full suite, then the MR pipeline, on the
# REBASED code → merge.
# merged → "completed" | conflict/degraded → "completed_with_conflict"
# gate_failed (red once repair rounds stop making progress, max 5)
# → "failed", needs::attention, not merged
# Per processed issue: npx spexso marathon-log fold {id} --status <final>.
# i. Orchestrator prints one line per issue, then feeds the circuit breaker:
# npx spexso breaker <event> — state in .spexso/marathon-state.json
# "completed" → reset to 0
# "failed" → +1, label issue needs::attention, post note
# "completed_with_conflict" (→ conflict) / "skipped" → neutral
# j. breaker exits non-zero at 3 consecutive failures → circuit breaker, exit.
# A multi-issue wave where EVERY runner failed → immediate exit
# (stop reason wave_failed — that is systemic, not bad luck).
# 5. Final summary: completed, MRs, needs::attention, conflicts,
# blocked-at-exit, stop reason; marathon-run finish --outcome "<stop reason>". Detail: .spexso/marathon-log.jsonlDependency links come from /spexso-brainstorm
The marathon reads blocking links — native blocks links where the tracker has them, Blocked by #n description lines where it does not (GitLab CE, GitHub). /spexso-brainstorm writes them during the dependency-check step of the interview; npx spexso link --type blocks on GitLab CE records the line on the dependent issue plus a relates_to link, and reports "emulated": true. Manually-created issues without links fall back to priority + created_at ordering — which means: no blockers, no special order beyond priority.
Crash recovery
A run that dies mid-train leaves its wave issues at stage::review with an open MR and a kept worktree. Recover each with /spexso-finish --train-merge {id} --mr {mr_id}; clean leftover worktrees with npx spexso worktrees reap.
Hard cost rail for overnight runs
--max bounds attempts, not spend. Pair it with Claude Code's own rails — --max-budget-usd and subagent spawn caps — as a hard ceiling on what a run can cost.
/spexso-stop
Phase: Utility | Signals: graceful marathon stop
Sends a graceful stop signal to a running /spexso-marathon. The marathon finishes the current wave completely (all tasks, review, MRs, merge train, cleanup — with parallel.budget: 1 a wave is exactly one issue) before exiting — it never interrupts a task mid-execution, only checks between waves.
/spexso-stop
# What happens:
# 1. Writes .spexso/stop (a UTC timestamp)
# 2. Confirms:
# "⏸ Stop signal sent. Yolo will finish the current issue and exit."
# (or "⏸ Stop signal created, but no active yolo detected." if no worktrees exist)
# Marathon side (checked between waves — after the wave's merge train,
# before picking the next window):
# 1. Deletes .spexso/stop
# 2. Prints the marathon summary
# 3. Exits cleanlyAlternative ways to stop
From another terminal: npx spexso stop, or touch .spexso/stop directly. Hard stop: Ctrl+C — may leave a worktree in a dirty state, use as a last resort.
/spexso-plan
Phase: Planning | Creates: task list
Breaks the spec into bite-sized implementation tasks. Uses the spexso-planner subagent to decompose the work. In pilot and copilot modes, presents the plan for human approval. In yolo mode, proceeds automatically. With --pre-plan {path} (set by the marathon when its plan-wave already scouted the issue) the planner is not spawned again — the plan file is used as-is, and everything after decomposition (size checkpoint, ADR capture, GitLab note) runs unchanged.
/spexso-plan
# What happens:
# 1. Spawns spexso-planner subagent
# 2. Planner reads: spec content + CLAUDE.md + existing code structure
# 3. Outputs ordered task list with:
# - Task ID, description, estimated tokens
# - Files to create/modify
# - Dependencies between tasks
# - Test requirements per task
# - UI: per UI task, the control per data element + header content
# (ux.md §5b) — the contract the builder builds and the reviewer checks
# - Architecture Decisions (ADRs) for any significant choices it made
# 3b. Consistency check (spec<->plan): every EARS clause in exactly one task's
# Covers:, no files outside the shown project structure, dependencies
# reference existing tasks, no file shared between independent tasks
# 4. In pilot/copilot: asks for approval. In yolo: auto-approved.
# 5. Captures proposed ADRs to docs/adr/ (see below)
# 6. Posts plan as comment on GitLab issue via npx spexso issue note,
# and keeps it as .spexso/plans/issue-{id}.md (the review reads its UI: lines)Consistency check (spec↔plan). Before approval the orchestrator mechanically verifies the plan text against the spec: every EARS clause appears in exactly one task's Covers: (none missing, none doubled), no task references files outside the project structure the planner was shown, every dependency names an existing task, and no two independent tasks share a file (planner rule 9b — npx spexso waves would fail on this at build time; catching it here saves a build round-trip). It is an orchestrator checklist against the plan text, not a subagent. Violations in yolo: re-prompt the planner once with the specific violations, and if still violated, note them on GitLab and proceed flagged. Pilot/copilot: violations are surfaced to the developer. Ported from spec-kit's /analyze, folded into the plan stage rather than shipped as a new command.
Automatic decision capture. The planner surfaces architecturally significant decisions (a tech/service choice, a cross-cutting pattern, a constraining data-model shape, a non-obvious trade-off) as ### ADR: blocks. The command writes each to docs/adr/ADR-NNN-*.md:
- yolo — auto-drafted with
Status: Proposed(no human is watching; capture now, a developer accepts/supersedes later during manual QA). Never blocks the marathon. - pilot / copilot — each proposed ADR is shown; the developer accepts (
Status: Accepted), edits, or skips.
This closes the gap where decisions made during autonomous runs were never recorded. ADRs are versioned in the repo (reviewed in the MR) and mirrored to the GitLab wiki via /spexso-docs sync. Routine/reversible choices are not turned into ADRs — they stay as lightweight notes in the plan and the GitLab issue thread.
/spexso-build
Phase: Implementation | Creates: code + tests
Executes the plan in dependency waves using strict TDD: npx spexso waves groups the plan's tasks so that dependencies land in earlier waves and tasks inside one wave never share a file. Per wave, all testers are batch-spawned in one message (parallel RED, parallel.red default on); builders batch-spawn the same way (parallel.green, default on), while GREEN verification and commits run per task in wave order. Behavior varies by execution mode.
/spexso-build
# Once, before the first task:
# 0. Plan tasks as JSON -> npx spexso waves -> {"waves": [["1"],["2","3"],...]}
# Wave with >1 task + parallel.red: spawn ALL its testers in ONE message
# (batch attempts: npx spexso attempt {id} red --batch — ceiling counts,
# budget clock waits for the task's own work)
# What happens per task:
# 1. npx spexso attempt {id} red -> code-enforced counter (ceiling 2; non-zero exit = escalate)
# then spawn spexso-tester -> writes failing tests based on spec + task
# 2. Verify tests fail (red phase). Faithful tests that PASS = terminal state
# "already implemented": tests kept as regression coverage, builder skipped
# 3. npx spexso attempt {id} green -> counted before EVERY builder dispatch (ceiling 3)
# then spawn spexso-builder -> writes minimum code to pass tests (one run per dispatch)
# 4. Run tests -> verify green. Targeted green + only falseFailPatterns failures =
# terminal state "environment false-fail": proceed, CI arbitrates
# 5. Refactor if needed (still green)
# 6. Git commit: "feat(spexso): [task-id] description" (staging the TASK's files,
# never -A: a sibling's parallel-RED tests are already on disk) + npx spexso attempt reset {id}
# 7. In yolo: move to next task. In pilot: show result, ask continue.
# In copilot: ask approval after each sub-step.
# 8. After all tasks: auto-trigger /spexso-review/spexso-review
Phase: Quality | Creates: review report
Runs the spexso-reviewer subagent against all code changed in this worktree. Reports issues by severity. Critical and High issues are auto-rewritten. Low issues are commented only.
/spexso-review
/spexso-review --converge # + post-review drift check against the spec's acceptance criteria
# What happens:
# 1. Spawns spexso-reviewer subagent
# 2. Reviews: git diff main...HEAD (all changes in this worktree)
# 3. Checks against: spec requirements, CLAUDE.md patterns, test coverage
# 4. Outputs severity-tagged issues:
# CRITICAL: Security, data loss, broken API contracts -> AUTO-REWRITE
# HIGH: Missing error handling, spec deviation, no tests -> AUTO-REWRITE
# LOW: Style, naming, minor improvements -> COMMENT ONLY
# 5. For auto-rewrite items: applies fix, re-runs the targeted tests for the
# fixed files (full suite stays with /spexso-finish + CI), commits
# 6. Presents final review summary to developer
# 7. Posts review summary as comment on GitLab issue
# 8. yolo (solo run): continues straight into /spexso-finish in the same turn;
# pilot/copilot stop here — the merge is the developer's call--converge (opt-in, brownfield drift). After the normal review, the shipped codebase — not just the diff — is compared against the spec's acceptance criteria, and every criterion the current code does not meet becomes a candidate follow-up issue (title + one-line rationale). In yolo they are created via npx spexso issue create with stage::opportunity and a [converge #{id}] marker in the body; pilot/copilot print the list for the developer. Default off — converge costs tokens and is a deliberate act. Ported from spec-kit's /converge, folded into the review stage rather than shipped as a new command.
Rulebook lessons. When the reviewer spots a systemic lesson that passes its admission test (at most one per review), pilot/copilot ask to apply or reject it on the spot; yolo records it in the project's [rulebook-inbox] issue. When the inbox holds lessons ready for a decision, the review summary ends with 📥 {n} rulebook lesson(s) ready (#{inbox}) → /spexso-rulebook. See Rulebook promotion.
/spexso-rulebook
Phase: Quality (rulebook) | Creates: merge request with rule changes
Works through the project's rulebook inbox — the [rulebook-inbox] issue where /spexso-review collects candidate lessons — and turns the approved ones into rules in .spexso/rules/{domain}.local.md.
/spexso-rulebook # lessons under ## Ready (seen 2× or more) + entries ticked in GitLab
/spexso-rulebook --all # also the candidates seen only once
# What happens:
# 1. Reads the inbox: ready, ticked, candidates, rejected
# One-time: open [rulebook-lesson] issues from earlier versions are sorted
# (inbox / drop / [spexso]) with the reviewer's admission test, shown as a
# plan, and — after you confirm — merged into the inbox and closed with a note
# 2. Asks: one by one, approve all ready lessons at once, or cancel
# (entries ticked in GitLab are already approved and are applied without asking)
# 3. One by one: apply / edit / reject / skip per lesson, shown as a concrete diff;
# [spexso] lessons (gaps in Spexso itself) are reported with /spexso-feedback instead
# 4. Applies the approved lessons on a fresh branch spexso/rulebook-<stamp>,
# one commit per lesson, pushes it and opens a merge request — never merges it
# 5. Updates the inbox: applied/reported entries removed, rejected ones kept under
# ## Rejected so /spexso-review never proposes them again
# 6. Offers to send applied [stack] lessons upstream with /spexso-feedbackThe same decisions can be made by hand in GitLab: tick an entry to approve it (the next /spexso-rulebook applies it), move it under ## Rejected to reject it, or edit its text before ticking. Deleting an entry instead of moving it means the lesson can come back. See Rulebook promotion and the scenario Rulebook-lessen goedkeuren.
/spexso-finish
Phase: Delivery | Destructive: removes worktree
The one-command ship. Pushes the branch, creates a merge request in GitLab, auto-merges it into the configured target branch, updates the issue stage, posts a manual test checklist, and cleans up the worktree.
/spexso-finish # full flow: MR + auto-merge + checklist + cleanup
/spexso-finish --no-merge # push + create MR, then stop: stage::review, worktree kept
/spexso-finish --train # marathon runner half: like --no-merge, but test gate deferred
/spexso-finish --train-merge 42 --mr 7 # marathon orchestrator half: rebase -> full suite -> merge
/spexso-finish --train-merge 42 --mr 7 --autopick # online runner: ownership re-check, then queue for auto-merge (see Auto-pick)
# What happens:
# 1. Runs final test suite + configured staticChecks — aborts if either fails
# 2. Reads targetBranch from .spexso/config.json (falls back to 'main')
# Refreshes the debt ledger, then merges the spec's ## Glossary section into
# GLOSSARY.md (commit "docs(glossary): …") — also with --train
# Then, when the config has releaseNotes, writes release-notes/unreleased/42.md
# (release-note fragment, commit "docs(release-notes): #42") — also with --train
# 3. git push origin spexso/issue-42
# 4. npx spexso pr create \
# --title "[commit-type]: [spec title] (closes #42)" \
# --description "Auto-generated by Spexso. Review summary: ..." \
# --label "stage::review,ai::ai-assisted" \
# --source-branch "spexso/issue-42" \
# --target-branch "${targetBranch}"
# The commit type derives from the issue's type:: label (bug→fix, tech-debt→refactor,
# maintenance→chore, otherwise feat) — the squash-merged MR title becomes the commit
# on main and feeds commit-and-tag-version in projects with the release flow.
# -- with --no-merge: stop here. npx spexso stage 42 review; MR stays open for
# human review, worktree and branch are kept. Steps 5-13 are skipped.
# -- with --train: same stop, but step 1 (test gate) was also skipped — it runs
# later in --train-merge, AFTER the rebase. Hand-off is to the marathon.
# -- with --train-merge {id} --mr {mr_id}: rebase worktree onto targetBranch,
# npm ci in the worktree, run the FULL suite + staticChecks on the rebased
# code, push and wait for the MR pipeline (npx spexso pr ci --wait). Red →
# builder repair rounds with every failed job's log, while each round makes
# progress (max 5); a type error only in a test file gets a tester round
# (no assertion may change). Then merge the tested SHA + steps 6-13.
# Outcomes: merged / conflict / gate_failed (still red after the repairs —
# not merged, needs::attention) / degraded. See the Finish Flow page.
# 5. npx spexso pr merge {MR_ID} --squash --remove-source-branch
# On conflict: rebase onto targetBranch + force-push + retry merge once
# If rebase fails: post MR comment, apply needs::conflict-resolution, skip merge
# 6. git pull origin {targetBranch} <- sync local main with squash commit
# 7. npx spexso stage 42 ship && npx spexso issue update 42 --label "needs::manual-test"
# npx spexso handoff 42 (test hand-off: assigns a tester when configured, else no-op;
# with handoff.on = "deploy" it only decides — CI runs `spexso handoff --deployed`)
# 8. npx spexso issue note 42 --message "## ✅ Manual Test Checklist\n- [ ] {criterion}..."
# 9. If spec has ## Demo section:
# npx spexso issue note 42 --message "## 🎬 Demo Scenario\n{demo steps from spec}"
# 10. cd back to main worktree, update CHANGELOG, git push origin {targetBranch}
# 11. git worktree remove .spexso/worktrees/issue-42
# 12. Refreshes .spexso/index.json
# 13. Prints: "MR !{id} merged. Issue #42 -> stage::ship. Test checklist + demo posted."/spexso-sync
Phase: Utility
Refreshes the local .spexso/index.json from GitLab. Can be run manually or is auto-triggered by other commands.
/spexso-sync
# What happens:
# 1. npx spexso issue list (open issues with stage::* labels, normalized JSON)
# 2. Parses response into compact index format
# 3. Writes .spexso/index.json
# 4. Prints summary: "Synced 15 active issues. 2 in opportunity, 3 in spec, 7 in build, 2 in review."/spexso-docs
Phase: Utility | Syncs to: GitLab wiki
Creates Architecture Decision Records, syncs documentation to the GitLab wiki, and manages the changelog.
# Create a new Architecture Decision Record
/spexso-docs adr Switch from REST to GraphQL for the dashboard API
# -> Creates docs/adr/ADR-003-switch-to-graphql.md with structured template
# -> Pushes to GitLab wiki under "Architecture Decisions" section
# Sync all docs to wiki
/spexso-docs sync
# -> Pushes all docs/adr/*.md to wiki
# -> Pushes all docs/research/*.md (from /spexso-tinder) to wiki
# Update changelog (normally auto-done by /spexso-finish)
/spexso-docs changelog Manual entry: migrated auth to XSUAA v3/spexso-demo <issue-id>
Phase: Demo / QA | Requires: Playwright MCP server
Runs an issue's ## Demo > Scenario steps in a real headed browser as a developer smoke test. Probes or starts the local app via spexso demo-env, reads the scenario from the issue, drives it live, and on failure captures artifacts + posts tracker feedback. On success, offers to save the run as tests/demo/issue-<id>.spec.ts. See Demo Runner for the full flow, config, and prerequisites.
/spexso-demo 42 # target from config (demo.localUrl, else demo.remoteUrl)
/spexso-demo 42 --remote # against the deployed app (demo.remoteUrl)
/spexso-demo 42 --remote https://other-dev.example.com # one-off url
/spexso-demo 42 --local # force the local app--design <path>. Before the interview, brainstorm reads the design. The standard input is a prototype folder from /spexso-prototype (docs/design/issue-{id}/): it takes the exact control names from the views and fragments (freestyle) or the annotations from spike.diff (Fiori Elements), the PNGs from .spexso/demo-artifacts/issue-{id}/design/, and does not ask again what the developer decided during the prototype rounds; once the spec is written it commits only that folder to main with [skip ci] (on main only, after a fast-forward pull; a rejected push stays local). A Claude Design export (zip, or HTML + one PNG per artboard) still works, but its artboards are look-alike HTML, not UI5, so brainstorm maps every region to what builds it in Fiori: a UI5 control for freestyle, an annotation or building block for Fiori Elements (ux.md §5b and Part A, confirmed with the Fiori MCP). What Fiori cannot render as drawn becomes an interview question: adapt the design to the nearest Fiori pattern (recommended), build it freestyle, or drop it, never a hidden CSS imitation. The mapping fills the spec's UI table, so it becomes the UI: contract the planner, builder and reviewer work from. A ## Design section gets the uploaded PNGs and the source link; "the design is the target look, the UI table is the contract". On a redesign issue it keeps the feedback and current screenshots under ## Redesign input and lifts the redesign label, so /spexso-start and the factory can pick it up.
/spexso-redesign <issue-id>
Phase: Quality (UX) | Creates: a redesign issue | Requires: Playwright MCP for the screenshots
Requests a redesign of a screen an issue already built. It reads the issue's spec and discussion (npx spexso issue comments), asks once for the users' feedback, walks the ## Demo scenario on the app (spexso demo-env, as /spexso-demo) and screenshots every screen. Then it files redesign: <screen> with type::enhancement, stage::opportunity and the redesign label, in the original's milestone, linked to it. The issue describes what the screen must do (goals, data and its shape, actions) rather than how it looks today, plus the user feedback, the current screenshots, the Fiori constraints and a prototype brief: per screen the user's goal, the data shape and its entities, the states and dialogs to show and the proposed UI5 control (or Fiori Elements annotation) per region.
/spexso-redesign 59 # app target from the demo config
/spexso-redesign 59 --remote # screenshot the deployed app
# Then:
/spexso-prototype <new-id> # real UI5 in docs/design/issue-<new-id>/
/spexso-brainstorm <new-id> --design docs/design/issue-<new-id> # spec + UI contract; lifts `redesign`The redesign label is the gate: the marathon, the factory and auto-pick skip an issue that carries it, and stage::opportunity keeps it out of every picker anyway until the design is loaded. See the scenario Een scherm herontwerpen.
/spexso-prototype <issue-id>
Phase: Quality (UX) | Writes: docs/design/issue-{id}/ | Requires: Playwright MCP (Fiori Elements route); headless Edge/Chrome is enough for freestyle
Builds the design for an issue from real UI5, because a drawn mock-up hides how the controls behave (a TreeTable indents in its first column, a ColumnLayout takes no HBox, a StepInput groups thousands) and the Claude Design canvas cannot load UI5 at all. Input is the issue's ## Prototype brief (from /spexso-redesign) or its UI table. The route follows the app's manifest.json:
- Freestyle — a mock app in
docs/design/issue-{id}/:index.html(UI5 fromui5.sap.com, Horizon, languageen),app.jsthat picks the screen from?screen=N§ion=…&open=…, XML views and fragments, anddata.json, a snapshot of the seed CSVs. Served withhttp-server, so it runs without a backend and the screenshots are reproducible. - Fiori Elements (
sap.fe.templates.*/sap.fe.core.fpm) — an annotation spike on the real app in a throwaway worktree with its ownnpm ci: onlyannotations.cdsand manifest settings change (Fiori MCP where it covers it), the app runs withcds serve --with-mocks --in-memoryand dummy auth, and what FE cannot render as briefed (ux.md§3b) becomes a finding with a decision. The folder keepsspike.diffand the README; the worktree is removed.
Every screen is shot at 1440×900 into .spexso/demo-artifacts/issue-{id}/design/ (not committed); README.md maps screen → PNG → source and lists the findings. While it runs, the issue carries the redesign label (added when missing, e.g. on a freshly brainstormed issue in stage::spec), so the factory, the marathon and auto-pick leave it alone; brainstorm lifts it again. It refuses an issue in stage::build/review. It iterates with the developer until they approve, then hands over to /spexso-brainstorm {id} --design docs/design/issue-{id}. It never commits and never touches the app in the main checkout. The pitfalls it guards against live in the rulebook prototype.md.
/spexso-autotest <issue-id>
Phase: Demo / QA | Run by: the test server | Requires: Playwright MCP (headless)
The browser half of the test server. It tests one shipped issue against its latest ✅ Manual Test Checklist and 🎬 Demo Scenario, in a headless browser, logged in as a CAP mock user, on the app the server started from the latest main. Items a browser cannot check (e.g. "a test pins X") are marked not-browser-checkable. It writes result.json (verdict pass / fail / blocked / skipped, one row per checklist item), plus failure.png and a spec-ready bug.md on a fail. It does not stop at the first failure: every new failure of the issue goes into that one bug.md. A failure that a known bug in the milestone (listed in issue.md) already describes goes into duplicateOf instead, so the server links and waits rather than filing it twice. It never writes to the tracker: the server applies the labels, files the bug and posts the comments. A failure caused by the test itself (outdated scenario, drifted selector, unreset data, login) is blocked, not fail, so no bug chases a ghost.
/spexso-autotest 59 --base-url http://localhost:4004 --out .spexso/factory/autotest/59/spexso-architecture [area]
Phase: Quality (codebase health) | Creates: type::tech-debt issues + an ADR MR
Surveys the codebase for deepening opportunities — shallow modules, concepts scattered over many small modules, coupling leaking across seams, code hard to test through its interface — and presents them as a visual HTML report in the OS temp dir. The engineer then triages every candidate: Issue (a type::tech-debt issue in stage::opportunity), Never (an ADR in docs/adr/ so later runs don't suggest it again) or Later (nothing recorded). It changes no code. Vocabulary and principles come from the architecture.md rulebook. Credit: improve-codebase-architecture + codebase-design from mattpocock/skills (MIT).
/spexso-architecture # hot spots: git churn + .spexso/debt.md + parallel.hotspots
/spexso-architecture srv/leave # one area
# What happens:
# 1. Picks the areas (named, or hot spots) and reads architecture.md, GLOSSARY.md,
# docs/adr/ and the open type::tech-debt issues
# 2. An Explore subagent walks the areas and notes friction (incl. CAP/UI5 shallow patterns);
# the deletion test separates pass-throughs from modules earning their keep
# 3. Dedupes against open tech-debt issues and ADRs (an ADR conflict is shown, flagged)
# 4. Writes architecture-review-<timestamp>.html (Tailwind + Mermaid): per candidate files,
# before/after diagram, problem, solution, wins, strength badge; a top recommendation
# 5. Triage per candidate: Issue / Never (+ reason) / Later
# 6. Issue → npx spexso issue create --label "type::tech-debt,stage::opportunity" ...
# Never → branch spexso/architecture-<date> + docs/adr/ADR-<n>-*.md → npx spexso pr create
# 7. npx spexso sync + report (html path, issue ids, ADR MR, how many on Later)Refine a resulting issue with /spexso-brainstorm {id} — designing the deepened module's interface happens there. See the architecture review scenario.
/spexso-wizard <procedure>
Phase: Operations | Creates: scripts/wizards/<name>.mjs (+ _lib.mjs)
Generates an interactive Node wizard for a manual BTP/SaaS procedure — onboarding a customer tenant, registering a service broker, setting up an environment with its CI/CD variables, a one-off migration or cutover. Repeatable wizards are committed to scripts/wizards/ and re-run per customer or environment; throwaway ones go to the OS temp dir. A wizard needs only Node and the repo to run — consultants without spexso can run it too. Idea credit: the wizard skill of mattpocock/skills (MIT).
/spexso-wizard klant onboarden
# What happens:
# 1. Reads mta.yaml, xs-security.json, .gitlab-ci.yml, .env.example, default-env.json and the
# btp-services / tenant-requirements registries — then proposes the stages and, per value,
# where it comes from, where it goes (BTP, CI variable, .env/default-env.json) and whether it
# is secret; repeatable or throwaway
# 2. Maps every stage twice: the btp/cf/glab command AND the cockpit click path — verified
# against the SAP docs, or marked "verify" in the script
# 3. Copies .spexso/templates/wizard-lib.mjs to scripts/wizards/_lib.mjs (if missing/outdated)
# and writes scripts/wizards/klant-onboarden.mjs
# 4. node --check + a static trace (every CI variable name matches .gitlab-ci.yml) — never
# runs the wizard itself; repeatable → commit + a line under "## Wizards" in the README
node scripts/wizards/klant-onboarden.mjs # the human runs itAt run time the wizard executes btp/cf/glab commands after confirmation when the CLI is installed and logged in, and otherwise prints the exact cockpit path and waits. Irreversible actions always ask y/N (default No). Secret values are entered hidden, redacted from every printed command, and the closing summary lists names only. See Templates → wizard-lib.mjs and the wizard scenario.
Auto-pick (CLI)
Phase: Utility | Off by default | Design: Auto-pick (online runner)
npx spexso autopick # runner entry point: sweep, then /spexso-marathon --autopick if work is ready
npx spexso autopick enable # write autopick.enabled to .spexso/config.json (disable to undo)
npx spexso autopick eligible 42 # rubric verdict + reasons for one issue, as JSON
npx spexso triage # propose the auto-pick label on eligible stage::spec issues, y/n per issueautopick is what the runner project calls; it exits without starting Claude when auto-pick is disabled or nothing is ready. The --autopick flags on /spexso-marathon, /spexso-start and /spexso-finish --train-merge above are set by the runner, not by hand. See Auto-pick for the rubric, the sweep and the bot/developer rules.
Factory (CLI)
Phase: Utility | Design: Factory
npx spexso factory start --milestone "<name>" [--max-iterations 50] [--type cx43] # ensure the Hetzner server, set up the project, start the loop
npx spexso factory status | logs | stop [--now] # follow or stop it
npx spexso factory run --milestone "<name>" # the loop itself — run by the server's systemd unitThe loop runs /spexso-marathon --milestone <name> --max 1 once per iteration, each in a fresh claude -p context. See Factory for setup, exit reasons, the sweep and self-deletion.
Release notes (CLI)
Phase: Utility | Off without releaseNotes in the config | Scenario: Release notes per ticket
npx spexso release-notes [version] [--publish] [--tag <tag>]spexso release-notes [version] [--publish] [--tag <tag>] — collects release-notes/unreleased/*.md into release-notes/{version}.md (version from package.json by default), moves the fragments to release-notes/{version}/ and commits. --publish sets the text as the GitLab release of the tag (v{version} by default) and creates that release when needed; other platforms: unsupported. Off without releaseNotes in the config.
Provider-Agnostic Façade Verbs
The prose layer (src/skills/*/SKILL.md, src/agents/*.md — rendered to dist/) never calls glab, gh, or az directly (a CI grep gate enforces this). Every platform interaction goes through spexso <verb>, which the façade (lib/facade.js) dispatches to the active tracker or code adapter. The verb surface mirrors glab's nouns, sub-verbs, and long-flag names 1:1, so glab X … swaps for npx spexso X … mechanically. All three adapters (GitLab, GitHub, Azure DevOps) implement the full verb surface; platform gaps (e.g. upload on GitHub, pr diff on Azure) return an explicit unsupported result instead of failing obscurely. See providers for the per-platform command mapping.
Tracker verbs (issue management)
| Verb | Adapter method | Notes |
|---|---|---|
spexso issue list [--label X] [--author U] [--search Q] [--milestone M] [--state open|closed|all] [--stage --assignee] | listIssues | Returns normalized Issue[]; open is the default state. Link-lazy: the link buckets are empty (fetching links costs one API round-trip per issue — the N+1 fix); use issue view or link list when blockers matter |
spexso issue view <id> | getIssue | Returns normalized Issue |
spexso issue comments <id> | listComments | The issue's discussion, oldest first (author, body, createdAt); used by /spexso-redesign |
spexso issue create --title <t> [--description <d> | --description-file <path>] [--label …] [--assignee --milestone --type --priority --size] [--repo <path>] | createIssue | Returns {ok, id, url}; --label is repeatable or comma-separated; --body is an alias of --description; --description-file reads the body from disk (use it for anything multiline — an inline --description breaks on Windows); on GitLab a body over 8,000 characters never goes on the glab command line but through a temp file (glab api … --field description=@file), so a large spec cannot hit Windows' ~32K command-line limit (ENAMETOOLONG) — the same for comment/issue note; it is mutually exclusive with --description; --repo files cross-repo |
spexso issue update <id> [--title --description <d> | --description-file <path> --label --unlabel --assignee --unassign --milestone <title> | --no-milestone] | updateIssue | Returns {ok, id}; same --description-file semantics as issue create — a long body is written first, so when it fails no label has changed and the command exits non-zero; --milestone takes the full title (like issue create), --no-milestone removes it — not supported on Azure |
spexso milestone list [--all] | listMilestones | Marathons: the open spexso/ milestones as [{name, title, due, state}] (--all adds closed). Other milestones are never returned. Azure: unsupported |
spexso milestone create "<name>" [--due YYYY-MM-DD] | createMilestone | Creates spexso/<name>; refuses a title that already exists. <name> may already carry the prefix |
spexso milestone close "<name>" | closeMilestone | Closes spexso/<name>; it disappears from the index after the next spexso sync |
spexso issue close <id> / spexso issue reopen <id> | closeIssue / reopenIssue | Uses glab issue close/reopen on GitLab |
spexso issue note <id> --message <body> or --message-file <path> | comment | Alias of spexso comment |
spexso issue delete <id> | deleteIssue | Destructive; exposed but not used by flows |
spexso comment <id> --message <body> or --message-file <path> | comment | Post a note/comment on an issue |
spexso label list [--repo <path>] / spexso label create --name --color --description | listLabels / createLabel | label create is idempotent |
spexso link <from> <to> --type blocks|relates|is_blocked_by | createLink | Typed dependency link (GitLab posts blocks from the blocker's side; on GitLab CE — no blocks links — it writes Blocked by #from on the dependent + a relates_to link and returns emulated: true) |
spexso link list <id> | getLinks | Returns {blockedBy, blocks, relatesTo} |
spexso bundle members <lead> / bundle join <id> --lead <lead> / bundle drop <id> --lead <lead> --reason "…" | listIssues, updateIssue, setStage, comment | Bundles: the members, lead first (derived from the companions' hidden marker); lock a companion (assignee, stage::build, marker); hand one back (unassigned, stage::spec, marker removed, a note) |
spexso board sync | syncBoards | Provision boards/lists idempotently |
spexso wiki push <title> --file <path> | pushWiki | Upserts the wiki page via the REST API |
spexso auth status | authStatus | Platform-agnostic auth preflight |
spexso api <endpoint> [--method --field --raw-field --form --header --paginate --hostname] | api | Escape hatch: raw platform REST call |
spexso upload <file> [--repo <path>] | upload | Multipart file upload; returns a markdown link |
spexso whoami [--output json] | whoami / getUser | User handle, or {username, name} with --output json |
The spexso stage <id> <stage> and spexso commit-ref <id> verbs were added earlier and also call adapter methods (setStage and nativeCommitRef/labeledCommitRef), but they are dispatched in bin/spexso.js directly — via lib/labels.js and lib/platform.js respectively — not through lib/facade.js. spexso handoff <id> (lib/handoff.js) is dispatched the same way: it decides and performs the finish → tester hand-off from the handoff config (--dry-run decides only, --rework prints the tester's feedback via the adapter's listComments) — see finish. The same goes for spexso agents sync (lib/agents.js), which is purely local: it stamps the models block of .spexso/config.json (model + optional reasoning effort per agent) into the frontmatter of .claude/agents/spexso-*.md — see agents for why effort requires this sync.
Code verbs (source & pull requests)
spexso mr is accepted as a noun alias for spexso pr (glab's noun).
| Verb | Adapter method | Notes |
|---|---|---|
spexso pr create --source-branch <br> --target-branch <br> --title <t> [--description <d>] [--label …] [--draft --assignee --reviewer --auto-merge --remove-source-branch] | createPR | Returns {ok, id, url}; old --source/--target/--body still work; --label is repeatable |
spexso pr list [--label --author --assignee --reviewer --search …] | listPRs | List merge/pull requests |
spexso pr view <id> | getPR | Returns normalized PR |
spexso pr ci <id> [--sha <sha>] [--wait] | pipelinePR | The MR pipeline of that commit: {status: running|success|failed|null, pipeline, url}; red adds failed (name, stage, log tail per job) and skipped job names. --wait polls every 30 s (2 h cap); null = no pipeline yet, after ~5 min: no CI. GitLab only. The merge-train gate. |
spexso pr update <id> [--title --description --label --unlabel …] | updatePR | Update an open MR/PR |
spexso pr merge <id> [--squash] [--remove-source-branch] [--message --squash-message --rebase --auto-merge --sha] | mergePR | Returns {ok, id}; --delete-branch is an alias of --remove-source-branch |
spexso pr comment <id> --message <body> or --message-file <path> | commentPR | Post a PR review comment; pr note is an alias |
spexso pr close <id> / spexso pr reopen <id> | closePR / reopenPR | Close/reopen without merging |
spexso pr approve <id> [--sha] / spexso pr revoke <id> | approvePR / revokePR | Approve / revoke approval |
spexso pr rebase <id> [--skip-ci] | rebasePR | Rebase the source branch |
spexso pr diff <id> [--raw] | diffPR | Show the MR/PR diff |
spexso pr checkout <id> [--branch] | checkoutPR | Check out the MR/PR branch locally |
Normalized output
Read verbs (issue view, issue list) print a stable JSON shape (Issue / Issue[]) on stdout. The prose always accesses the same fields — .stage, .blockedBy[], .url — regardless of platform. issue view carries populated link buckets; issue list is link-lazy (empty buckets — pair it with link list <id> per issue that needs blocker state). Write verbs print {ok, id, url}. Errors print {ok: false, code, message} and exit non-zero.
See Providers (Multi-Platform) for the full normalized shapes and adapter interface.
Demo-env CLI verb
| Verb | Purpose |
|---|---|
spexso demo-env <id> [--local] or [--remote [url]] | Probe / start / wait for the target app; print a JSON envelope { ok, baseUrl, started, mode }. Used by /spexso-demo. See Demo Runner. |
Marathon rail verbs
Local deterministic rails (no platform adapter) that carry /spexso-marathon state on disk instead of in the orchestrator's context — the same family as waves, fence, and attempt:
| Verb | Purpose |
|---|---|
spexso changed-files [<base>] | Print the worktree's changed files vs the merge-base with origin/{targetBranch} (one-line JSON array of repo-relative paths). Run by the issue runner from inside its worktree — the mechanical fence input. |
spexso window | stdin {issues, budget, sizeScores?, max?, autopick?} → {window, spent, closed_by[, bundle]}. The wave-window fill: first pick always enters, closes at the first non-fitter, max caps attempts. With bundle.budget > 0 and parallel.budget 1 in the config (and no "autopick": true) the verb fills a bundle itself: the budget and weights come from bundle, max is dropped, and the output carries "bundle": true. --bundle forces that mode. |
spexso train guard [--milestone <name>] | Stop the line: exits 1 and names the issue and MR while an issue at stage::review with a needs::* label has an open spexso/issue-<id> MR. The marathon runs it before every window; the factory preflight runs the same check. |
spexso breaker <completed|conflict|skipped|failed> / spexso breaker reset | Persistent circuit-breaker counter in .spexso/marathon-state.json (record-then-signal); exits non-zero at 3 consecutive failures. reset runs at marathon start. |
spexso marathon-log start <issue-id> / spexso marathon-log write <issue-id> '<json>' | The runner's telemetry writer: start records the issue's start time, write writes .spexso/marathon-log/<id>.jsonl with started_at/finished_at (UTC ISO, to the second) and duration_seconds stamped from the clock, overriding any hand-written values. No start → started_at and duration_seconds are null, never invented. |
spexso marathon-run start [--milestone <name>] [--issues 1,2] / spexso marathon-run finish --outcome "<reason>" | Run record for the dashboard's run screen in .spexso/marathon-runs/<id>.json: milestone, issues, start/end (UTC, to the second), stop reason, and the observe log the hooks write to at start. A run left open is closed as abandoned by the next start. |
spexso marathon-log fold <issue-id> [--status <completed|completed_with_conflict|skipped|failed>] | Append .spexso/marathon-log/<id>.jsonl into .spexso/marathon-log.jsonl and delete the per-issue file — telemetry never enters context. --status stamps the merge train's outcome as final_status. Idempotent. |
Complete Command & Agent Map
All slash commands
| Command | Phase | Agent spawned | spexso verbs |
|---|---|---|---|
/spexso-setup | Setup | — | issue list, issue update, issue close, issue note |
/spexso-report | Intake (opportunity) | — | issue create |
/spexso-tinder | Discovery | spexso-researcher | issue create (multiple), wiki push |
/spexso-brainstorm | Discovery (spec) | — | issue list, issue create/update, stage, link |
/spexso-start | Setup (requires spec) | — | issue view (single fetch, incl. links), issue update, stage |
/spexso-marathon | Implementation (loop) | spexso-issue-runner (per issue), spexso-planner (plan-wave scouts when parallel.budget > 1) | issue list, link list, issue update, issue note, window, waves, fence, breaker, marathon-run, marathon-log fold |
/spexso-stop | Utility | — | — |
/spexso-plan | Planning | spexso-planner | issue note |
/spexso-build | Implementation | spexso-tester + spexso-builder (per task) | — |
/spexso-review | Quality | spexso-reviewer | issue note; rulebook inbox: issue list, issue view, issue update/create |
/spexso-rulebook | Quality (rulebook) | — | issue list, issue view, issue update, issue note, pr create |
/spexso-finish | Delivery | — | pr create, pr merge, stage, issue update, issue note |
/spexso-cicd-init | Setup (CI/CD) | — | — |
/spexso-boards-init | Setup (boards) | — | board sync |
/spexso-feedback | Feedback (cross-project) | — | auth status, whoami, upload, label list, issue create |
/spexso-checks | Config (static checks) | — | — |
/spexso-sync | Utility | — | issue list |
/spexso-docs | Utility | — | wiki push |
/spexso-demo | Demo / QA | — | issue view, comment, issue update |
/spexso-autotest | Demo / QA (test server) | — | — (the server does the tracker writes) |
/spexso-redesign | Quality (UX) | — | issue view, issue comments, upload, issue create, link, comment |
/spexso-prototype | Quality (UX) | — | issue view |
Complete lifecycle flow
Report (opportunity) → Brainstorm (spec + dependency links) → Start (Lock + worktree + mode) → Plan (Auto or approved) → Build (TDD per task) → Review (Auto-rewrite crit/high) → Finish (Push+MR+clean) → Docs (ADR + wiki sync)
/spexso-marathon dispatches a fresh spexso-issue-runner subagent per issue (which itself runs Start → Plan → Build → Review → Finish), auto-picking issues by dependency-graph + priority + age. The runner returns only a JSON summary, keeping the orchestrator's context flat for overnight runs.