@jaggerxtrm/specialists 3.17.0 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +268 -134
- package/config/mandatory-rules/json-only-final-output.md +13 -0
- package/config/mandatory-rules/service-skills-diff-scan-mandatory.md +26 -0
- package/config/mandatory-rules/service-skills-gitnexus-triage.md +5 -0
- package/config/skills/setup-specialists/SKILL.md +556 -0
- package/config/skills/specialists-creator/SKILL.md +132 -4
- package/config/skills/specialists-creator/scripts/audit-spec-uniformity.mjs +1 -1
- package/config/specialists/bare.specialist.json +3 -3
- package/config/specialists/changelog-drafter.specialist.json +5 -4
- package/config/specialists/changelog-keeper.specialist.json +7 -6
- package/config/specialists/debugger.specialist.json +2 -2
- package/config/specialists/executor.specialist.json +2 -2
- package/config/specialists/explorer.specialist.json +4 -4
- package/config/specialists/memory-processor.specialist.json +3 -3
- package/config/specialists/node-coordinator.specialist.json +3 -3
- package/config/specialists/obligations-scanner.specialist.json +67 -17
- package/config/specialists/overthinker.specialist.json +3 -3
- package/config/specialists/planner.specialist.json +4 -4
- package/config/specialists/quant-methodologist.specialist.json +145 -0
- package/config/specialists/quant-researcher.specialist.json +144 -0
- package/config/specialists/researcher.specialist.json +5 -5
- package/config/specialists/reviewer.specialist.json +1 -1
- package/config/specialists/seconder.specialist.json +2 -2
- package/config/specialists/security-auditor.specialist.json +2 -2
- package/config/specialists/service-skills-sync.specialist.json +90 -75
- package/config/specialists/specialists-creator.specialist.json +4 -4
- package/config/specialists/sync-docs.specialist.json +4 -4
- package/config/specialists/test-engineer.specialist.json +3 -3
- package/config/specialists/test-runner.specialist.json +7 -7
- package/config/specialists/transcriber.specialist.json +3 -3
- package/config/specialists/xt-merge.specialist.json +4 -4
- package/dist/asset-contract.json +21 -2
- package/dist/index.js +25704 -16376
- package/dist/lib.js +9849 -6147
- package/dist/types/cli/console/components.d.ts +83 -0
- package/dist/types/cli/console/components.d.ts.map +1 -0
- package/dist/types/cli/console/config-source.d.ts +58 -0
- package/dist/types/cli/console/config-source.d.ts.map +1 -0
- package/dist/types/cli/console/forensic.d.ts +11 -0
- package/dist/types/cli/console/forensic.d.ts.map +1 -0
- package/dist/types/cli/console/git.d.ts +28 -0
- package/dist/types/cli/console/git.d.ts.map +1 -0
- package/dist/types/cli/console/help.d.ts +2 -0
- package/dist/types/cli/console/help.d.ts.map +1 -0
- package/dist/types/cli/console/log.d.ts +13 -0
- package/dist/types/cli/console/log.d.ts.map +1 -0
- package/dist/types/cli/console/repo-config.d.ts +26 -0
- package/dist/types/cli/console/repo-config.d.ts.map +1 -0
- package/dist/types/cli/console/repo-discovery.d.ts +12 -0
- package/dist/types/cli/console/repo-discovery.d.ts.map +1 -0
- package/dist/types/cli/console/runtime.d.ts +12 -0
- package/dist/types/cli/console/runtime.d.ts.map +1 -0
- package/dist/types/cli/console/subscribe-prototype.d.ts +18 -0
- package/dist/types/cli/console/subscribe-prototype.d.ts.map +1 -0
- package/dist/types/cli/console/theme.d.ts +91 -0
- package/dist/types/cli/console/theme.d.ts.map +1 -0
- package/dist/types/cli/console/types.d.ts +231 -0
- package/dist/types/cli/console/types.d.ts.map +1 -0
- package/dist/types/cli/console/view-model.d.ts +252 -0
- package/dist/types/cli/console/view-model.d.ts.map +1 -0
- package/dist/types/cli/console.d.ts +2 -0
- package/dist/types/cli/console.d.ts.map +1 -0
- package/dist/types/cli/db.d.ts.map +1 -1
- package/dist/types/cli/doctor.d.ts.map +1 -1
- package/dist/types/cli/edit.d.ts.map +1 -1
- package/dist/types/cli/epic.d.ts.map +1 -1
- package/dist/types/cli/feed.d.ts.map +1 -1
- package/dist/types/cli/forensic.d.ts +2 -0
- package/dist/types/cli/forensic.d.ts.map +1 -0
- package/dist/types/cli/format-helpers.d.ts +4 -2
- package/dist/types/cli/format-helpers.d.ts.map +1 -1
- package/dist/types/cli/help.d.ts.map +1 -1
- package/dist/types/cli/init.d.ts +10 -0
- package/dist/types/cli/init.d.ts.map +1 -1
- package/dist/types/cli/list.d.ts.map +1 -1
- package/dist/types/cli/log.d.ts.map +1 -1
- package/dist/types/cli/metrics.d.ts +2 -0
- package/dist/types/cli/metrics.d.ts.map +1 -0
- package/dist/types/cli/ps.d.ts.map +1 -1
- package/dist/types/cli/result.d.ts.map +1 -1
- package/dist/types/cli/run.d.ts +1 -0
- package/dist/types/cli/run.d.ts.map +1 -1
- package/dist/types/cli/script.d.ts +3 -0
- package/dist/types/cli/script.d.ts.map +1 -1
- package/dist/types/cli/serve.d.ts.map +1 -1
- package/dist/types/cli/setup.d.ts +19 -1
- package/dist/types/cli/setup.d.ts.map +1 -1
- package/dist/types/cli/status.d.ts.map +1 -1
- package/dist/types/cli/version-check.d.ts +1 -0
- package/dist/types/cli/version-check.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/pi/session.d.ts +11 -1
- package/dist/types/pi/session.d.ts.map +1 -1
- package/dist/types/server.d.ts +15 -0
- package/dist/types/server.d.ts.map +1 -1
- package/dist/types/specialist/benchmarks.d.ts +37 -0
- package/dist/types/specialist/benchmarks.d.ts.map +1 -0
- package/dist/types/specialist/chain-identity.d.ts +7 -1
- package/dist/types/specialist/chain-identity.d.ts.map +1 -1
- package/dist/types/specialist/control.d.ts.map +1 -1
- package/dist/types/specialist/forensic-events.d.ts +138 -0
- package/dist/types/specialist/forensic-events.d.ts.map +1 -0
- package/dist/types/specialist/forensic-renderer.d.ts +34 -0
- package/dist/types/specialist/forensic-renderer.d.ts.map +1 -0
- package/dist/types/specialist/git-diff-evidence.d.ts +28 -0
- package/dist/types/specialist/git-diff-evidence.d.ts.map +1 -0
- package/dist/types/specialist/global-config.d.ts +389 -0
- package/dist/types/specialist/global-config.d.ts.map +1 -0
- package/dist/types/specialist/launch.d.ts +1 -0
- package/dist/types/specialist/launch.d.ts.map +1 -1
- package/dist/types/specialist/live-aggregates.d.ts +46 -0
- package/dist/types/specialist/live-aggregates.d.ts.map +1 -0
- package/dist/types/specialist/loader.d.ts +50 -1
- package/dist/types/specialist/loader.d.ts.map +1 -1
- package/dist/types/specialist/model-chain.d.ts +7 -0
- package/dist/types/specialist/model-chain.d.ts.map +1 -0
- package/dist/types/specialist/model-probes.d.ts +28 -0
- package/dist/types/specialist/model-probes.d.ts.map +1 -0
- package/dist/types/specialist/node-contract.d.ts +18 -18
- package/dist/types/specialist/node-supervisor.d.ts.map +1 -1
- package/dist/types/specialist/observability-db.d.ts +1 -1
- package/dist/types/specialist/observability-db.d.ts.map +1 -1
- package/dist/types/specialist/observability-sqlite.d.ts +25 -0
- package/dist/types/specialist/observability-sqlite.d.ts.map +1 -1
- package/dist/types/specialist/preset-resolver.d.ts +56 -0
- package/dist/types/specialist/preset-resolver.d.ts.map +1 -0
- package/dist/types/specialist/prometheus-projection.d.ts +25 -0
- package/dist/types/specialist/prometheus-projection.d.ts.map +1 -0
- package/dist/types/specialist/runner.d.ts +26 -1
- package/dist/types/specialist/runner.d.ts.map +1 -1
- package/dist/types/specialist/schema.d.ts +163 -54
- package/dist/types/specialist/schema.d.ts.map +1 -1
- package/dist/types/specialist/script-runner.d.ts +5 -1
- package/dist/types/specialist/script-runner.d.ts.map +1 -1
- package/dist/types/specialist/snapshot-diff.d.ts +8 -0
- package/dist/types/specialist/snapshot-diff.d.ts.map +1 -0
- package/dist/types/specialist/source-queue.d.ts +13 -0
- package/dist/types/specialist/source-queue.d.ts.map +1 -0
- package/dist/types/specialist/supervisor.d.ts +15 -1
- package/dist/types/specialist/supervisor.d.ts.map +1 -1
- package/dist/types/specialist/timeline-events.d.ts +68 -1
- package/dist/types/specialist/timeline-events.d.ts.map +1 -1
- package/dist/types/tools/specialist/resume_specialist.tool.d.ts +4 -4
- package/dist/types/tools/specialist/specialist_status.tool.d.ts +1 -1
- package/dist/types/tools/specialist/steer_specialist.tool.d.ts +4 -4
- package/dist/types/tools/specialist/use_specialist.tool.d.ts +16 -16
- package/docs/ARCHITECTURE.md +1176 -0
- package/docs/TODO.md +9 -0
- package/docs/architecture.md +11 -0
- package/docs/archive/2026-03-13-bd-decision-context-template-plan.md +96 -0
- package/docs/archive/AGENT-HANDOFF.md +351 -0
- package/docs/archive/PARITY-ANALYSIS.md +296 -0
- package/docs/archive/SPECIALISTS_REFACTOR.md.md +30 -0
- package/docs/archive/cc-programmatic.md +216 -0
- package/docs/archive/claude-agent-sdk.md +594 -0
- package/docs/archive/decision-specialist-directory.md +41 -0
- package/docs/archive/discoveries.md +148 -0
- package/docs/archive/executor-benchmark-protocol.md +198 -0
- package/docs/archive/future-features.md +66 -0
- package/docs/archive/gzrx-completion-critique.md +183 -0
- package/docs/archive/gzrx-research-notes.md +401 -0
- package/docs/archive/gzrx-tool-catalog.md +760 -0
- package/docs/archive/iron-review-hardening-qa-chain-substrate.md +322 -0
- package/docs/archive/iron-review-hardening.html +1004 -0
- package/docs/archive/issuetracking.md +312 -0
- package/docs/archive/qa-v3.0.2.md +220 -0
- package/docs/archive/restructure.md +231 -0
- package/docs/archive/script-specialists.md +1254 -0
- package/docs/archive/spec-v3.md +792 -0
- package/docs/archive/specialist-stats.md +127 -0
- package/docs/archive/specialists-friction-audit.md +1347 -0
- package/docs/archive/specialists-runtime-critique.md +170 -0
- package/docs/archive/specialists-service-evaluation.md +713 -0
- package/docs/archive/specialists-substrate-alignment.md +255 -0
- package/docs/archive/substrate-review.md +1288 -0
- package/docs/archive/test-writer-specialist.md +254 -0
- package/docs/archive/using-specialists-v3-improvements-2026-05-09.md +600 -0
- package/docs/archive/xtrm-specialists-analysis.md +314 -0
- package/docs/authoring.md +701 -0
- package/docs/background-jobs.md +203 -0
- package/docs/bare-specialists.md +83 -0
- package/docs/benchmarks/executor-benchmark-runner.md +66 -0
- package/docs/bootstrap.md +161 -0
- package/docs/cli-reference.md +1645 -0
- package/docs/deploying-alongside.md +155 -0
- package/docs/design/README.md +36 -0
- package/docs/design/darth-feedor-migration.md +290 -0
- package/docs/design/roadmap/README.md +32 -0
- package/docs/design/roadmap/chain-templates/README.md +146 -0
- package/docs/design/roadmap/chain-templates/code-quick.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/code-standard.formula.json +126 -0
- package/docs/design/roadmap/chain-templates/code-with-advisors.formula.json +128 -0
- package/docs/design/roadmap/chain-templates/code-with-tests.formula.json +76 -0
- package/docs/design/roadmap/chain-templates/debug.formula.json +128 -0
- package/docs/design/roadmap/chain-templates/doc-sync.formula.json +28 -0
- package/docs/design/roadmap/chain-templates/memory-hygiene.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/planning.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/premortem.formula.json +26 -0
- package/docs/design/roadmap/chain-templates/release-prep.formula.json +36 -0
- package/docs/design/roadmap/chain-templates/research-only.formula.json +28 -0
- package/docs/design/roadmap/chain-templates/restitch.formula.json +125 -0
- package/docs/design/roadmap/chain-templates/security-deep.formula.json +161 -0
- package/docs/design/roadmap/chain-templates/test-only.formula.json +52 -0
- package/docs/design/roadmap/chain-templates/triage.formula.json +35 -0
- package/docs/design/roadmap/history/handoff-from-substrate-design.md +87 -0
- package/docs/design/roadmap/history/substrate-reconciliation.md +105 -0
- package/docs/design/roadmap/specialists-roadmap.md +1193 -0
- package/docs/design/sp-console-subscribe-via-materializer.md +231 -0
- package/docs/design/sp-console-tui-mock-v2.html +293 -0
- package/docs/design/sp-console-tui-mock.html +120 -0
- package/docs/design/sp-console-tui.md +340 -0
- package/docs/design/specialist-agentops-suite.md +323 -0
- package/docs/design/substrate/channels.md +14 -0
- package/docs/design/substrate/devops-platform-engineering-prd.md +446 -0
- package/docs/design/substrate/html-design-example.md +339 -0
- package/docs/design/xtrm-tiers-architecture.svg +132 -0
- package/docs/devops/dependency-verdict-materialization.md +46 -0
- package/docs/epic-readiness.md +75 -0
- package/docs/examples/mercury-atomic-summarizer.specialist.json +26 -0
- package/docs/examples/smoke-echo-text-expected-keys.specialist.json +25 -0
- package/docs/examples/smoke-echo.specialist.json +25 -0
- package/docs/features.md +1577 -0
- package/docs/hooks.md +81 -0
- package/docs/installation.md +142 -0
- package/docs/manifest.md +184 -0
- package/docs/mcp-servers.md +73 -0
- package/docs/mcp-tools.md +71 -0
- package/docs/nodes.md +231 -0
- package/docs/observability-metrics.md +152 -0
- package/docs/operator/sp-console-v2-walkthrough.md +410 -0
- package/docs/overrides-guide.md +306 -0
- package/docs/pi-rpc-boundary.md +118 -0
- package/docs/pi-session.md +195 -0
- package/docs/release.md +22 -0
- package/docs/skills.md +132 -0
- package/docs/specialists/handoff-schema.md +181 -0
- package/docs/specialists-catalog.md +99 -0
- package/docs/specialists-service-install.md +226 -0
- package/docs/specialists-service.md +363 -0
- package/docs/surface-ownership.md +138 -0
- package/docs/upgrade-notes/kan-90-global-user-config.md +114 -0
- package/docs/upgrade-notes/kan-91-expanded-overrides.md +261 -0
- package/docs/workflow.md +114 -0
- package/docs/worktree.md +71 -0
- package/docs/worktrees.md +309 -0
- package/package.json +6 -3
package/docs/features.md
ADDED
|
@@ -0,0 +1,1577 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Feature Guides
|
|
3
|
+
scope: runtime-features
|
|
4
|
+
category: guide
|
|
5
|
+
version: 2.5.0
|
|
6
|
+
updated: 2026-06-23
|
|
7
|
+
synced_at: bf6baf7a
|
|
8
|
+
description: Practical guides for structured output, job observation, bead-linked runs, keep-alive resume, worktree isolation, stuck detection, waiting state observability, auto gitnexus sync, specialist authoring, config presets, JSON-first configuration, context denormalization, and job lineage tracking.
|
|
9
|
+
source_of_truth_for:
|
|
10
|
+
- "src/cli/run.ts"
|
|
11
|
+
- "src/cli/feed.ts"
|
|
12
|
+
- "src/cli/result.ts"
|
|
13
|
+
- "src/cli/resume.ts"
|
|
14
|
+
- "src/specialist/supervisor.ts"
|
|
15
|
+
- "src/specialist/schema.ts"
|
|
16
|
+
- "src/specialist/job-root.ts"
|
|
17
|
+
- "src/specialist/worktree.ts"
|
|
18
|
+
- "src/specialist/worktree-gc.ts"
|
|
19
|
+
- "src/cli/edit.ts"
|
|
20
|
+
- "src/specialist/loader.ts"
|
|
21
|
+
- "src/cli/ps.ts"
|
|
22
|
+
- "src/cli/epic.ts"
|
|
23
|
+
- "src/cli/end.ts"
|
|
24
|
+
- "src/cli/merge.ts"
|
|
25
|
+
- "src/specialist/epic-lifecycle.ts"
|
|
26
|
+
- "src/specialist/chain-identity.ts"
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Feature Guides
|
|
30
|
+
|
|
31
|
+
> `sp` is an alias for `specialists`.
|
|
32
|
+
|
|
33
|
+
## 1) Structured run output modes (`human`, `--json`, `--raw`)
|
|
34
|
+
|
|
35
|
+
`specialists run` supports three foreground output modes.
|
|
36
|
+
|
|
37
|
+
### Human mode (default)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
sp run executor --prompt "Investigate failing tests"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- Shows formatted timeline events (debounced to reduce noise)
|
|
44
|
+
- Prints final assistant output when `run_complete` arrives
|
|
45
|
+
- Prints job footer to stderr with `job`, optional `bead`, elapsed time, model/backend
|
|
46
|
+
|
|
47
|
+
### JSON mode (`--json`)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
sp run executor --prompt "Investigate failing tests" --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Streams NDJSON, one event per line
|
|
54
|
+
- Each event envelope includes `jobId`, `specialist`, optional `beadId`, plus timeline event fields
|
|
55
|
+
- Model/backend banner still prints to stderr
|
|
56
|
+
|
|
57
|
+
### Raw mode (`--raw`)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
sp run executor --prompt "Investigate failing tests" --raw
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- Legacy stream of raw progress deltas (`onProgress`) to stdout
|
|
64
|
+
- Useful for backward compatibility with older parsers
|
|
65
|
+
- Does not tail `events.jsonl` formatting
|
|
66
|
+
|
|
67
|
+
### Mode selection rules
|
|
68
|
+
|
|
69
|
+
- Default is `human`
|
|
70
|
+
- `--json` switches to structured event stream
|
|
71
|
+
- `--raw` switches to legacy progress stream
|
|
72
|
+
- If both are passed, the last flag wins
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 2) Job observation: `feed`, `ps`, `result`
|
|
77
|
+
|
|
78
|
+
All observation reads DB-backed runtime state first. Legacy/operator mirrors under:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Legacy fallback artifacts (`observability.db` is primary runtime store):
|
|
82
|
+
.specialists/jobs/<job-id>/
|
|
83
|
+
status.json
|
|
84
|
+
events.jsonl
|
|
85
|
+
result.txt
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### SQLite persistence (schema v4)
|
|
89
|
+
|
|
90
|
+
When SQLite is available, Supervisor uses it as the primary storage backend. File-based fallback is legacy/operator-only:
|
|
91
|
+
|
|
92
|
+
- **`specialist_jobs` table**: status, bead_id, node_id, worktree_path, branch, last_output, elapsed_ms
|
|
93
|
+
- **`specialist_events` table**: append-only timeline with event_json (JSON-first design)
|
|
94
|
+
- **Node tables** (schema v4): `node_runs`, `node_members`, `node_events`, `node_memory` for orchestrator tracking
|
|
95
|
+
- **Dual-write**: atomic transactions at job start/completion; mid-run writes are standalone for resilience
|
|
96
|
+
- **Backward compatible**: file-based storage remains available only for recovery/debug tooling when SQLite is unavailable
|
|
97
|
+
|
|
98
|
+
### `feed` (timeline-first)
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
sp feed <job-id>
|
|
102
|
+
sp feed <job-id> --follow
|
|
103
|
+
sp feed -f --forever
|
|
104
|
+
sp feed --json --since 5m --limit 200
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- Best for timeline/event visibility
|
|
108
|
+
- Snapshot mode: replay matching events
|
|
109
|
+
- Follow mode (`-f`): polls and appends new events in chronological order
|
|
110
|
+
- JSON mode outputs NDJSON envelopes with job metadata + event payload
|
|
111
|
+
- **Waiting state**: when a keep-alive job enters `waiting` status, feed displays a magenta `WAIT` banner with resume instructions
|
|
112
|
+
- **Text preview**: `TURN+` lines show 80-char preview of accumulated text content
|
|
113
|
+
- **Context warnings**: feed displays context utilization warnings at WARN/CRITICAL thresholds
|
|
114
|
+
- **Startup context lines**: on `run_start` events with `startup_snapshot`, emits dimmed `↳ startup` summary (job, specialist, bead, worktree, branch, vars, skills); on `meta` events with `memory_injection`, emits `↳ memory` token accounting line (static, dynamic, gitnexus, total)
|
|
115
|
+
|
|
116
|
+
### `result` (final text)
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
sp result <job-id>
|
|
120
|
+
sp result <job-id> --wait --timeout 120
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- Prints `result.txt`
|
|
124
|
+
- `--wait` polls until `done`/`error`
|
|
125
|
+
- `--timeout` applies only with `--wait`
|
|
126
|
+
- **Waiting state**: when status is `waiting`, result prints a footer with resume instructions
|
|
127
|
+
- **SQLite-backed**: reads from `specialist_jobs.last_output` column when available
|
|
128
|
+
- **Startup context block**: derives startup snapshot from `status.json.startup_context` merged with `run_start` event + `meta` memory_injection. Prepends `--- startup context ---` block in human mode; adds `startup_context` field in `--json` mode
|
|
129
|
+
|
|
130
|
+
Use `result` when you want final plain text; use `feed` when you want event history and incremental state.
|
|
131
|
+
|
|
132
|
+
### Current tool staleness fix (April 2026)
|
|
133
|
+
|
|
134
|
+
`sp ps` exposes `current_tool` to show which tool a job is executing. Prior to April 2026, this field was stale because:
|
|
135
|
+
|
|
136
|
+
1. `current_tool` was set on `tool_execution_start` but never cleared on `tool_execution_end`
|
|
137
|
+
2. `sp ps` read from `status.json` snapshot, not the live event stream
|
|
138
|
+
|
|
139
|
+
**Fix (unitAI-66xn, unitAI-yke7):**
|
|
140
|
+
|
|
141
|
+
- **Read side**: `sp ps` now derives `current_tool` from `specialist_events` table, querying the latest tool event (start/update/end) instead of trusting `status.json`
|
|
142
|
+
- **Write side**: Supervisor clears `current_tool: undefined` in `onToolEndCallback` on every `tool_execution_end`
|
|
143
|
+
|
|
144
|
+
This prevents false-positive "hung job" diagnoses where `sp ps` showed a stale tool (e.g., `gitnexus_context`) while the model was actively streaming text.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 2a) Console TUI (`sp console`)
|
|
149
|
+
|
|
150
|
+
`sp console` provides an interactive TUI for monitoring and controlling jobs across multiple repos.
|
|
151
|
+
|
|
152
|
+
### ALL view (multi-repo overview)
|
|
153
|
+
|
|
154
|
+
The ALL view shows active jobs from all configured repos in a single scrollable list.
|
|
155
|
+
|
|
156
|
+
**Navigation:**
|
|
157
|
+
- `↑↓` or `j/k` — move cursor through selectable job rows (skips headers/spacers)
|
|
158
|
+
- `0` — reset cursor to top and switch to ALL view
|
|
159
|
+
|
|
160
|
+
**Actions (cursor on job row):**
|
|
161
|
+
- `↵` (Enter) — open feed for selected job
|
|
162
|
+
- `r` — open result for selected job
|
|
163
|
+
- `i` — inspect job details
|
|
164
|
+
- `b` — open bead view for the job's input bead
|
|
165
|
+
- `d` — open diff view for the job's worktree changes
|
|
166
|
+
|
|
167
|
+
**Repo selection:**
|
|
168
|
+
- `Tab` — cycle to next repo tab
|
|
169
|
+
- `1-9` — jump to repo by index
|
|
170
|
+
|
|
171
|
+
**Other keys:**
|
|
172
|
+
- `q` — quit console
|
|
173
|
+
- `g` — open global config view (from ps view)
|
|
174
|
+
- `R` — open repo config view (from ps view)
|
|
175
|
+
- `x` — stop selected job (from ps/all view)
|
|
176
|
+
|
|
177
|
+
The ALL view auto-scrolls to keep the cursor visible and auto-advances off non-selectable rows (headers/spacers) on first render.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
Use an existing bead as the run input source:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
sp run executor --bead unitAI-123
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Behavior:
|
|
188
|
+
|
|
189
|
+
- Reads bead content via `bd show --json`
|
|
190
|
+
- Builds full run prompt from bead context (`buildBeadContext(...)`)
|
|
191
|
+
- Injects variables:
|
|
192
|
+
- `$bead_context`
|
|
193
|
+
- `$bead_id`
|
|
194
|
+
- Adds `bead_id` to status and timeline (`run_start`, status footer)
|
|
195
|
+
- **Schema v2**: `bead_id` persisted as dedicated column in `specialist_jobs` table (backfilled from status_json)
|
|
196
|
+
|
|
197
|
+
### Dependency context injection
|
|
198
|
+
|
|
199
|
+
By default, `--bead` injects completed blockers at depth 1.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
sp run executor --bead unitAI-123 --context-depth 2
|
|
203
|
+
sp run executor --bead unitAI-123 --context-depth 0 # disable blocker injection
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Tracking control
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
sp run executor --bead unitAI-123 --no-beads
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
- `--no-beads` disables bead tracking/updates
|
|
213
|
+
- Bead reading still works (run input still comes from `--bead`)
|
|
214
|
+
|
|
215
|
+
### Prompt source exclusivity
|
|
216
|
+
|
|
217
|
+
`--prompt` and `--bead` are mutually exclusive.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 4) Keep-alive + resume (`--keep-alive`, `--no-keep-alive`, `resume`)
|
|
222
|
+
|
|
223
|
+
Keep a session alive for multi-turn flows:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
sp run executor --prompt "Analyze this bug" --keep-alive
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Interactive specialists can enable this by default in YAML:
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
specialist:
|
|
233
|
+
execution:
|
|
234
|
+
interactive: true
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Default behavior and precedence:
|
|
238
|
+
|
|
239
|
+
1. `--no-keep-alive` / `no_keep_alive` forces one-shot mode
|
|
240
|
+
2. `--keep-alive` / `keep_alive` forces keep-alive
|
|
241
|
+
3. Otherwise, runner uses merged `execution.interactive` (package spec → `~/.config/specialists/user.json` → repo override)
|
|
242
|
+
4. If unset, default is one-shot (`false`)
|
|
243
|
+
|
|
244
|
+
Supervisor behavior in keep-alive mode:
|
|
245
|
+
|
|
246
|
+
- Creates FIFO: `.specialists/jobs/<job-id>/steer.pipe`
|
|
247
|
+
- On first turn completion, job status becomes `waiting`
|
|
248
|
+
- Emits `status_change` timeline event with `status: "waiting"` and `previous_status: "running"`
|
|
249
|
+
- Session stays alive with full conversation history retained
|
|
250
|
+
|
|
251
|
+
Resume with a next-turn task:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
sp resume <job-id> "Now implement the fix and add tests"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Rules:
|
|
258
|
+
|
|
259
|
+
- `resume` is valid only when status is `waiting`
|
|
260
|
+
- If status is `running`, use `steer`/`steer_specialist` (mid-turn guidance)
|
|
261
|
+
- `resume` writes `{type:"resume", task:"..."}` to FIFO
|
|
262
|
+
- After resume turn finishes, status returns to `waiting` until closed
|
|
263
|
+
|
|
264
|
+
### Waiting state observability
|
|
265
|
+
|
|
266
|
+
When a keep-alive job enters the `waiting` state, the system provides multiple observation signals:
|
|
267
|
+
|
|
268
|
+
**Timeline event** (`events.jsonl`):
|
|
269
|
+
```json
|
|
270
|
+
{"t": 1743883200000, "type": "status_change", "status": "waiting", "previous_status": "running"}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Feed output** (`sp feed <job-id>`):
|
|
274
|
+
```
|
|
275
|
+
WAIT executor (49adda) is waiting for input. Use: specialists resume 49adda "..."
|
|
276
|
+
```
|
|
277
|
+
- Displayed in **magenta** to distinguish from running/done states
|
|
278
|
+
- Shows specialist name, job ID, and exact resume command
|
|
279
|
+
|
|
280
|
+
**Status output** (`sp status --job <job-id>`):
|
|
281
|
+
```
|
|
282
|
+
status waiting
|
|
283
|
+
action specialists resume 49adda "..."
|
|
284
|
+
```
|
|
285
|
+
- Status field rendered in magenta
|
|
286
|
+
- `action` row shows the resume command to use
|
|
287
|
+
|
|
288
|
+
**Result footer** (`sp result <job-id>`):
|
|
289
|
+
```
|
|
290
|
+
--- Session is waiting for your input. Use: specialists resume 49adda "..." ---
|
|
291
|
+
```
|
|
292
|
+
- Appended to result output when status is `waiting`
|
|
293
|
+
- Printed to stderr in dimmed text
|
|
294
|
+
|
|
295
|
+
Use `--no-keep-alive` for a one-off run even when the specialist is interactive:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
sp run executor --prompt "Quick check only" --no-keep-alive
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Observation loop for keep-alive runs:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
sp feed <job-id> --follow
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 5) --job concurrency guard
|
|
310
|
+
|
|
311
|
+
When `--job <id>` reuses an existing job's worktree, MEDIUM/HIGH permission specialists are blocked from entering while the target job is still `starting` or `running`. This prevents concurrent file corruption.
|
|
312
|
+
|
|
313
|
+
### Blocked statuses
|
|
314
|
+
|
|
315
|
+
| Status | Blocked for MEDIUM/HIGH | Allowed for READ_ONLY/LOW |
|
|
316
|
+
|--------|:-----------------------:|:------------------------:|
|
|
317
|
+
| `starting` | ✗ Blocked | ✓ Allowed |
|
|
318
|
+
| `running` | ✗ Blocked | ✓ Allowed |
|
|
319
|
+
| `waiting` | ✓ Allowed | ✓ Allowed |
|
|
320
|
+
| `done` | ✓ Allowed | ✓ Allowed |
|
|
321
|
+
| `error` | ✓ Allowed | ✓ Allowed |
|
|
322
|
+
| `cancelled` | ✓ Allowed | ✓ Allowed |
|
|
323
|
+
| Unknown | ✗ Blocked (conservative) | ✓ Allowed |
|
|
324
|
+
|
|
325
|
+
### Bypass with --force-job
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
sp run executor --job a1b2c3 --force-job --bead fix-123
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Use `--force-job` when:
|
|
332
|
+
- The target job's status is stale/unknown but the worktree is known to be safe
|
|
333
|
+
- Emergency fix entry when the original job is stalled but not terminal
|
|
334
|
+
- Caller explicitly accepts concurrent write risk
|
|
335
|
+
|
|
336
|
+
READ_ONLY and LOW specialists bypass the guard entirely — they cannot corrupt files.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 6) Liveness checks for `sp list --live`
|
|
341
|
+
|
|
342
|
+
The `--live` mode in `sp list` filters out dead jobs by default. A job is **dead** when:
|
|
343
|
+
- Its PID no longer exists (`ps -p <pid>` fails)
|
|
344
|
+
- Its tmux session is gone (`tmux has-session -t <name>` fails or times out)
|
|
345
|
+
|
|
346
|
+
`is_dead` is a **computed field**, never persisted to `status.json`. This avoids stale state where a dead job is marked alive or vice versa.
|
|
347
|
+
|
|
348
|
+
### `--show-dead` flag
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
sp list --live --show-dead
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Shows dead jobs with a `dead` status indicator. Useful for debugging sessions that crashed or were killed externally.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## 7) Job status lifecycle
|
|
359
|
+
|
|
360
|
+
Supervisor tracks job status through a state machine:
|
|
361
|
+
|
|
362
|
+
```
|
|
363
|
+
starting → running → waiting → (resume) → running → ... → done/error/cancelled
|
|
364
|
+
↘ error
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Terminal statuses**:
|
|
368
|
+
- `done` — job completed normally with `run_complete` event
|
|
369
|
+
- `error` — job failed (exception, timeout, crash)
|
|
370
|
+
- `cancelled` — job stopped intentionally without completion evidence
|
|
371
|
+
|
|
372
|
+
**`cancelled` status**:
|
|
373
|
+
|
|
374
|
+
Introduced to distinguish intentional stops from failures:
|
|
375
|
+
- Set by `sp stop` when job has no `run_complete` event
|
|
376
|
+
- Preserved in SQLite + legacy/operator file mirror `status.json`
|
|
377
|
+
- Rendered in `sp ps` and `sp status` (gray color)
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 8) Stuck detection configuration
|
|
382
|
+
|
|
383
|
+
There are two complementary mechanisms.
|
|
384
|
+
|
|
385
|
+
### A) Session-level stall timeout (`execution.stall_timeout_ms`)
|
|
386
|
+
|
|
387
|
+
Defined in specialist YAML under `execution`.
|
|
388
|
+
|
|
389
|
+
```yaml
|
|
390
|
+
specialist:
|
|
391
|
+
execution:
|
|
392
|
+
stall_timeout_ms: 120000
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- Passed to `PiAgentSession` as `stallTimeoutMs`
|
|
396
|
+
- If no RPC/protocol activity occurs within this window, the session is killed with `StallTimeoutError`
|
|
397
|
+
- Set `0`/unset to disable this watchdog
|
|
398
|
+
|
|
399
|
+
### B) Supervisor-level stale detection (`stall_detection`)
|
|
400
|
+
|
|
401
|
+
Defined at top-level specialist config:
|
|
402
|
+
|
|
403
|
+
```yaml
|
|
404
|
+
specialist:
|
|
405
|
+
stall_detection:
|
|
406
|
+
running_silence_warn_ms: 60000
|
|
407
|
+
running_silence_error_ms: 300000
|
|
408
|
+
waiting_stale_ms: 3600000
|
|
409
|
+
waiting_auto_close_ms: 0
|
|
410
|
+
tool_duration_warn_ms: 120000
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Defaults (if omitted):
|
|
414
|
+
|
|
415
|
+
- `running_silence_warn_ms`: 60s
|
|
416
|
+
- `running_silence_error_ms`: 300s
|
|
417
|
+
- `waiting_stale_ms`: 1h (3600s) — waiting jobs past this threshold emit `stale_warning` events
|
|
418
|
+
- `waiting_auto_close_ms`: disabled by default (`0` or `null`) — when set to a positive number, stale waiting jobs attempt graceful close first, then forced termination fallback if graceful close times out
|
|
419
|
+
- `tool_duration_warn_ms`: 120s
|
|
420
|
+
|
|
421
|
+
Supervisor outcomes:
|
|
422
|
+
|
|
423
|
+
- Emits `stale_warning` timeline events
|
|
424
|
+
- Can promote long-running silence to `status=error`
|
|
425
|
+
- Dead waiting jobs with no `run_complete` evidence transition to `error` (non-node only)
|
|
426
|
+
- Dead waiting jobs with `run_complete` evidence reconcile to `done`
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 9) Test-aware stall detection
|
|
431
|
+
|
|
432
|
+
PiAgentSession extends the stall timeout window when a bash tool command matches a test runner pattern:
|
|
433
|
+
|
|
434
|
+
- `vitest` (including `bun --bun vitest`)
|
|
435
|
+
- `bun test`
|
|
436
|
+
- `npm/pnpm/yarn test`
|
|
437
|
+
- `jest`
|
|
438
|
+
- `pytest`
|
|
439
|
+
|
|
440
|
+
During detected test commands, the effective timeout is `max(base_timeout, test_timeout)` where `test_timeout` defaults to 300s. This prevents the stall watchdog from killing test runners during tinypool worker initialization, which can take longer than the standard 30-120s stall window.
|
|
441
|
+
|
|
442
|
+
### Extended window lifecycle
|
|
443
|
+
|
|
444
|
+
1. `tool_execution_start` detected → pattern match on command string
|
|
445
|
+
2. If test pattern matched → extend stall timeout for this tool call
|
|
446
|
+
3. `tool_execution_end` → restore base stall timeout
|
|
447
|
+
4. Stall watchdog still fires for actual hangs — no upper-bound removal
|
|
448
|
+
|
|
449
|
+
### Known limitations
|
|
450
|
+
|
|
451
|
+
- Pattern-based detection may miss custom test wrappers
|
|
452
|
+
- Process-group isolation not implemented (deeper refactor needed)
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## 10) Specialist authoring example (executor-style)
|
|
457
|
+
|
|
458
|
+
Example with structured-friendly settings and stall controls (JSON format):
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"specialist": {
|
|
463
|
+
"metadata": {
|
|
464
|
+
"name": "executor",
|
|
465
|
+
"version": "1.0.0",
|
|
466
|
+
"description": "General-purpose execution specialist",
|
|
467
|
+
"category": "codegen"
|
|
468
|
+
},
|
|
469
|
+
"execution": {
|
|
470
|
+
"model": "openai-codex/gpt-5.3-codex",
|
|
471
|
+
"fallback_model": "google-gemini-cli/gemini-3.1-pro-preview",
|
|
472
|
+
"timeout_ms": 0,
|
|
473
|
+
"stall_timeout_ms": 120000,
|
|
474
|
+
"response_format": "text",
|
|
475
|
+
"permission_required": "HIGH",
|
|
476
|
+
"thinking_level": "medium"
|
|
477
|
+
},
|
|
478
|
+
"prompt": {
|
|
479
|
+
"system": "You are a production implementation specialist.",
|
|
480
|
+
"task_template": "$prompt\n\nWorking directory: $cwd"
|
|
481
|
+
},
|
|
482
|
+
"stall_detection": {
|
|
483
|
+
"running_silence_warn_ms": 60000,
|
|
484
|
+
"running_silence_error_ms": 300000,
|
|
485
|
+
"waiting_stale_ms": 3600000,
|
|
486
|
+
"tool_duration_warn_ms": 120000
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Authoring notes:
|
|
493
|
+
|
|
494
|
+
- **JSON-first**: Specialist configs use `.specialist.json` format (YAML deprecated but supported)
|
|
495
|
+
- `response_format` controls requested format (`text|json|markdown`) at specialist config level
|
|
496
|
+
- `stall_timeout_ms` handles session protocol silence
|
|
497
|
+
- `stall_detection` handles Supervisor state/timeline warnings and error promotion
|
|
498
|
+
- `permission_required` controls post-job GitNexus reindex (see below)
|
|
499
|
+
- For bead-driven specialists, rely on `$bead_context` / `$bead_id` in templates
|
|
500
|
+
- Bare specialists: see [bare-specialists.md](bare-specialists.md)
|
|
501
|
+
- Additional fields: `author`, `tags`, `created`, `output_type`, `max_retries`, `beads_write_notes`, `communication`
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## 11) Configuration presets (`--preset`)
|
|
507
|
+
|
|
508
|
+
Presets provide one-shot configuration profiles for quick adaptation to different task types without editing specialist configs.
|
|
509
|
+
|
|
510
|
+
### Available presets
|
|
511
|
+
|
|
512
|
+
Presets are defined in `config/presets.json`:
|
|
513
|
+
|
|
514
|
+
| Preset | Model | Thinking | Stall Timeout | Use Case |
|
|
515
|
+
|--------|-------|----------|---------------|----------|
|
|
516
|
+
| `cheap` | see `sp edit --list-presets` | `off` | 60s | Exploration, simple tasks, quick lookups |
|
|
517
|
+
| `medium` | see `sp edit --list-presets` | `low` | 120s | Balanced cost/quality — default for most tasks |
|
|
518
|
+
| `power` | see `sp edit --list-presets` | `high` | 300s | Complex implementation, deep reasoning |
|
|
519
|
+
|
|
520
|
+
Preset model values are operational defaults and may change between releases; inspect the live package with `sp edit --list-presets` or `config/presets.json`.
|
|
521
|
+
|
|
522
|
+
### Usage
|
|
523
|
+
|
|
524
|
+
Apply a preset to a specialist config:
|
|
525
|
+
|
|
526
|
+
```bash
|
|
527
|
+
sp edit executor --preset cheap
|
|
528
|
+
sp edit executor --preset medium
|
|
529
|
+
sp edit executor --preset power
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
This mutates the specialist's JSON config in place, updating:
|
|
533
|
+
- `specialist.execution.model`
|
|
534
|
+
- `specialist.execution.thinking_level`
|
|
535
|
+
- `specialist.execution.stall_timeout_ms`
|
|
536
|
+
|
|
537
|
+
### When to use
|
|
538
|
+
|
|
539
|
+
- **cheap**: Quick exploration, documentation lookups, simple refactors
|
|
540
|
+
- **medium**: Standard implementation work, bug fixes, feature development
|
|
541
|
+
- **power**: Complex architecture changes, multi-file refactors, difficult debugging
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## 12) Configuration format: JSON-first with YAML fallback
|
|
546
|
+
|
|
547
|
+
Specialist configurations migrated from YAML to JSON in v2.1.15+.
|
|
548
|
+
|
|
549
|
+
### File locations
|
|
550
|
+
|
|
551
|
+
Specialist configs and global overrides include:
|
|
552
|
+
- `config/specialists/<name>.specialist.json` (canonical)
|
|
553
|
+
- `.specialists/user/<name>.specialist.json` (repo user override fork, full spec)
|
|
554
|
+
- `~/.config/specialists/user.json` (global user override layer, sparse fields only, machine scope)
|
|
555
|
+
|
|
556
|
+
### Loading precedence (KAN-90)
|
|
557
|
+
|
|
558
|
+
Override merge is strict 3-layer policy:
|
|
559
|
+
|
|
560
|
+
1. **Package canonical** specialist from `config/specialists/<name>.specialist.json`
|
|
561
|
+
2. **Global user** sparse overrides from `~/.config/specialists/user.json`
|
|
562
|
+
3. **Repo user spec** from `.specialists/user/<name>.specialist.json`
|
|
563
|
+
|
|
564
|
+
Only allowed fields flow through global/repo override layers. Package canonical defines baseline behavior, then machine and repo layers may override safe fields (or append `skills.paths` values).
|
|
565
|
+
|
|
566
|
+
Blocked fields are still guarded:
|
|
567
|
+
- `execution.permission_required`
|
|
568
|
+
- `execution.auto_commit`
|
|
569
|
+
- `prompt.system`
|
|
570
|
+
- `prompt.output_schema`
|
|
571
|
+
- `skills.scripts`
|
|
572
|
+
- `mandatory_rules`
|
|
573
|
+
- `capabilities`
|
|
574
|
+
|
|
575
|
+
Allowed override fields include:
|
|
576
|
+
- `execution.model`, `execution.fallback_model`, `execution.timeout_ms`, `execution.stall_timeout_ms`, `execution.interactive`, `execution.thinking_level`, `execution.max_retries`, `execution.response_format`
|
|
577
|
+
- `execution.extensions.serena`, `execution.extensions.gitnexus`
|
|
578
|
+
- `specialist.stall_detection.waiting_auto_close_ms`
|
|
579
|
+
- `specialist.prompt.system_prompt_mode`
|
|
580
|
+
|
|
581
|
+
Global-layer blocked attempts are stripped at merge time; repo-layer blocked attempts are surfaced in `sp doctor --specialists`.
|
|
582
|
+
|
|
583
|
+
The loader keeps JSON-first with YAML fallback at each leaf source:
|
|
584
|
+
|
|
585
|
+
1. Look for `<name>.specialist.json` — use if found
|
|
586
|
+
2. Fall back to `<name>.specialist.yaml` — use if JSON missing (deprecated)
|
|
587
|
+
3. Emit warning to stderr when YAML is used:
|
|
588
|
+
```
|
|
589
|
+
[specialists] DEPRECATED: YAML specialist config detected at <path>. Please migrate to .specialist.json
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Migration from YAML
|
|
593
|
+
|
|
594
|
+
YAML configs remain functional but are deprecated. To migrate:
|
|
595
|
+
|
|
596
|
+
```bash
|
|
597
|
+
# YAML (deprecated)
|
|
598
|
+
config/specialists/executor.specialist.yaml
|
|
599
|
+
|
|
600
|
+
# JSON (preferred)
|
|
601
|
+
config/specialists/executor.specialist.json
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
JSON supports all YAML fields plus additional metadata:
|
|
605
|
+
- `author`: Config author
|
|
606
|
+
- `tags`: Array of categorization tags
|
|
607
|
+
- `created`: Creation date
|
|
608
|
+
- `output_type`: Expected output format
|
|
609
|
+
- `max_retries`: Retry count for transient failures
|
|
610
|
+
- `beads_write_notes`: Whether to write bead notes
|
|
611
|
+
- `communication`: Communication preferences
|
|
612
|
+
|
|
613
|
+
### Schema validation
|
|
614
|
+
|
|
615
|
+
All configs are validated against `src/specialist/schema.ts` at load time. Invalid configs are skipped with an error message.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
## 13) Auto GitNexus reindex after high-permission jobs
|
|
619
|
+
|
|
620
|
+
Supervisor automatically triggers a GitNexus reindex after jobs with elevated file access complete.
|
|
621
|
+
### Trigger conditions
|
|
622
|
+
|
|
623
|
+
```json
|
|
624
|
+
{
|
|
625
|
+
"specialist": {
|
|
626
|
+
"execution": {
|
|
627
|
+
"permission_required": "MEDIUM"
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
When `permission_required` is `MEDIUM` or `HIGH`
|
|
634
|
+
|
|
635
|
+
When `permission_required` is `MEDIUM` or `HIGH`, the supervisor spawns a detached `npx gitnexus analyze` process after job completion.
|
|
636
|
+
|
|
637
|
+
### Behavior
|
|
638
|
+
|
|
639
|
+
- **Detached execution**: reindex runs in background, does not block job completion
|
|
640
|
+
- **Working directory**: analyze runs in the job's worktree (if applicable) or main checkout
|
|
641
|
+
- **Timeline event**: emits a `meta` event with `model: "gitnexus_analyze_started"` or `model: "gitnexus_analyze_start_failed"`
|
|
642
|
+
- **Failure handling**: if spawn fails, error is logged to timeline but job still completes
|
|
643
|
+
|
|
644
|
+
### Example timeline events
|
|
645
|
+
|
|
646
|
+
```json
|
|
647
|
+
{"t": 1743883200000, "type": "meta", "model": "gitnexus_analyze_started", "backend": "supervisor"}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Rationale
|
|
651
|
+
|
|
652
|
+
High-permission specialists (`MEDIUM`/`HIGH`) typically modify source code. Auto-reindex ensures the GitNexus knowledge graph stays current without requiring manual intervention or separate CI steps.
|
|
653
|
+
|
|
654
|
+
### Disabling
|
|
655
|
+
|
|
656
|
+
To disable auto-reindex for a high-permission specialist, set `permission_required` to `LOW` or omit it (defaults to `LOW`).
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## 14) Debugger v2.0 — Keep-alive iterative debugging
|
|
661
|
+
|
|
662
|
+
The `debugger` specialist was upgraded to v2.0 with enhanced capabilities for iterative debug-fix-verify cycles.
|
|
663
|
+
|
|
664
|
+
### Configuration
|
|
665
|
+
|
|
666
|
+
```json
|
|
667
|
+
{
|
|
668
|
+
"specialist": {
|
|
669
|
+
"metadata": {
|
|
670
|
+
"name": "debugger",
|
|
671
|
+
"version": "2.0.0",
|
|
672
|
+
"description": "Autonomous debugger: given any symptom, error, or stack trace, systematically traces call chains with GitNexus, identifies root cause at file:line precision, applies targeted fixes, and verifies the fix works. Keep-alive for iterative debug-fix-verify cycles."
|
|
673
|
+
},
|
|
674
|
+
"execution": {
|
|
675
|
+
"permission_required": "HIGH",
|
|
676
|
+
"interactive": true
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
### Key changes in v2.0
|
|
683
|
+
|
|
684
|
+
| Feature | v1.0 | v2.0 |
|
|
685
|
+
|---------|------|------|
|
|
686
|
+
| Permission level | MEDIUM | **HIGH** |
|
|
687
|
+
| Keep-alive | No | **Yes** (`interactive: true`) |
|
|
688
|
+
| Workflow | Single-pass | **Iterative cycles** |
|
|
689
|
+
|
|
690
|
+
### Iterative workflow
|
|
691
|
+
|
|
692
|
+
1. **Initial run**: `sp run debugger --bead bd-123`
|
|
693
|
+
- Investigates root cause using GitNexus
|
|
694
|
+
- Applies targeted fix
|
|
695
|
+
- Verifies fix works
|
|
696
|
+
- Enters `waiting` state
|
|
697
|
+
|
|
698
|
+
2. **Resume if needed**: `sp resume <job-id> "Fix didn't work, error is now..."`
|
|
699
|
+
- Re-diagnoses with new evidence
|
|
700
|
+
- Applies corrected fix
|
|
701
|
+
- Re-verifies
|
|
702
|
+
- Returns to `waiting`
|
|
703
|
+
|
|
704
|
+
3. **Repeat** until issue is resolved
|
|
705
|
+
|
|
706
|
+
### When to use
|
|
707
|
+
|
|
708
|
+
- Complex bugs requiring multiple fix attempts
|
|
709
|
+
- Issues where the initial hypothesis may be wrong
|
|
710
|
+
- Debugging sessions that need human verification between attempts
|
|
711
|
+
|
|
712
|
+
### Observation
|
|
713
|
+
|
|
714
|
+
Use standard observation commands:
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
sp feed <job-id> --follow # Watch investigation progress
|
|
718
|
+
sp status --job <job-id> # Check waiting state
|
|
719
|
+
sp result <job-id> # Read bug report + resume footer
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## 15) Worktree isolation (`--worktree`, `--job`)
|
|
725
|
+
|
|
726
|
+
Each edit-permission specialist runs in an isolated git worktree (branch). This prevents concurrent file corruption when multiple executors modify overlapping paths, and produces a clean per-task branch that the orchestrator merges in dependency order.
|
|
727
|
+
|
|
728
|
+
### CLI flags
|
|
729
|
+
|
|
730
|
+
```bash
|
|
731
|
+
specialists run <name> [--worktree] [--job <id>]
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
| Flag | Semantics | Creates worktree? |
|
|
735
|
+
|------|-----------|:-:|
|
|
736
|
+
| `--worktree` | Explicitly provision a new isolated workspace; requires `--bead` | Yes |
|
|
737
|
+
| `--job <id>` | Reuse the workspace of an existing job | No |
|
|
738
|
+
|
|
739
|
+
`--worktree` and `--job` are **mutually exclusive**.
|
|
740
|
+
|
|
741
|
+
### Worktree guard (MEDIUM/HIGH permission specialists)
|
|
742
|
+
|
|
743
|
+
Specialists with `permission_required = MEDIUM` or `HIGH` and `requires_worktree: true` auto-provision an isolated worktree when `--bead` is provided and `--job` is not used. If no bead is supplied, the command exits with:
|
|
744
|
+
|
|
745
|
+
```
|
|
746
|
+
Error: specialist '<name>' has permission_required=<MEDIUM|HIGH> and requires worktree isolation.
|
|
747
|
+
Provide --bead <id> for automatic worktree provisioning, or use --job <id> to reuse an existing worktree.
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
### `requires_worktree` config flag
|
|
751
|
+
|
|
752
|
+
Specialists can opt out of the worktree guard by setting:
|
|
753
|
+
|
|
754
|
+
```json
|
|
755
|
+
{
|
|
756
|
+
"specialist": {
|
|
757
|
+
"execution": {
|
|
758
|
+
"requires_worktree": false
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
When `requires_worktree: false`:
|
|
765
|
+
- Worktree guard is bypassed even for MEDIUM/HIGH permission
|
|
766
|
+
- Specialist can write directly to the main checkout
|
|
767
|
+
- Use for workflow specialists that manage shared state (e.g. memory-processor writes `.xtrm/memory.md`)
|
|
768
|
+
|
|
769
|
+
**Default**: `requires_worktree: true` — all edit-capable specialists are gated.
|
|
770
|
+
|
|
771
|
+
`READ_ONLY` specialists are never gated.
|
|
772
|
+
|
|
773
|
+
### `--worktree` (new isolated workspace)
|
|
774
|
+
|
|
775
|
+
Requires `--bead <id>` — the bead id drives the deterministic branch name.
|
|
776
|
+
|
|
777
|
+
```bash
|
|
778
|
+
sp run executor --worktree --bead hgpu.3
|
|
779
|
+
# stderr: [worktree created: /repo/.worktrees/hgpu.3/hgpu.3-executor branch: feature/hgpu.3-executor]
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
If a worktree for that branch already exists (e.g. from a prior interrupted run) it is reused:
|
|
783
|
+
|
|
784
|
+
```bash
|
|
785
|
+
# stderr: [worktree reused: /repo/.worktrees/hgpu.3/hgpu.3-executor branch: feature/hgpu.3-executor]
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### `--job <id>` (reuse existing workspace)
|
|
789
|
+
|
|
790
|
+
Reads `worktree_path` from the target job's `status.json` and uses that directory as `cwd`. The **caller's** `--bead` remains authoritative — only the workspace is borrowed.
|
|
791
|
+
|
|
792
|
+
```bash
|
|
793
|
+
sp run reviewer --job 49adda --bead hgpu.3-review
|
|
794
|
+
# stderr: [workspace reused from job 49adda: /repo/.worktrees/hgpu.3/hgpu.3-executor]
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Hard fail conditions:
|
|
798
|
+
- `status.json` missing or unreadable for the given job id
|
|
799
|
+
- `worktree_path` absent — the target job was not started with `--worktree`
|
|
800
|
+
|
|
801
|
+
### Worktree GC
|
|
802
|
+
|
|
803
|
+
Clean up terminal job worktrees:
|
|
804
|
+
|
|
805
|
+
```bash
|
|
806
|
+
sp clean # prunes job dirs AND terminal worktrees
|
|
807
|
+
sp clean --dry-run # preview removals without deleting
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
GC candidates must satisfy all conditions:
|
|
811
|
+
1. Job status is `done` or `error` (terminal)
|
|
812
|
+
2. `worktree_path` is recorded in `status.json`
|
|
813
|
+
3. The directory still exists on disk
|
|
814
|
+
4. Job status is **not** `starting`, `running`, or `waiting`
|
|
815
|
+
|
|
816
|
+
For full technical details, see [worktrees.md](worktrees.md).
|
|
817
|
+
|
|
818
|
+
---
|
|
819
|
+
## 16) Context denormalization in `status.json`
|
|
820
|
+
|
|
821
|
+
Context utilization fields are denormalized directly into `status.json` on every `turn_summary` event, so any consumer reading `status.json` gets the latest context percentage without having to scan `events.jsonl`.
|
|
822
|
+
|
|
823
|
+
### Fields
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
interface SupervisorStatus {
|
|
827
|
+
// ... existing fields ...
|
|
828
|
+
context_pct?: number; // context window utilization (0-100)
|
|
829
|
+
context_health?: 'OK' | 'MONITOR' | 'WARN' | 'CRITICAL';
|
|
830
|
+
}
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Health classification thresholds
|
|
834
|
+
|
|
835
|
+
| Range | Health |
|
|
836
|
+
|-------|--------|
|
|
837
|
+
| < 40% | `OK` |
|
|
838
|
+
| 40–65% | `MONITOR` |
|
|
839
|
+
| 65–80% | `WARN` |
|
|
840
|
+
| > 80% | `CRITICAL` |
|
|
841
|
+
|
|
842
|
+
### Model context windows
|
|
843
|
+
|
|
844
|
+
| Model pattern | Window |
|
|
845
|
+
|---------------|--------|
|
|
846
|
+
| `gemini-3.1-pro` | 1M tokens |
|
|
847
|
+
| `qwen3.5` / `glm-5` | 128K tokens |
|
|
848
|
+
| `claude` | 200K tokens |
|
|
849
|
+
|
|
850
|
+
### Where context is surfaced
|
|
851
|
+
|
|
852
|
+
- `sp status` / `sp status --job <id>` — renders `context_pct` and `context_health`
|
|
853
|
+
- `sp ps` — shows `ctx%` column on every job row (from `status.json` directly)
|
|
854
|
+
- `sp feed` — prints WARN/CRITICAL banners when thresholds are crossed
|
|
855
|
+
- `sp ps --json` — includes `context_pct` and `context_health` in `flat[]` array
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
## 17) Job lineage tracking (`reused_from_job_id`, `worktree_owner_job_id`)
|
|
860
|
+
|
|
861
|
+
When `--job <id>` is used, the new job records two lineage fields in its `status.json`. These enable `sp ps` to reconstruct worktree trees reliably without guessing from directory paths.
|
|
862
|
+
|
|
863
|
+
### Fields
|
|
864
|
+
|
|
865
|
+
```typescript
|
|
866
|
+
interface SupervisorStatus {
|
|
867
|
+
reused_from_job_id?: string; // the job whose workspace was borrowed via --job
|
|
868
|
+
worktree_owner_job_id?: string; // the root job that owns the worktree
|
|
869
|
+
}
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
### Semantics
|
|
873
|
+
|
|
874
|
+
| Field | Set when | Value |
|
|
875
|
+
|-------|----------|-------|
|
|
876
|
+
| `reused_from_job_id` | `--job <id>` is used | The explicit `--job` argument |
|
|
877
|
+
| `worktree_owner_job_id` | `--job <id>` is used | The transitive root owner of the worktree: resolves `worktree_owner_job_id` from the target status, falling back to the target job's `id` |
|
|
878
|
+
|
|
879
|
+
### Example
|
|
880
|
+
|
|
881
|
+
```bash
|
|
882
|
+
# Executor provisions the worktree (owner)
|
|
883
|
+
sp run executor --worktree --bead unitAI-55d
|
|
884
|
+
# → job a1b2c3, worktree_owner_job_id=a1b2c3
|
|
885
|
+
|
|
886
|
+
# Reviewer reuses the executor's workspace
|
|
887
|
+
sp run reviewer --job a1b2c3 --bead unitAI-55d-review
|
|
888
|
+
# → new job d4e5f6, reused_from_job_id=a1b2c3, worktree_owner_job_id=a1b2c3
|
|
889
|
+
|
|
890
|
+
# Second reviewer reuses the first reviewer's job (chained reuse)
|
|
891
|
+
sp run validator --job d4e5f6 --bead unitAI-55d-validate
|
|
892
|
+
# → new job g7h8i9, reused_from_job_id=d4e5f6, worktree_owner_job_id=a1b2c3 (resolved transitively)
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### Tree reconstruction in `sp ps`
|
|
896
|
+
|
|
897
|
+
`sp ps` groups all jobs sharing the same `worktree_owner_job_id` into one worktree tree. Jobs are further arranged as a reuse forest: parent → child edges follow `reused_from_job_id` pointers.
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
## 18) `sp merge`: per-chain publication
|
|
902
|
+
|
|
903
|
+
`sp merge` publishes a single chain. The original "refuse if epic unresolved" inverted gate was removed in the chain-lifecycle redesign — per-chain merge is now allowed for any PASS chain regardless of sibling-epic state. Use `sp epic merge` only when batching all epic chains together.
|
|
904
|
+
|
|
905
|
+
### When `sp merge` accepts a chain
|
|
906
|
+
|
|
907
|
+
- Chain has reviewer PASS verdict in its terminal state.
|
|
908
|
+
- All chain jobs are terminal (executor closed via auto-finalize-on-streaming-PASS or `sp finalize <any-chain-job-id>` cascade).
|
|
909
|
+
- Epic membership is allowed; the chain merges incrementally regardless of sibling state.
|
|
910
|
+
- Epic has not been explicitly `merged` or `abandoned` (those two are the only blocking terminal states).
|
|
911
|
+
|
|
912
|
+
### Scope
|
|
913
|
+
|
|
914
|
+
**What it does**:
|
|
915
|
+
- Merge a single chain-root branch (one bead → one branch)
|
|
916
|
+
- Run TypeScript gate after merge
|
|
917
|
+
- Optional rebuild (`--rebuild`) after merge
|
|
918
|
+
- Optional PR mode (`--pr`)
|
|
919
|
+
|
|
920
|
+
**What it does NOT include**:
|
|
921
|
+
- Atomic batch publish across multiple chains (use `sp epic merge`)
|
|
922
|
+
- Topological dependency ordering across chains (use `sp epic merge`)
|
|
923
|
+
- Worktree cleanup after merge
|
|
924
|
+
- Conflict auto-resolution
|
|
925
|
+
|
|
926
|
+
### Vocabulary
|
|
927
|
+
|
|
928
|
+
| Term | Definition |
|
|
929
|
+
|------|------------|
|
|
930
|
+
| **Epic** | Top merge-gated identity with state machine. Use `sp epic merge` for publication. |
|
|
931
|
+
| **Chain** | Worktree lineage (`chain_kind: 'chain'`), seeded by edit-capable specialist. |
|
|
932
|
+
| **Prep** | Standalone job without worktree lineage (`chain_kind: 'prep'`). |
|
|
933
|
+
| **Wave** | Stage/batch label — speech only, no code meaning. |
|
|
934
|
+
| **Job** | Atomic execution unit. Jobs belong to chains or are prep. |
|
|
935
|
+
|
|
936
|
+
### Command
|
|
937
|
+
|
|
938
|
+
```bash
|
|
939
|
+
sp merge <chain-root-bead-id> [--rebuild]
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
- `<chain-root-bead-id>`: A **chain-root bead**. **Must NOT belong to an unresolved epic.**
|
|
943
|
+
- `--rebuild`: run `bun run build` after merge
|
|
944
|
+
|
|
945
|
+
### Safety
|
|
946
|
+
|
|
947
|
+
- Non-terminal jobs block merge (`starting`, `running` statuses)
|
|
948
|
+
- Epic guard blocks if chain belongs to unresolved epic
|
|
949
|
+
- **Merge-preview worthiness guard** — blocks empty-delta and noise-only-delta branches (see [cli-reference.md#merge-preview-worthiness-guard](cli-reference.md#merge-preview-worthiness-guard))
|
|
950
|
+
- TypeScript gate after merge
|
|
951
|
+
- Uses `--no-ff` to preserve branch history
|
|
952
|
+
|
|
953
|
+
### File listing
|
|
954
|
+
|
|
955
|
+
Merge output uses `git diff HEAD^1 HEAD` for accurate changed-file reporting (not `git diff-tree`).
|
|
956
|
+
|
|
957
|
+
### Example
|
|
958
|
+
|
|
959
|
+
```bash
|
|
960
|
+
# Standalone chain merge (epic guard must pass)
|
|
961
|
+
sp merge unitAI-55d
|
|
962
|
+
# → merges branch feature/unitAI-55d-executor
|
|
963
|
+
|
|
964
|
+
# PR mode
|
|
965
|
+
sp merge unitAI-55d --pr
|
|
966
|
+
# → creates PR instead of direct merge
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
### Implementation
|
|
970
|
+
|
|
971
|
+
Source: `src/cli/merge.ts`
|
|
972
|
+
|
|
973
|
+
Key functions:
|
|
974
|
+
- `resolveMergeTargets()` — resolve bead to chain
|
|
975
|
+
- `resolveChainEpicMembership()` — epic guard check
|
|
976
|
+
- `mergeBranch()` — git merge with conflict detection
|
|
977
|
+
- `runTypecheckGate()` — tsc validation
|
|
978
|
+
|
|
979
|
+
---
|
|
980
|
+
|
|
981
|
+
## 19) `sp epic merge`: canonical publication for wave-bound chains
|
|
982
|
+
|
|
983
|
+
`sp epic merge` is the canonical publication path for wave-bound chain groups.
|
|
984
|
+
|
|
985
|
+
### Synopsis
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
sp epic merge <epic-id> [--pr] [--rebuild] [--json]
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
### Behavior
|
|
992
|
+
|
|
993
|
+
1. Reads epic record from observability SQLite (refuses only on `merged` / `abandoned`)
|
|
994
|
+
2. Computes readiness live from chain state (no operator-driven `resolving → merge_ready` transition needed)
|
|
995
|
+
3. Verifies all chains are terminal (executor finalized via auto-finalize-on-streaming-PASS or `sp finalize` cascade)
|
|
996
|
+
4. Verifies latest reviewer verdict is PASS for each chain (matches plain or markdown-bold format)
|
|
997
|
+
5. Topologically sorts chains by bead dependencies
|
|
998
|
+
6. For each chain: `git merge <branch> --no-ff --no-edit`
|
|
999
|
+
7. Runs `bunx tsc --noEmit` after each merge
|
|
1000
|
+
8. Creates PRs if `--pr` is set
|
|
1001
|
+
9. Persists `merged` on success; on transient failure (rebase conflict, dirty worktree) writes a soft `failed` marker that the next attempt clears automatically
|
|
1002
|
+
|
|
1003
|
+
### Epic lifecycle (derived model)
|
|
1004
|
+
|
|
1005
|
+
```
|
|
1006
|
+
chains in flight ──── derive ──── blocked / failed / merge_ready
|
|
1007
|
+
│
|
|
1008
|
+
├── merged (persisted, terminal)
|
|
1009
|
+
└── abandoned (persisted, terminal)
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
Only `merged` and `abandoned` are persisted as terminal markers. `blocked`, `failed`, and `merge_ready` are recomputed live from chain readiness on every read. A persisted soft `failed` marker (from a transient publish failure) is recoverable — the next `sp epic merge` retries fresh.
|
|
1013
|
+
|
|
1014
|
+
See `docs/cli-reference.md` and `docs/ARCHITECTURE.md` §10 for the full derived-readiness rules.
|
|
1015
|
+
|
|
1016
|
+
### Examples
|
|
1017
|
+
|
|
1018
|
+
```bash
|
|
1019
|
+
# Check readiness first
|
|
1020
|
+
sp epic status unitAI-3f7b
|
|
1021
|
+
|
|
1022
|
+
# Publish all chains
|
|
1023
|
+
sp epic merge unitAI-3f7b
|
|
1024
|
+
|
|
1025
|
+
# PR mode
|
|
1026
|
+
sp epic merge unitAI-3f7b --pr
|
|
1027
|
+
|
|
1028
|
+
# Rebuild after merge
|
|
1029
|
+
sp epic merge unitAI-3f7b --rebuild
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
---
|
|
1033
|
+
|
|
1034
|
+
## 20) `sp end`: epic-aware session close
|
|
1035
|
+
|
|
1036
|
+
`sp end` integrates with epic lifecycle for publication.
|
|
1037
|
+
|
|
1038
|
+
### Synopsis
|
|
1039
|
+
|
|
1040
|
+
```bash
|
|
1041
|
+
sp end [--bead <id>|--epic <id>] [--pr] [--rebuild]
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
### Behavior
|
|
1045
|
+
|
|
1046
|
+
1. **Epic redirect**: If `--epic <id>` provided, delegates to `sp epic merge <id>`
|
|
1047
|
+
2. **Epic guard**: If current chain belongs to unresolved epic, auto-redirects to `sp epic merge`
|
|
1048
|
+
3. **Chain merge**: For standalone chains, publishes the branch
|
|
1049
|
+
|
|
1050
|
+
### Example
|
|
1051
|
+
|
|
1052
|
+
```bash
|
|
1053
|
+
# Epic publication
|
|
1054
|
+
sp end --epic unitAI-3f7b --pr
|
|
1055
|
+
# → delegates to: sp epic merge unitAI-3f7b --pr
|
|
1056
|
+
|
|
1057
|
+
# Chain in unresolved epic (auto-detect)
|
|
1058
|
+
sp end
|
|
1059
|
+
# Chain unitAI-impl belongs to unresolved epic unitAI-3f7b (resolving).
|
|
1060
|
+
# Redirecting to: sp epic merge unitAI-3f7b
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## 21) Chain identity: chain vs prep jobs
|
|
1066
|
+
|
|
1067
|
+
Jobs are classified as `chain` or `prep` based on worktree lineage.
|
|
1068
|
+
|
|
1069
|
+
### Kinds
|
|
1070
|
+
|
|
1071
|
+
| Kind | Definition | Has worktree? |
|
|
1072
|
+
|------|------------|:-------------:|
|
|
1073
|
+
| `chain` | Worktree lineage seeded by edit-capable specialist | Yes |
|
|
1074
|
+
| `prep` | Standalone job without worktree lineage | No |
|
|
1075
|
+
|
|
1076
|
+
### Derivation
|
|
1077
|
+
|
|
1078
|
+
```typescript
|
|
1079
|
+
// Automatic classification from status fields
|
|
1080
|
+
const isChainJob = Boolean(
|
|
1081
|
+
status.worktree_path || status.worktree_owner_job_id || status.chain_id
|
|
1082
|
+
);
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
### Fields in status.json
|
|
1086
|
+
|
|
1087
|
+
- `chain_kind` — 'chain' or 'prep'
|
|
1088
|
+
- `chain_id` — unique identifier
|
|
1089
|
+
- `chain_root_job_id` — root worktree owner
|
|
1090
|
+
- `chain_root_bead_id` — seeding bead
|
|
1091
|
+
|
|
1092
|
+
---
|
|
1093
|
+
|
|
1094
|
+
## 22) Crash recovery for zombie jobs
|
|
1095
|
+
|
|
1096
|
+
`crashRecovery()` runs at Supervisor startup and reconciles orphaned job states:
|
|
1097
|
+
|
|
1098
|
+
**Dead running/starting jobs**:
|
|
1099
|
+
- Dead PID + non-node → status becomes `error` ("Process crashed or was killed")
|
|
1100
|
+
- Dead PID + node member → status becomes `waiting` ("recovery_pending") — preserved for NodeSupervisor
|
|
1101
|
+
|
|
1102
|
+
**Dead waiting jobs**:
|
|
1103
|
+
- Emits `stale_warning` event if idle past `waiting_stale_ms` threshold
|
|
1104
|
+
- If `waiting_auto_close_ms` is set, stale waiting jobs request graceful close first, then forced termination fallback if close hangs
|
|
1105
|
+
- Default remains recoverable waiting sessions when `waiting_auto_close_ms` is unset/0
|
|
1106
|
+
- Node members preserved for NodeSupervisor recovery
|
|
1107
|
+
|
|
1108
|
+
**`hasRunCompleteEvent()`**:
|
|
1109
|
+
|
|
1110
|
+
Used by `sp stop` to resolve terminal status:
|
|
1111
|
+
```typescript
|
|
1112
|
+
// SQLite-first, then events.jsonl fallback
|
|
1113
|
+
export function hasRunCompleteEvent(jobId: string): boolean;
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
---
|
|
1117
|
+
|
|
1118
|
+
## 23) Epic chain membership auto-sync
|
|
1119
|
+
|
|
1120
|
+
Supervisor automatically syncs epic chain membership on job completion:
|
|
1121
|
+
|
|
1122
|
+
**Trigger**: Both success (`done`) and error paths
|
|
1123
|
+
|
|
1124
|
+
**Actions**:
|
|
1125
|
+
1. `upsertEpicChainMembership()` — persist chain→epic linkage
|
|
1126
|
+
2. `loadEpicReadinessSummary()` — recompute readiness state
|
|
1127
|
+
3. `syncEpicStateFromReadiness()` — update epic state machine
|
|
1128
|
+
|
|
1129
|
+
This ensures epic readiness is always current without manual sync steps.
|
|
1130
|
+
|
|
1131
|
+
---
|
|
1132
|
+
|
|
1133
|
+
## 24) Worktree write-boundary enforcement
|
|
1134
|
+
|
|
1135
|
+
When a specialist runs with `--worktree`, the pi session enforces a **write-boundary** on tool calls. This prevents accidental modifications to files outside the isolated worktree.
|
|
1136
|
+
|
|
1137
|
+
### Intercepted tools
|
|
1138
|
+
|
|
1139
|
+
| Tool | Intercepted? | Behavior on out-of-bounds absolute path |
|
|
1140
|
+
|------|:-------------:|------------------------------------------|
|
|
1141
|
+
| `edit` | ✓ Yes | Blocked with reason — tool call rejected |
|
|
1142
|
+
| `write` | ✓ Yes | Blocked with reason |
|
|
1143
|
+
| `multiEdit` | ✓ Yes | Blocked with reason |
|
|
1144
|
+
| `notebookEdit` | ✓ Yes | Blocked with reason |
|
|
1145
|
+
| `read` | ✗ No | Allowed (read-only, no corruption risk) |
|
|
1146
|
+
| `bash` | ✗ No | Allowed (command execution, not file write) |
|
|
1147
|
+
|
|
1148
|
+
### Boundary semantics
|
|
1149
|
+
|
|
1150
|
+
- **Worktree root**: from `SPECIALISTS_WORKTREE_BOUNDARY` env var (set by the runner from `worktree_path` recorded in `status.json`)
|
|
1151
|
+
- **In-bounds path**: any path that resolves to a location under worktree root
|
|
1152
|
+
- **Out-of-bounds path**: any absolute path resolving outside worktree root
|
|
1153
|
+
- **Relative paths**: not intercepted — they resolve against the specialist's cwd, which is the worktree root
|
|
1154
|
+
|
|
1155
|
+
### Block behavior
|
|
1156
|
+
|
|
1157
|
+
When a write tool is called with an out-of-bounds absolute path:
|
|
1158
|
+
1. The tool call is **blocked** before reaching the file system.
|
|
1159
|
+
2. The specialist receives a structured rejection: `{ block: true, reason: "Path '<X>' is outside worktree boundary ('<root>'). Use a relative path or a path within the worktree." }`.
|
|
1160
|
+
3. No file is created, no tmp-fs redirect, no silent success.
|
|
1161
|
+
4. The specialist sees the reason and is expected to retry with a worktree-relative path.
|
|
1162
|
+
|
|
1163
|
+
This design prevents:
|
|
1164
|
+
- Specialists accidentally modifying main checkout files
|
|
1165
|
+
- Parallel specialists racing on shared files
|
|
1166
|
+
- Escape via absolute paths (LLMs commonly generate these from context memory)
|
|
1167
|
+
|
|
1168
|
+
### Why this matters
|
|
1169
|
+
|
|
1170
|
+
Without write-boundary enforcement, specialists in worktrees could:
|
|
1171
|
+
1. Generate absolute paths from session context (e.g. `/home/user/project/src/file.ts`)
|
|
1172
|
+
2. Modify files in the main repo, bypassing worktree isolation
|
|
1173
|
+
3. Create race conditions with other specialists or the operator
|
|
1174
|
+
|
|
1175
|
+
This was observed in production (2026-04-09): sync-docs specialist in worktree `.worktrees/8we6/8we6-sync-docs/` emitted edit calls with absolute paths pointing to main repo. All 6 doc edits landed in main repo instead of the worktree — isolation was completely bypassed.
|
|
1176
|
+
|
|
1177
|
+
### Implementation
|
|
1178
|
+
|
|
1179
|
+
Enforcement lives in pi session layer (not specialists code):
|
|
1180
|
+
- Commit: `da9ac9e3` (elhl/a2u7 Phase 1)
|
|
1181
|
+
- Applied at tool invocation boundary
|
|
1182
|
+
- Path resolution checks against declared `worktree_path`
|
|
1183
|
+
|
|
1184
|
+
### Limitations
|
|
1185
|
+
|
|
1186
|
+
- `Bash` commands are not intercepted — a `bash` tool call invoking `cp`, `mv`, or shell redirection can still write outside the worktree.
|
|
1187
|
+
- Relative paths are not checked — they resolve against the specialist's cwd. Escape via `..` traversal is possible if the specialist explicitly does so; in practice the worktree boundary catches the absolute-path failure mode that motivated this enforcement.
|
|
1188
|
+
- Only `path` and `file_path` input fields are inspected; tools with non-standard input keys are not covered.
|
|
1189
|
+
|
|
1190
|
+
---
|
|
1191
|
+
|
|
1192
|
+
## 25) Memory injection at specialist spawn
|
|
1193
|
+
|
|
1194
|
+
Runner injects project context at specialist spawn using keyword-filtered memory retrieval from a local SQLite FTS cache. This replaced the previous full `bd prime` dump (~3000 tokens) with targeted retrieval (~600 tokens max).
|
|
1195
|
+
|
|
1196
|
+
### Injection pipeline
|
|
1197
|
+
|
|
1198
|
+
| # | Source | Tokens | Condition | Purpose |
|
|
1199
|
+
|---|--------|--------|-----------|--------|
|
|
1200
|
+
| 0 | Caveman-micro output directive | ~80 | Always | Terse output style (+26pp accuracy, ~65% token savings) |
|
|
1201
|
+
| 1 | GitNexus workflow mandate | ~200 | `.gitnexus/meta.json` exists | Code intelligence usage rules |
|
|
1202
|
+
| — | `.xtrm/memory.md` | — | Injected by xtrm Pi extension, not runner | Saves ~800 tokens per spawn |
|
|
1203
|
+
| 2 | Static workflow rules | ~60 | Always | `STATIC_WORKFLOW_RULES_BLOCK` from `memory-retrieval.ts` |
|
|
1204
|
+
| 3 | Keyword-filtered memories | ~0-600 | `--bead <id>` provided | FTS query on bead title/description keywords |
|
|
1205
|
+
| 4 | GitNexus pre-query snapshot | ~0-200 | `.gitnexus/` exists + CamelCase tokens in bead title | Caller/callee summaries |
|
|
1206
|
+
|
|
1207
|
+
### Keyword-filtered memory retrieval
|
|
1208
|
+
|
|
1209
|
+
`src/specialist/memory-retrieval.ts` provides `buildFilteredMemoryInjection()`:
|
|
1210
|
+
|
|
1211
|
+
1. Extract keywords from bead title + description (max 6, stop-word filtered)
|
|
1212
|
+
2. Query FTS cache (`specialist_memories_cache` SQLite table) for matching `bd memories`
|
|
1213
|
+
3. Return top matches within 600-token budget
|
|
1214
|
+
|
|
1215
|
+
Key parameters:
|
|
1216
|
+
- `MAX_KEYWORDS = 6`
|
|
1217
|
+
- `MAX_MEMORIES = 10`
|
|
1218
|
+
- `MAX_MEMORY_TOKENS = 600`
|
|
1219
|
+
- `CACHE_MAX_AGE_MS = 3600000` (1 hour)
|
|
1220
|
+
|
|
1221
|
+
### FTS cache sync triggers
|
|
1222
|
+
|
|
1223
|
+
| Trigger | Type |
|
|
1224
|
+
|---------|------|
|
|
1225
|
+
| `specialists init` | Full bootstrap sync |
|
|
1226
|
+
| `PostToolUse` hook (`specialists-memory-cache-sync.mjs`) | Incremental after memory mutations |
|
|
1227
|
+
| `sp memory sync [--force]` | Manual CLI sync |
|
|
1228
|
+
| `sp memory refresh` | Invalidate + full rebuild |
|
|
1229
|
+
|
|
1230
|
+
### Extension opt-out
|
|
1231
|
+
|
|
1232
|
+
Specialists can disable specific npm extensions:
|
|
1233
|
+
|
|
1234
|
+
```json
|
|
1235
|
+
{
|
|
1236
|
+
"execution": {
|
|
1237
|
+
"extensions": {
|
|
1238
|
+
"serena": false,
|
|
1239
|
+
"gitnexus": false
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
### `memory_injection` timeline event
|
|
1246
|
+
|
|
1247
|
+
Every spawn emits a `meta` event with `model: "memory_injection"` recording token accounting:
|
|
1248
|
+
|
|
1249
|
+
```json
|
|
1250
|
+
{
|
|
1251
|
+
"memory_injection": {
|
|
1252
|
+
"static_tokens": 60,
|
|
1253
|
+
"memory_tokens": 400,
|
|
1254
|
+
"gitnexus_tokens": 150,
|
|
1255
|
+
"total_tokens": 610
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
### Non-fatal behavior
|
|
1261
|
+
|
|
1262
|
+
All injection sources are non-fatal:
|
|
1263
|
+
- Missing FTS cache → no keyword-filtered memories (static rules still inject)
|
|
1264
|
+
- `.gitnexus/meta.json` missing → no GitNexus mandate or pre-query
|
|
1265
|
+
- GitNexus CLI unavailable → pre-query skipped silently
|
|
1266
|
+
|
|
1267
|
+
---
|
|
1268
|
+
|
|
1269
|
+
## 26) Edit gate bead-claim KV pattern
|
|
1270
|
+
|
|
1271
|
+
The edit gate hooks check two KV keys before allowing file edits:
|
|
1272
|
+
|
|
1273
|
+
### Primary: session-scoped claim
|
|
1274
|
+
|
|
1275
|
+
```bash
|
|
1276
|
+
bd kv set "claimed:<session-id>" "<bead-id>"
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
Set by Claude Code hooks when an agent claims a bead. Session-bound, cleared on session end.
|
|
1280
|
+
|
|
1281
|
+
### Fallback: bead-claim
|
|
1282
|
+
|
|
1283
|
+
```bash
|
|
1284
|
+
bd kv set "bead-claim:<bead-id>" "active"
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
Set by Runner **before spawning a specialist** when `--bead <id>` is provided. Enables worktree specialists to edit without requiring a session-scoped claim.
|
|
1288
|
+
|
|
1289
|
+
### Lifecycle
|
|
1290
|
+
|
|
1291
|
+
```typescript
|
|
1292
|
+
// Before specialist spawn (run.ts)
|
|
1293
|
+
if (args.beadId && workingDirectory) {
|
|
1294
|
+
execSync(`bd kv set "bead-claim:${args.beadId}" "active"`);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// After specialist completes (success or error)
|
|
1298
|
+
if (args.beadId && workingDirectory) {
|
|
1299
|
+
execSync(`bd kv clear "bead-claim:${args.beadId}"`);
|
|
1300
|
+
}
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
**Why this matters**: Worktree specialists run in subprocesses without session context. The bead-claim pattern provides an edit gate entry that:
|
|
1304
|
+
1. Is independent of session IDs
|
|
1305
|
+
2. Is scoped to the specific bead being worked on
|
|
1306
|
+
3. Is automatically cleaned up when the run completes
|
|
1307
|
+
|
|
1308
|
+
---
|
|
1309
|
+
|
|
1310
|
+
## 27) Auto-append bead notes for ALL specialists
|
|
1311
|
+
|
|
1312
|
+
Supervisor now auto-appends full specialist output to the **input bead** on every `run_complete` event. This applies to **all specialists**, not just READ_ONLY.
|
|
1313
|
+
|
|
1314
|
+
### Behavior
|
|
1315
|
+
|
|
1316
|
+
For specialists with `--bead <id>`:
|
|
1317
|
+
- **First turn**: output appended with `[WAITING]` header if keep-alive and non-terminal
|
|
1318
|
+
- **Subsequent turns**: output appended after each resume turn completes
|
|
1319
|
+
- **Terminal completion**: output appended with `[DONE]` header
|
|
1320
|
+
|
|
1321
|
+
### Format
|
|
1322
|
+
|
|
1323
|
+
```markdown
|
|
1324
|
+
### Specialist Output — executor (job 49adda) [WAITING]
|
|
1325
|
+
|
|
1326
|
+
<full assistant output>
|
|
1327
|
+
|
|
1328
|
+
---
|
|
1329
|
+
timestamp=2026-04-13T10:30:00Z
|
|
1330
|
+
status=waiting
|
|
1331
|
+
prompt_hash=abc123
|
|
1332
|
+
git_sha=def456
|
|
1333
|
+
elapsed_ms=45678
|
|
1334
|
+
model=gpt-5.3-codex
|
|
1335
|
+
backend=openai-codex
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
Status labels:
|
|
1339
|
+
- `WAITING — more output may follow` — keep-alive session awaiting resume
|
|
1340
|
+
- `DONE` — terminal completion
|
|
1341
|
+
- `ERROR` — failed completion
|
|
1342
|
+
|
|
1343
|
+
### Implementation
|
|
1344
|
+
|
|
1345
|
+
Commit: `428cd7f7`
|
|
1346
|
+
- `formatBeadNotes()` — enriched with specialist name, job ID, status label, timestamp
|
|
1347
|
+
- `appendResultToInputBead()` — called on every `run_complete` (not just terminal)
|
|
1348
|
+
- `BeadsClient.updateBeadNotes()` — returns `{ ok, error }` instead of void
|
|
1349
|
+
|
|
1350
|
+
---
|
|
1351
|
+
|
|
1352
|
+
## 28) Auto-commit worktree changes (checkpoint policy)
|
|
1353
|
+
|
|
1354
|
+
Specialists with `auto_commit: checkpoint_on_waiting` or `checkpoint_on_terminal` automatically commit substantive worktree changes at designated lifecycle points.
|
|
1355
|
+
|
|
1356
|
+
### Policy options
|
|
1357
|
+
|
|
1358
|
+
| Policy | Trigger | Use case |
|
|
1359
|
+
|--------|---------|----------|
|
|
1360
|
+
| `never` | Never | Default — no auto-commit |
|
|
1361
|
+
| `checkpoint_on_waiting` | Each keep-alive turn entering `waiting` | Executors, debuggers — preserve partial work before review |
|
|
1362
|
+
| `checkpoint_on_terminal` | Terminal completion (`done`/`error`) | One-shot specialists — commit only at end |
|
|
1363
|
+
|
|
1364
|
+
### Configuration
|
|
1365
|
+
|
|
1366
|
+
```json
|
|
1367
|
+
{
|
|
1368
|
+
"specialist": {
|
|
1369
|
+
"execution": {
|
|
1370
|
+
"auto_commit": "checkpoint_on_waiting"
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
```
|
|
1375
|
+
|
|
1376
|
+
Built-in defaults:
|
|
1377
|
+
- **executor**: `checkpoint_on_waiting`
|
|
1378
|
+
- **debugger**: `checkpoint_on_waiting`
|
|
1379
|
+
|
|
1380
|
+
### Noise filtering
|
|
1381
|
+
|
|
1382
|
+
Auto-commit ignores paths matching:
|
|
1383
|
+
- `.xtrm/`
|
|
1384
|
+
- `.wolf/`
|
|
1385
|
+
- `.specialists/jobs/`
|
|
1386
|
+
- `.beads/`
|
|
1387
|
+
|
|
1388
|
+
Only **substantive files** (source, config, docs) are committed.
|
|
1389
|
+
|
|
1390
|
+
### Commit message format
|
|
1391
|
+
|
|
1392
|
+
```
|
|
1393
|
+
checkpoint(executor): unitAI-55d turn 1
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
### Timeline events
|
|
1397
|
+
|
|
1398
|
+
```json
|
|
1399
|
+
{"type": "auto_commit_success", "commit_sha": "abc123", "committed_files": ["src/cli/run.ts"]}
|
|
1400
|
+
{"type": "auto_commit_skipped", "reason": "no_substantive_changes"}
|
|
1401
|
+
{"type": "auto_commit_failed", "reason": "git commit failed"}
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
### Status fields
|
|
1405
|
+
|
|
1406
|
+
```typescript
|
|
1407
|
+
interface SupervisorStatus {
|
|
1408
|
+
auto_commit_count?: number; // cumulative checkpoints this run
|
|
1409
|
+
last_auto_commit_sha?: string; // SHA of most recent checkpoint
|
|
1410
|
+
last_auto_commit_at_ms?: number; // timestamp of most recent checkpoint
|
|
1411
|
+
}
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
### Implementation
|
|
1415
|
+
|
|
1416
|
+
Commit: `11e9b016`
|
|
1417
|
+
- `runAutoCommitCheckpoint()` — substantive file detection, git add + commit, SHA capture
|
|
1418
|
+
- `applyAutoCommitCheckpoint()` — called after `run_complete` on waiting/terminal transitions
|
|
1419
|
+
- Timeline: `auto_commit_success/skipped/failed` events
|
|
1420
|
+
- Schema: `execution.auto_commit` field
|
|
1421
|
+
|
|
1422
|
+
---
|
|
1423
|
+
|
|
1424
|
+
## 29) Stale-base guard — rebase at merge + block at dispatch
|
|
1425
|
+
|
|
1426
|
+
Two-layer protection against parallel-chain divergence:
|
|
1427
|
+
|
|
1428
|
+
### Layer 1: Dispatch-time guard
|
|
1429
|
+
|
|
1430
|
+
When `--worktree` provisions a new worktree, the stale-base guard checks for sibling chains with unmerged substantive commits:
|
|
1431
|
+
|
|
1432
|
+
```
|
|
1433
|
+
Error: Epic 'unitAI-3f7b' has sibling chains with unmerged changes.
|
|
1434
|
+
- impl-a: 2 substantive commits on 'feature/unitAI-impl-a-executor'
|
|
1435
|
+
- impl-b: 3 substantive commits on 'feature/unitAI-impl-b-executor'
|
|
1436
|
+
Merge sibling chains first via 'sp epic merge unitAI-3f7b', or use --force-stale-base to bypass.
|
|
1437
|
+
```
|
|
1438
|
+
|
|
1439
|
+
**Bypass**: `--force-stale-base` flag forces provisioning at caller's risk.
|
|
1440
|
+
|
|
1441
|
+
### Layer 2: Merge-time rebase
|
|
1442
|
+
|
|
1443
|
+
Before merging each chain (via `sp merge` or `sp epic merge`), the branch is rebased onto master inside the worktree:
|
|
1444
|
+
|
|
1445
|
+
```bash
|
|
1446
|
+
git rebase master # runs in worktree cwd
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
If rebase fails with conflicts:
|
|
1450
|
+
|
|
1451
|
+
```
|
|
1452
|
+
Error: Rebase failed for 'feature/unitAI-impl-a-executor' onto 'master'.
|
|
1453
|
+
Conflicting files:
|
|
1454
|
+
- src/cli/run.ts
|
|
1455
|
+
- src/specialist/supervisor.ts
|
|
1456
|
+
Resolve conflicts manually in that worktree, then re-run merge.
|
|
1457
|
+
```
|
|
1458
|
+
|
|
1459
|
+
Abort is automatic (`git rebase --abort`) — no partial rebase state remains.
|
|
1460
|
+
|
|
1461
|
+
### Why this matters
|
|
1462
|
+
|
|
1463
|
+
Parallel chains branched from the same base diverge:
|
|
1464
|
+
|
|
1465
|
+
1. Wave A branches from master at commit X
|
|
1466
|
+
2. Wave B branches from master at commit X (same base)
|
|
1467
|
+
3. Wave A merges → master now has Wave A changes
|
|
1468
|
+
4. Wave B merges → its diff shows **reversions** of Wave A (branched before merge)
|
|
1469
|
+
|
|
1470
|
+
Rebase at merge-time resolves this by incorporating earlier waves' changes before publication.
|
|
1471
|
+
|
|
1472
|
+
### Implementation
|
|
1473
|
+
|
|
1474
|
+
Commit: `4c3eeb36`
|
|
1475
|
+
- `assertNoStaleBaseSiblings()` — dispatch-time guard in run.ts
|
|
1476
|
+
- `rebaseBranchOntoMaster()` — merge-time rebase in merge.ts
|
|
1477
|
+
- `listEpicChainsWithLatestJob()` — SQLite query for sibling chain state
|
|
1478
|
+
- Schema: `ChainMergeTarget.worktreePath` field
|
|
1479
|
+
|
|
1480
|
+
---
|
|
1481
|
+
|
|
1482
|
+
## 30) Manifest-driven tool resolver
|
|
1483
|
+
|
|
1484
|
+
Each specialist's `--tools` argument is computed at session start by `resolvePermissionTools` from a JSON tool catalog plus an optional per-specialist override block. There are no hardcoded tier→tool arrays in source: the catalog is the only source of truth.
|
|
1485
|
+
|
|
1486
|
+
### Inputs
|
|
1487
|
+
|
|
1488
|
+
1. The specialist's tier from `execution.permission_required` (`READ_ONLY`/`LOW`/`MEDIUM`/`HIGH`)
|
|
1489
|
+
2. The catalog index at `.specialists/catalog/index.json` (with `native.json` / `gitnexus.json` / `serena.json` siblings)
|
|
1490
|
+
3. Live extension health probe of `pi-gitnexus` and `pi-serena-tools` in the global npm modules directory
|
|
1491
|
+
4. Optional `permissions[<TIER>]` override block on the specialist JSON
|
|
1492
|
+
|
|
1493
|
+
### Resolution layers (in order)
|
|
1494
|
+
|
|
1495
|
+
| Layer | Effect |
|
|
1496
|
+
|-------|--------|
|
|
1497
|
+
| `catalog` | Tier defaults from each catalog (native + gitnexus + serena) |
|
|
1498
|
+
| `specialist_override` | The specialist's `permissions[<TIER>]` block strips natives via `denied_natives_when_extension` |
|
|
1499
|
+
| `runtime_health` | Tools belonging to unhealthy extensions are dropped; if a hard-deny had stripped natives whose replacement extension is now unhealthy, those natives are restored automatically |
|
|
1500
|
+
|
|
1501
|
+
### Deny modes
|
|
1502
|
+
|
|
1503
|
+
- `soft` (default): native tool stays in `--tools`; resolver emits a `preference signals` line as a hint
|
|
1504
|
+
- `hard`: native tool is removed when the replacement extension is healthy; restored when it isn't
|
|
1505
|
+
|
|
1506
|
+
### Override example: explorer
|
|
1507
|
+
|
|
1508
|
+
`config/specialists/explorer.specialist.json` is the only specialist with an override today:
|
|
1509
|
+
|
|
1510
|
+
```json
|
|
1511
|
+
"permissions": {
|
|
1512
|
+
"READ_ONLY": {
|
|
1513
|
+
"denied_natives_when_extension": ["grep", "find", "ls"],
|
|
1514
|
+
"denied_natives_mode": "hard"
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
```
|
|
1518
|
+
|
|
1519
|
+
Result at runtime when both extensions are healthy: explorer's `--tools` excludes native `grep`/`find`/`ls`, includes `gitnexus_query` + `search_for_pattern` + `find_file` + symbol-graph tools. If `pi-serena-tools` becomes unhealthy mid-run, the natives are restored.
|
|
1520
|
+
|
|
1521
|
+
### Inspection
|
|
1522
|
+
|
|
1523
|
+
```bash
|
|
1524
|
+
sp config show <name> --resolved
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1527
|
+
Prints layer attribution, extension health, denied natives, deny mode, downgrade reasons, and the final `--tools` string. See [manifest.md](manifest.md) for the full reference and [cli-reference.md](cli-reference.md#specialists-config) for the CLI surface.
|
|
1528
|
+
|
|
1529
|
+
---
|
|
1530
|
+
|
|
1531
|
+
## Quick reference flows
|
|
1532
|
+
|
|
1533
|
+
### CLI async observation flow
|
|
1534
|
+
|
|
1535
|
+
```bash
|
|
1536
|
+
sp run executor --prompt "Task" --json
|
|
1537
|
+
# capture job id from stderr
|
|
1538
|
+
sp feed <job-id> --follow
|
|
1539
|
+
sp result <job-id> --wait --timeout 120
|
|
1540
|
+
```
|
|
1541
|
+
|
|
1542
|
+
### Process dashboard flow
|
|
1543
|
+
|
|
1544
|
+
```bash
|
|
1545
|
+
# Live view of all active jobs
|
|
1546
|
+
sp ps --follow
|
|
1547
|
+
|
|
1548
|
+
# Snapshot with context% and bead titles
|
|
1549
|
+
sp ps
|
|
1550
|
+
|
|
1551
|
+
# Include completed jobs
|
|
1552
|
+
sp ps --all
|
|
1553
|
+
|
|
1554
|
+
# Machine-readable for scripting
|
|
1555
|
+
sp ps --json | jq '.flat[] | select(.status == "waiting")'
|
|
1556
|
+
```
|
|
1557
|
+
|
|
1558
|
+
### Worktree isolation flow
|
|
1559
|
+
|
|
1560
|
+
```bash
|
|
1561
|
+
# 1. Executor provisions worktree, runs implementation
|
|
1562
|
+
sp run executor --worktree --bead hgpu.3
|
|
1563
|
+
# → job id: 49adda
|
|
1564
|
+
|
|
1565
|
+
# 2. Reviewer reuses same workspace (read-only)
|
|
1566
|
+
sp run reviewer --job 49adda --bead hgpu.3-review
|
|
1567
|
+
|
|
1568
|
+
# 3. Clean up terminal worktrees after review complete
|
|
1569
|
+
sp clean --dry-run # preview
|
|
1570
|
+
sp clean # execute
|
|
1571
|
+
```
|
|
1572
|
+
|
|
1573
|
+
### MCP single-run flow
|
|
1574
|
+
|
|
1575
|
+
1. `use_specialist` with `name` + `prompt`/`bead_id`
|
|
1576
|
+
2. Read final output directly from MCP response
|
|
1577
|
+
|