feat(lanes): drive runs from the pipeline template's own skill

A pipeline template may now declare the slash command that drives it
(`skill`), so the choice of pipeline is the choice of workflow rather
than just a picture on the dashboard:

- `ccam ship-full "<req>"` runs the 16-node `ship-feature` template's
  skill (`/ccam:ship-feature-lane`) — through gates, QC and the senior
  gate to a published PR, watched until a human merges it.
- `ccam ship-quick "<req>"` runs the 8-node `default` template's skill
  (`/ccam:ship-feature`) — in-repo feature work that stops at the gate.

Each command puts the lane on its own template before spawning, so the
dashboard renders the right node count from the first stage instead of
after the skill self-corrects. `--print` shows the command, switches
nothing and runs nothing. The prompt reaches `claude` as one argv
element, never through a shell.

The same field feeds the Workspace run console, which pre-fills its
prompt with the lane's driving skill and never overwrites a prompt the
user has already edited.
This commit is contained in:
2026-08-24 16:34:55 +07:00
parent 2cbb185b7f
commit 2103dde889
12 changed files with 212 additions and 0 deletions
+4
View File
@@ -238,11 +238,15 @@ A lane is a durable unit of parallel agent work — one working directory, many
| `ccam lanes pipeline [<template-id>] [<id>]` | Show which pipeline template a lane renders against, plus the available templates and their node counts; pass a template id to switch. An unknown id is refused (`400 EBADPIPELINE`), and a switch that leaves the lane's current stage unresolvable warns |
| `ccam lanes profile check [<path>]` | Validate a profile — parses, every referenced hook exists and is executable, no leftover `TODO:`, declared ports free. `<path>` defaults to the current directory (not a lane id) |
| `ccam lanes reset\|remove\|purge <id> [--force] [--keep-db] --yes` | Show preflight facts, then perform a destructive action. Refuses without `--yes`; `--force` is required when commits are unpushed; `--keep-db` (`reset` only) skips dropping/recreating a data-isolated lane's database |
| `ccam ship-full "<requirement>" [<id>] [--print]` | **The 16-stage lane pipeline.** Puts the lane on the `ship-feature` template and starts a `claude` session running its skill (`/ccam:ship-feature-lane`): implement → gates → e2e → review → local QC → senior GO/NO-GO → push branch + open PR, then watches the PR until a human merges it. Use when the work should end in a reviewable PR |
| `ccam ship-quick "<requirement>" [<id>] [--print]` | **The 8-stage in-repo pipeline.** Puts the lane on the `default` template and runs its skill (`/ccam:ship-feature`): plan → implement → tests → review → gate → ship. No PR, no browser QC. Use for work that stays in the working copy |
| `ccam stage <stage> [--evidence <text>] [--note <text>] [--result pass\|fail]` | Declare the lane's current pipeline stage. Called by a skill at each phase boundary. `<stage>` may be a node id or one of its template's aliases; a name matching neither is still recorded but warns on stderr (exit stays `0`) that the pipeline map won't show it |
| `ccam feature list [<id>]` | List every feature this lane has activated, archived or live |
| `ccam feature activate <slug> [--title text] [<id>]` | Switch to a feature by slug (echoes the canonicalized slug), archiving the current one first |
| `ccam feature show <slug> [<id>]` | Show one feature's saved pipeline — works on an archived one too |
`ccam ship-full` / `ccam ship-quick` both resolve the lane from the working directory (or take a lane id), pass the requirement to `claude` as one argv element — never through a shell — and accept `--print`, which shows the exact command, switches no template and runs nothing. The skill string itself lives in the template's `skill` field; a template without one makes the command refuse rather than guess.
**Runtime** — the lane's own application stack, as opposed to `start`/`stop`, which drive its Claude run. Two lifecycles, one lane id. Each requires the repository to declare a profile at `<repo>/.ccam/profile/` ([contract](LANES.md#lane-runtime-running-a-lanes-own-stack)); without one they report that nothing is configured rather than failing.
+30
View File
@@ -434,6 +434,34 @@ ccam lanes pipeline ship-feature # switch it
or from the dashboard: the pipeline-template select next to the lane's title in the Workspace detail panel does the same `PATCH /api/lanes/:id` the CLI uses, live (disabled while viewing an archived feature snapshot).
**The template names the skill that drives it.** `"skill": "/ccam:ship-feature-lane"` on the 16-node `ship-feature` template, `"skill": "/ccam:ship-feature"` on the 8-node `default` one. It rides along on every lane payload as `pipeline_skill`, and from a terminal there is one command per depth of work — the command you type picks the pipeline, so no `ccam lanes pipeline` step first:
```bash
cd ~/lanes/myrepo__feat-export
# 16 stages: ends in a published PR, watched until a human merges it
ccam ship-full "add an export button"
# → lane switched to `ship-feature`, then: claude "/ccam:ship-feature-lane add an export button"
# 8 stages: in-repo feature work, stops at review/gate — no PR, no browser QC
ccam ship-quick "fix the CSV separator"
# → lane switched to `default`, then: claude "/ccam:ship-feature fix the CSV separator"
ccam ship-full "add an export button" --print # show the command, switch nothing, run nothing
```
| | `ccam ship-full` | `ccam ship-quick` |
|---|---|---|
| Template | `ship-feature` (16 nodes) | `default` (8 nodes) |
| Skill | `/ccam:ship-feature-lane` | `/ccam:ship-feature` |
| Ends at | PR open on `development`, watched until merged | `ship` in the working copy |
| Includes | unit-test agent, CI gates, e2e, code review, local browser QC, senior GO/NO-GO | plan, implement, tests, review, gate |
| Use when | the work should reach reviewers | the work stays local |
The lane is resolved from the working directory, so no id is needed (pass one to target another lane). Each command puts the lane on its own template *before* spawning, so the dashboard renders the right node count from the first stage rather than after the skill self-corrects; `--print` switches nothing. The requirement is handed to `claude` as ONE argv element — never through a shell — so quotes, `$` and `;` in it are text. A template with no `skill` field makes the command refuse rather than guess.
**The template also decides what the Workspace run console pre-fills.** A template may name the slash command that drives it — `"skill": "/ccam:ship-feature-lane"` on the 16-node `ship-feature` template, `"skill": "/ccam:ship-feature"` on the 8-node `default` one. That string rides along on every lane payload as `pipeline_skill`, and the run console starts its prompt box with it (plus a trailing space) so you only type the requirement: pick the 16-node template and Run starts the 16-step skill, pick the 8-node one and it starts the 8-step skill. The dashboard never executes it — it is text in a prompt box, exactly as if you had typed it. A prompt you have already edited is never overwritten by a later template switch, and a template with no `skill` field pre-fills nothing.
Switching re-resolves the lane's existing declared `stage` against the new node list. A stage the old template knew may resolve to nothing in the new one; the switch warns when that happens (both CLI and UI), and the next `ccam stage` fixes it.
## Attaching a real terminal to a lane
@@ -559,6 +587,7 @@ Create a JSON file in your custom pipeline directory (e.g., `~/.ccam/pipelines/m
{
"id": "ml-training",
"name": "ML Training Pipeline",
"skill": "/my-training-skill",
"nodes": [
{ "id": "data", "label": "data", "icon": "📊", "gate": false, "aliases": ["intake"] },
{ "id": "preprocess","label": "preprocess","icon": "⚙️", "gate": false, "aliases": ["prepare", "clean"] },
@@ -573,6 +602,7 @@ Create a JSON file in your custom pipeline directory (e.g., `~/.ccam/pipelines/m
- **id** (string, required): unique identifier for this template
- **name** (string, optional): display name shown in the UI
- **skill** (string, optional): the slash command that drives this pipeline (e.g. `"/ccam:ship-feature-lane"`). The Workspace run console pre-fills its prompt with it for lanes on this template; omit it and the prompt starts empty. Never executed by the dashboard.
- **nodes** (array, required): list of pipeline stages, in order
- **id** (string): stage identifier (used in `ccam stage`)
- **label** (string, optional): display name in the UI; defaults to `id` if omitted