pi-soly 0.6.0 → 0.7.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/agents-install.ts CHANGED
@@ -1,14 +1,18 @@
1
1
  // =============================================================================
2
- // agents-install.ts — Idempotent install of soly-aware subagent configs
2
+ // assets-install.ts — Idempotent install of soly-managed user assets
3
3
  // =============================================================================
4
4
  //
5
- // Soly ships ONE subagent: `soly-manager`. It's a workflow executor that
6
- // switches modes (worker / debugger / tester / reviewer / refactor /
7
- // documenter / oracle / planner) based on the task brief the parent passes.
8
- // One agent, one system prompt, all roles.
5
+ // Soly ships two kinds of user-scope assets:
9
6
  //
10
- // pi-subagents discovers agents from `~/.pi/agent/agents/`, so on first
11
- // session_start we copy our `soly-manager.md` there.
7
+ // 1. Subagent configs `~/.pi/agent/agents/`
8
+ // The single `soly-manager` subagent (mode-switching executor).
9
+ //
10
+ // 2. Skills → `~/.pi/agent/skills/<name>/`
11
+ // The `soly-framework` skill — framework documentation the LLM
12
+ // loads on demand via the read tool.
13
+ //
14
+ // pi discovers both from `~/.pi/agent/`, so on first session_start we
15
+ // copy our shipped files there.
12
16
  //
13
17
  // IDEMPOTENT: if the target file already exists (user may have customized
14
18
  // it), we do NOT overwrite. This is one-way "first install wins".
@@ -23,34 +27,73 @@ const SHIPPED_AGENTS = [
23
27
  "soly-manager.md",
24
28
  ] as const;
25
29
 
26
- /** Where pi-subagents looks for user agents. Respects HOME/USERPROFILE
27
- * for testability (otherwise we'd always write to the real user home). */
30
+ /** soly skills bundled with the extension. Each entry is a directory
31
+ * under `skills/` containing a SKILL.md. */
32
+ const SHIPPED_SKILLS = [
33
+ "soly-framework",
34
+ ] as const;
35
+
36
+ /** Where pi looks for user agents. Respects HOME/USERPROFILE for
37
+ * testability (otherwise we'd always write to the real user home). */
28
38
  function userAgentsDir(): string {
29
39
  const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
30
40
  return path.join(home, ".pi", "agent", "agents");
31
41
  }
32
42
 
43
+ /** Where pi looks for user skills. */
44
+ function userSkillsDir(): string {
45
+ const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
46
+ return path.join(home, ".pi", "agent", "skills");
47
+ }
48
+
33
49
  /** Where this soly extension's `agents/` directory lives. */
34
- function shippedDir(extensionRoot: string): string {
50
+ function shippedAgentsDir(extensionRoot: string): string {
35
51
  return path.join(extensionRoot, "agents");
36
52
  }
37
53
 
54
+ /** Where this soly extension's `skills/` directory lives. */
55
+ function shippedSkillsDir(extensionRoot: string): string {
56
+ return path.join(extensionRoot, "skills");
57
+ }
58
+
38
59
  export interface InstallResult {
39
60
  installed: string[];
40
61
  skipped: string[];
41
62
  errors: string[];
42
63
  }
43
64
 
65
+ /** Copy a single file if destination doesn't exist. Idempotent. */
66
+ function copyIfMissing(from: string, to: string): "installed" | "skipped" | "error" {
67
+ if (!fs.existsSync(from)) return "error";
68
+ if (fs.existsSync(to)) return "skipped";
69
+ try {
70
+ fs.copyFileSync(from, to);
71
+ return "installed";
72
+ } catch {
73
+ return "error";
74
+ }
75
+ }
76
+
77
+ /** Recursively copy a directory tree if destination doesn't exist. Idempotent. */
78
+ function copyDirIfMissing(from: string, to: string): "installed" | "skipped" | "error" {
79
+ if (!fs.existsSync(from)) return "error";
80
+ if (fs.existsSync(to)) return "skipped";
81
+ try {
82
+ fs.mkdirSync(path.dirname(to), { recursive: true });
83
+ fs.cpSync(from, to, { recursive: true });
84
+ return "installed";
85
+ } catch {
86
+ return "error";
87
+ }
88
+ }
89
+
44
90
  /** Install shipped soly agents to `~/.pi/agent/agents/`. Idempotent. */
45
91
  export function installSolyAgents(extensionRoot: string): InstallResult {
46
92
  const result: InstallResult = { installed: [], skipped: [], errors: [] };
47
- const src = shippedDir(extensionRoot);
93
+ const src = shippedAgentsDir(extensionRoot);
48
94
  const dst = userAgentsDir();
49
95
 
50
- if (!fs.existsSync(src)) {
51
- // Development mode or partial install — silently no-op
52
- return result;
53
- }
96
+ if (!fs.existsSync(src)) return result; // dev mode no-op
54
97
 
55
98
  try {
56
99
  fs.mkdirSync(dst, { recursive: true });
@@ -62,26 +105,46 @@ export function installSolyAgents(extensionRoot: string): InstallResult {
62
105
  for (const name of SHIPPED_AGENTS) {
63
106
  const from = path.join(src, name);
64
107
  const to = path.join(dst, name);
65
- if (!fs.existsSync(from)) {
66
- result.errors.push(`missing source: ${from}`);
67
- continue;
68
- }
69
- if (fs.existsSync(to)) {
70
- // User already has this file (possibly customized) — respect it
71
- result.skipped.push(name);
72
- continue;
73
- }
74
- try {
75
- fs.copyFileSync(from, to);
76
- result.installed.push(name);
77
- } catch (err) {
78
- result.errors.push(`copy ${name}: ${(err as Error).message}`);
79
- }
108
+ const r = copyIfMissing(from, to);
109
+ if (r === "installed") result.installed.push(name);
110
+ else if (r === "skipped") result.skipped.push(name);
111
+ else result.errors.push(`missing source: ${from}`);
112
+ }
113
+
114
+ return result;
115
+ }
116
+
117
+ /** Install shipped soly skills to `~/.pi/agent/skills/`. Idempotent. */
118
+ export function installSolySkills(extensionRoot: string): InstallResult {
119
+ const result: InstallResult = { installed: [], skipped: [], errors: [] };
120
+ const src = shippedSkillsDir(extensionRoot);
121
+ const dst = userSkillsDir();
122
+
123
+ if (!fs.existsSync(src)) return result; // dev mode no-op
124
+
125
+ for (const name of SHIPPED_SKILLS) {
126
+ const from = path.join(src, name);
127
+ const to = path.join(dst, name);
128
+ const r = copyDirIfMissing(from, to);
129
+ if (r === "installed") result.installed.push(name);
130
+ else if (r === "skipped") result.skipped.push(name);
131
+ else result.errors.push(`missing source: ${from}`);
80
132
  }
81
133
 
82
134
  return result;
83
135
  }
84
136
 
137
+ /** Install all soly assets (agents + skills). Combined for convenience. */
138
+ export function installSolyAssets(extensionRoot: string): {
139
+ agents: InstallResult;
140
+ skills: InstallResult;
141
+ } {
142
+ return {
143
+ agents: installSolyAgents(extensionRoot),
144
+ skills: installSolySkills(extensionRoot),
145
+ };
146
+ }
147
+
85
148
  /** Check which shipped soly agents are present in the user dir. Used by doctor. */
86
149
  export function checkSolyAgentsInstalled(extensionRoot: string): {
87
150
  installed: string[];
@@ -99,3 +162,21 @@ export function checkSolyAgentsInstalled(extensionRoot: string): {
99
162
  }
100
163
  return { installed, missing };
101
164
  }
165
+
166
+ /** Check which shipped soly skills are present in the user dir. */
167
+ export function checkSolySkillsInstalled(extensionRoot: string): {
168
+ installed: string[];
169
+ missing: string[];
170
+ } {
171
+ const dst = userSkillsDir();
172
+ const installed: string[] = [];
173
+ const missing: string[] = [];
174
+ for (const name of SHIPPED_SKILLS) {
175
+ if (fs.existsSync(path.join(dst, name, "SKILL.md"))) {
176
+ installed.push(name);
177
+ } else {
178
+ missing.push(name);
179
+ }
180
+ }
181
+ return { installed, missing };
182
+ }
package/index.ts CHANGED
@@ -45,7 +45,7 @@ import {
45
45
  type SourceSpec,
46
46
  } from "./core.ts";
47
47
  import { buildIntegrationsSection } from "./integrations.ts";
48
- import { installSolyAgents } from "./agents-install.ts";
48
+ import { installSolyAssets } from "./agents-install.ts";
49
49
  import {
50
50
  DEFAULT_CONFIG,
51
51
  loadConfig,
@@ -388,21 +388,22 @@ export default function solyExtension(pi: ExtensionAPI) {
388
388
  }
389
389
  }
390
390
 
391
- // Auto-install soly-manager subagent config to ~/.pi/agent/agents/
392
- // on first run. Opt-in via config `agent.useSolyWorkerSubagents`
393
- // (default false). Idempotent — respects any existing user-
394
- // customized copies.
391
+ // Auto-install soly user-scope assets (soly-manager agent + soly-framework
392
+ // skill) to ~/.pi/agent/ on first run. Opt-in via config
393
+ // `agent.useSolyWorkerSubagents` (default false). Idempotent — respects
394
+ // any existing user-customized copies.
395
395
  if (activeConfig.agent.useSolyWorkerSubagents) {
396
396
  const extRoot = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
397
- const installResult = installSolyAgents(extRoot);
398
- if (installResult.installed.length > 0) {
397
+ const assets = installSolyAssets(extRoot);
398
+ const installed = [...assets.agents.installed, ...assets.skills.installed.map((s) => `skill:${s}`)];
399
+ if (installed.length > 0) {
399
400
  ctx.ui.notify(
400
- `soly: installed subagent config (${installResult.installed.join(", ")}) — run \`/subagents-doctor\` to verify`,
401
+ `soly: installed (${installed.join(", ")}) — run \`/subagents-doctor\` to verify`,
401
402
  "info",
402
403
  );
403
404
  }
404
- for (const e of installResult.errors) {
405
- ctx.ui.notify(`soly: agent install error — ${e}`, "warning");
405
+ for (const e of [...assets.agents.errors, ...assets.skills.errors]) {
406
+ ctx.ui.notify(`soly: install error — ${e}`, "warning");
406
407
  }
407
408
  }
408
409
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-soly",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Project management framework for pi-coding-agent. Workflows, planning, multi-question picker, agent switcher, live task list — one npm install, zero config.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -40,6 +40,7 @@
40
40
  "agents-install.ts",
41
41
  "agents",
42
42
  "ask",
43
+ "skills",
43
44
  "switch",
44
45
  "workflows",
45
46
  "workflows-data"
@@ -0,0 +1,320 @@
1
+ ---
2
+ name: soly-framework
3
+ description: Use when the user asks how to do anything with the soly framework for pi — start a new project, plan or execute a phase, pause and resume sessions, add rules, add intent docs, write PLAN.md or SUMMARY.md, troubleshoot issues. Triggers on "how do I", "what's the command for", "soly help", "soly framework", and any practical question about using the soly extension. NOT loaded for generic code questions — only when the user is working with the soly workflow.
4
+ ---
5
+
6
+ # soly framework
7
+
8
+ The **soly** extension adds project-management workflow to [pi-coding-agent](https://github.com/nicobailon/pi-coding-agent): intent docs, ROADMAP/STATE/PHASE state machine, and subagent-driven plan execution. This skill is your complete reference for using it.
9
+
10
+ ## Quick start (read first if new)
11
+
12
+ **Mental model — three layers, always in system prompt, in this order:**
13
+
14
+ 1. **Project intent** (`.soly/docs/`) — the 0-point. What the user wants the app to be. Written BEFORE plans, by humans.
15
+ 2. **Project state** (`.soly/STATE.md`, `ROADMAP.md`) — where we are, current phase, recent decisions.
16
+ 3. **Project rules** (`.soly/rules/`, `~/.soly/rules/`) — how to behave in this project.
17
+
18
+ **Workflow model — phases and plans:**
19
+
20
+ - A **phase** is a milestone (e.g. "01-foundation"). Has one or more `PLAN.md` files.
21
+ - A **plan** is one ordered execution unit. Has `<task>` blocks.
22
+ - A **task** is the smallest unit. Has type, description, verify, accept.
23
+ - **Close-out**: production code commits → `SUMMARY.md` → `STATE.md` updated → ROADMAP check.
24
+
25
+ ## Slash commands (interactive mode)
26
+
27
+ | Command | What it does |
28
+ |---|---|
29
+ | `/plan [N]` | Generate or update `PLAN.md` for phase N (or current phase) |
30
+ | `/execute [N[.MM]]` | Dispatch plan(s) to `soly-manager` subagent. `N` = all plans in phase. `N.MM` = specific plan. |
31
+ | `/discuss N` | Discussion-driven scoping for phase N — capture decisions before planning |
32
+ | `/inspect` | One-screen summary: position, phases, recent decisions |
33
+ | `/pause` | Save handoff (`HANDOFF.json` + `.continue-here.md`) for later resume |
34
+ | `/resume` | Restore from a paused handoff |
35
+ | `/quick <task>` | One-shot task that doesn't need a full plan — direct dispatch |
36
+ | `/soly` | Project state inspection (alias for `/inspect`) |
37
+ | `/why` | Show what context the LLM's last turn was based on |
38
+ | `/agent [name]` | Switch the current cycle agent (or open picker) |
39
+
40
+ `/soly <verb>` plain-text aliases also work for some verbs (legacy compat).
41
+
42
+ ## File structure
43
+
44
+ ```
45
+ <project-root>/
46
+ ├── .soly/
47
+ │ ├── ROADMAP.md # phase table
48
+ │ ├── STATE.md # current position + decisions log
49
+ │ ├── docs/ # 0-point intent docs (human-written, locked)
50
+ │ │ ├── vision.md
51
+ │ │ └── architecture.md
52
+ │ ├── rules/ # project rules (version-controlled)
53
+ │ │ ├── code-style.md
54
+ │ │ └── testing.md
55
+ │ ├── phases/
56
+ │ │ ├── 01-foundation/
57
+ │ │ │ ├── 01-CONTEXT.md # domain + decisions for phase 1
58
+ │ │ │ ├── 01-RESEARCH.md # what we looked up
59
+ │ │ │ ├── 01-PLAN-01.md # plan 1
60
+ │ │ │ ├── 01-PLAN-01-SUMMARY.md
61
+ │ │ │ ├── 01-PLAN-02.md
62
+ │ │ │ └── 01-PLAN-02-SUMMARY.md
63
+ │ │ └── 02-feature-x/
64
+ │ │ └── ...
65
+ │ ├── iterations/ # per-execution context bundles (auto)
66
+ │ ├── HANDOFF.json # pause snapshot
67
+ │ └── .continue-here.md # pause resume marker
68
+ ```
69
+
70
+ ## Frontmatter conventions
71
+
72
+ ### PLAN.md frontmatter (required)
73
+
74
+ ```markdown
75
+ ---
76
+ id: 01-02 # phase-plan, zero-padded
77
+ title: Add OAuth flow
78
+ status: pending # pending | in_progress | done
79
+ phase: 1
80
+ depends-on: [] # other plan ids
81
+ parallelizable: true # can run alongside siblings
82
+ ---
83
+
84
+ # Add OAuth flow
85
+
86
+ ## read_first
87
+ - .soly/STATE.md
88
+ - .soly/ROADMAP.md
89
+ - .soly/rules/code-style.md
90
+
91
+ ## tasks
92
+ - [ ] **type: implement**, description: Add token refresh logic
93
+ - files: src/auth/refresh.ts
94
+ - verify: bun test src/auth/refresh.test.ts
95
+ - accept: Refresh succeeds when token is expired; fails when refresh_token is also expired
96
+
97
+ - [ ] **type: tdd**, description: Write integration test for the auth flow
98
+ - verify: bun test src/auth/
99
+
100
+ - [ ] **type: checkpoint**, description: Pause for human review of UX
101
+
102
+ ## verification
103
+ - bun test
104
+ - bun run typecheck
105
+ - bun run lint
106
+
107
+ ## risks
108
+ - Token storage depends on the encryption scheme (see .soly/docs/architecture.md)
109
+ ```
110
+
111
+ ### SUMMARY.md frontmatter
112
+
113
+ ```markdown
114
+ ---
115
+ plan: 01-02
116
+ completed: 2026-06-15
117
+ duration: 47min
118
+ files-touched: 7
119
+ ---
120
+
121
+ # Summary
122
+
123
+ ## Tasks
124
+ - [x] Add token refresh logic
125
+ - [x] Write integration test
126
+ - [x] Pause for human review
127
+
128
+ ## Deviations
129
+ - Refactored `auth/refresh.ts` to use singleton pattern (was factory). Documented in `architecture.md`.
130
+
131
+ ## Verification
132
+ - `bun test`: 142 passing
133
+ - `bun run typecheck`: clean
134
+ - `bun run lint`: 0 warnings
135
+
136
+ ## Next
137
+ - Phase 02 plan 01: User profile page
138
+ ```
139
+
140
+ ### Rules file frontmatter (optional)
141
+
142
+ ```markdown
143
+ ---
144
+ applyTo: "src/**/*.ts" # glob (optional, default: all)
145
+ priority: 50 # higher wins on conflict (default: 0)
146
+ ---
147
+
148
+ # TypeScript style
149
+
150
+ - Strict mode required
151
+ - Never use `any` — use `unknown` and narrow
152
+ ```
153
+
154
+ ## Path discipline (NON-NEGOTIABLE)
155
+
156
+ **All soly-managed files live under `.soly/`.** Source code lives in the project's normal source tree.
157
+
158
+ | File kind | Goes to |
159
+ |---|---|
160
+ | `PLAN.md`, `SUMMARY.md`, `CONTEXT.md`, `RESEARCH.md` | `.soly/phases/<NN>-<slug>/` |
161
+ | Intent docs (0-point) | `.soly/docs/` |
162
+ | Rules | `.soly/rules/` (project) or `~/.soly/rules/` (user) |
163
+ | Handoff | `.soly/HANDOFF.json`, `.soly/.continue-here.md` |
164
+ | Iteration context | `.soly/iterations/` (auto-generated) |
165
+ | Production code, tests | project's normal `src/`, `tests/`, `app/`, etc. |
166
+
167
+ Use absolute paths (or paths starting with `$SOLY_DIR`) when calling tools. Never bare relative names that could land in cwd.
168
+
169
+ ## Close-out order
170
+
171
+ The only legal sequence for finishing a plan:
172
+
173
+ 1. Production code commits (1+)
174
+ 2. `SUMMARY.md` committed
175
+ 3. `STATE.md` "Current Position" block updated
176
+ 4. `ROADMAP.md` phase checkbox updated
177
+ 5. `PLAN.md` frontmatter `status: done`
178
+
179
+ Once production commits exist, returning without a committed `SUMMARY.md` is an **illegal partial-plan state** — the next `/execute` will detect it and refuse to start.
180
+
181
+ ## Cycle agents (4 built-in)
182
+
183
+ | Agent | Writes | Use for |
184
+ |---|---|---|
185
+ | `worker` | ✅ | Generic implementation, full tools |
186
+ | `oracle` | ❌ | Decision-consistency, no file edits |
187
+ | `scout` | ❌ | Codebase recon, read-only |
188
+ | `reviewer` | ❌ | Adversarial code review |
189
+
190
+ Switch with `/agent <name>` or `Ctrl+Tab` (cycles through). Footer pill shows current: `· ⚡ worker` / `▶ 🐢 oracle`.
191
+
192
+ ## Subagent: soly-manager (single, mode-switching)
193
+
194
+ Spawn via `subagent({ agent: "soly-manager", task: ... })`. The task brief tells it which mode to be in:
195
+
196
+ | Task brief mentions | Mode |
197
+ |---|---|
198
+ | implement, build, write code, add feature, create | **worker** |
199
+ | debug, bug, fix, crash, error, repro, broken | **debugger** |
200
+ | test, coverage, spec, assert, only modify tests | **tester** |
201
+ | review, audit, adversarial, find bugs, qa | **reviewer** |
202
+ | refactor, simplify, extract, rename, no behavior change | **refactor** |
203
+ | document, readme, jsdoc, comment, intent doc | **documenter** |
204
+ | validate, scope, drift, decision, before committing | **oracle** |
205
+ | plan, design, outline, structure, decompose | **planner** |
206
+
207
+ **soly-manager is ONE agent that switches modes. Don't spawn soly-worker / soly-debugger / etc. — those don't exist anymore.**
208
+
209
+ ## Tools the LLM can call
210
+
211
+ | Tool | Purpose |
212
+ |---|---|
213
+ | `soly_read(artifact, phase, taskId)` | Read soly artifacts: STATE, plan, context, research, ROADMAP, requirements, project, milestone, task |
214
+ | `soly_log_decision(decision, rationale, phase)` | Append to STATE.md Decisions table |
215
+ | `soly_list_phases()` | List all phases with plan counts, C/R markers |
216
+ | `soly_list_tasks()` | List all tasks across features (kind, status, priority, deps) |
217
+ | `soly_todos(paths, limit)` | Scan working tree for TODO/FIXME/HACK/XXX/NOTE |
218
+ | `soly_env()` | Detect runtime (package manager, runtimes, services, scripts) |
219
+ | `soly_snippet(path, offset, limit)` | Read bounded line range with line numbers |
220
+ | `soly_doc_search(query, limit)` | Search .md/.html under cwd (prioritizes intent docs) |
221
+ | `soly_intent()` | List 0-point intent docs from `.soly/docs/` |
222
+ | `soly_scratchpad(limit)` | Recent conversation recap (one line per turn) |
223
+ | `ask_pro(questions)` | Multi-question picker (tabbed, single/multi-select, ⭐, Other…) |
224
+ | `todo_update(todos)` | Update task list rendered in footer |
225
+
226
+ ## Add a new rule (most common task)
227
+
228
+ Three places, in priority order:
229
+
230
+ 1. **Project rule** — `~/.pi/agent/agents/soly/rules/<name>.md` (version-controlled, shared with team)
231
+ 2. **User rule** — `~/.soly/rules/<name>.md` (per-user, not committed)
232
+ 3. **Phase rule** — `<phase-dir>/<plan>.md.rules/<name>.md` (active only for that plan)
233
+
234
+ Use `/rulewizard` slash command to scaffold a new rule with the right frontmatter.
235
+
236
+ A rule file looks like:
237
+
238
+ ```markdown
239
+ ---
240
+ applyTo: "src/**/*.ts"
241
+ priority: 50
242
+ ---
243
+
244
+ # TypeScript style
245
+
246
+ - Strict mode required
247
+ - Never use `any`
248
+ - Prefer `type` over `interface`
249
+ ```
250
+
251
+ ## Add a new intent doc
252
+
253
+ Create a file in `.soly/docs/`:
254
+
255
+ ```markdown
256
+ # Architecture
257
+
258
+ ## Goal
259
+
260
+ Build a CLI tool that...
261
+
262
+ ## Non-obvious constraints
263
+
264
+ - Must work offline (no network calls)
265
+ - Must be a single static binary
266
+ - Must integrate with the existing `~/.config/x` schema
267
+ ```
268
+
269
+ Intent docs are 0-point — written BEFORE any plan, by humans. They define the "why", not the "how".
270
+
271
+ ## Common workflows
272
+
273
+ ### Start a new project
274
+
275
+ 1. `soly init` (or manually create `.soly/`, `docs/`, `rules/`)
276
+ 2. Write 1-3 intent docs in `.soly/docs/`
277
+ 3. Create `ROADMAP.md` with phase table
278
+ 4. `/plan 1` to start phase 1
279
+
280
+ ### Add a feature to an existing phase
281
+
282
+ 1. `/plan 1.05` (next plan number)
283
+ 2. Edit the generated `PLAN.md`
284
+ 3. `/execute 1.05`
285
+
286
+ ### Pause a long session
287
+
288
+ 1. `/pause` → writes `HANDOFF.json` + `.continue-here.md`
289
+ 2. Later, in a new session: `/resume`
290
+
291
+ ### Troubleshoot a partial plan
292
+
293
+ If `/execute` complains about illegal partial state:
294
+
295
+ 1. `cat .soly/iterations/<latest>.md` — see what the last run did
296
+ 2. Check if `SUMMARY.md` exists for the last plan
297
+ 3. If yes, finish close-out: update `STATE.md` + `ROADMAP.md`
298
+ 4. If no, either commit the SUMMARY or revert the production commits
299
+
300
+ ## Where to look for answers
301
+
302
+ - **"What command does X"** → this skill, Slash commands section
303
+ - **"What does PLAN.md look like"** → this skill, Frontmatter section
304
+ - **"How to add a rule"** → this skill, Add a new rule section
305
+ - **"Why did the LLM do Y"** → `/why`
306
+ - **"What context is loaded"** → `soly_read(artifact: "state")` + `soly_doc_search(...)`
307
+ - **"What was the recent conversation"** → `soly_scratchpad()`
308
+
309
+ ## Don'ts
310
+
311
+ - ❌ Edit `.soly/rules/` files you didn't write — those are project invariants
312
+ - ❌ Skip the SUMMARY — illegal partial state
313
+ - ❌ Spawn `soly-worker` or `soly-debugger` — use `soly-manager` (mode-switches)
314
+ - ❌ Write rules in code comments — use `.soly/rules/*.md` files
315
+ - ❌ Edit `.soly/phases/*/PLAN.md` after `status: in_progress` — create a new plan
316
+ - ❌ Put intent docs anywhere other than `.soly/docs/`
317
+
318
+ ## When in doubt
319
+
320
+ Call `soly_read(artifact: "state")` and `soly_read(artifact: "roadmap")` first. The system prompt has the layers, but `soly_read` gives you full content. Then check `soly_doc_search` for any other relevant docs.