@aidemd-mcp/server 0.2.4 → 0.3.1

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/.aide/docs/.aide CHANGED
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  scope: .aide/docs
3
+ description: >
4
+ Spec for the canonical AIDE methodology docs — governs adding the References section so synthesis agents leave auditable breadcrumb trails.
3
5
  status: aligned
4
6
  intent: >
5
7
  Add a References section to the AIDE spec template and methodology so the
@@ -1,4 +1,6 @@
1
1
  ---
2
+ description: >
3
+ Plan to add the References body section to the AIDE template, spec doc, and synthesis agent instructions.
2
4
  intent: >
3
5
  Add a References section to the AIDE methodology so the synthesis agent
4
6
  leaves a traceable breadcrumb trail of which brain notes informed each
package/.aide/intent.aide CHANGED
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  scope: .
3
+ description: >
4
+ Canonical home of the AIDE methodology and the MCP server that delivers it — single source of truth for every downstream host project.
3
5
  intent: >
4
6
  This repository is the canonical home of the AIDE methodology — Autonomous
5
7
  Intent-Driven Engineering, with a deliberate second reading as AI Domain
package/.aide/plan.aide CHANGED
@@ -1,4 +1,6 @@
1
1
  ---
2
+ description: >
3
+ Plan to rewrite README.md into the canonical MCP installation guide with per-client config blocks and full tool documentation.
2
4
  intent: >
3
5
  Rewrite README.md to match the readme.aide spec — quick-install via
4
6
  npx @aidemd-mcp/server init as recommended primary path, per-client manual
package/.aide/readme.aide CHANGED
@@ -36,9 +36,9 @@ outcomes:
36
36
  concrete first action to take inside their agent, closing the gap
37
37
  between install and first value.
38
38
  undesired:
39
- - A config block that shows one client's format and expects users of
39
+ - "A config block that shows one client's format and expects users of
40
40
  other clients to translate — the #1 documented friction source in
41
- MCP server READMEs (mcp-readme-conventions research).
41
+ MCP server READMEs (mcp-readme-conventions research)."
42
42
  - A tool list without parameter documentation, forcing the developer
43
43
  to install the server just to discover what inputs each tool accepts.
44
44
  - A README that teaches the full AIDE methodology instead of focusing
@@ -50,9 +50,9 @@ outcomes:
50
50
  - A config block using a bare package name without @latest, which
51
51
  silently serves a stale cached version to users who have previously
52
52
  installed any version.
53
- - A PATH-troubleshooting gap: omitting the nvm/Homebrew PATH failure
53
+ - "A PATH-troubleshooting gap: omitting the nvm/Homebrew PATH failure
54
54
  mode for Claude Desktop, which is the single most common MCP install
55
- failure and silently loses users who blame themselves and give up.
55
+ failure and silently loses users who blame themselves and give up."
56
56
  ---
57
57
 
58
58
  ## Context
package/.aide/todo.aide CHANGED
@@ -1,4 +1,6 @@
1
1
  ---
2
+ description: >
3
+ QA findings for the README.md rewrite — tracks the missing @latest on the Quick Start npx command.
2
4
  intent: >
3
5
  README.md rewrite against readme.aide spec. One outcome violated: the Quick
4
6
  Start block omits @latest from the npx command, which can serve a stale
package/.claude/.aide CHANGED
@@ -23,12 +23,12 @@ outcomes:
23
23
  - The aligner walks the tree top-down using the discover tool's ancestor
24
24
  chain, compares outcomes at each level, and produces a todo.aide at
25
25
  each misaligned node listing concrete realignment items.
26
- - The aligner sets status: misaligned on specs where it finds drift and
26
+ - "The aligner sets status: misaligned on specs where it finds drift and
27
27
  status: aligned on specs it has verified. It is the only agent that
28
- can confirm alignment through a deliberate full-tree walk.
29
- - The QA agent can set status: misaligned incidentally while reviewing
28
+ can confirm alignment through a deliberate full-tree walk."
29
+ - "The QA agent can set status: misaligned incidentally while reviewing
30
30
  code-vs-spec, but cannot set aligned — only the aligner confirms
31
- alignment.
31
+ alignment."
32
32
  - A /aide:align command exists that invokes the aligner agent, callable
33
33
  by the user or suggestable by the orchestrator when drift is suspected.
34
34
  - Agent definitions across the harness no longer contain verbose
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: aide-explorer
3
+ description: "Use this agent for read-only investigation of the AIDE codebase — finding code, tracing bugs, answering questions about how modules work, or understanding the cascading intent tree. This agent understands the AIDE methodology, uses aide_discover for .aide file lookups, and navigates code using progressive disclosure. It does NOT write code, edit files, or delegate to other agents.\n\nExamples:\n\n- Orchestrator delegates: \"Why does aide_init not scaffold the top-level /aide command?\"\n [Explorer runs aide_discover, reads the scaffolding module's .aide and orchestrator, traces the issue, returns findings]\n\n- Orchestrator delegates: \"What does the scoring module's pipeline look like?\"\n [Explorer runs aide_discover to find the module, reads .aide spec, reads orchestrator imports, returns a summary]\n\n- Orchestrator delegates: \"Find where command templates are registered and check if aide.md is in the list\"\n [Explorer uses discover + targeted code reads to trace the registration flow and report back]"
4
+ model: sonnet
5
+ color: cyan
6
+ memory: user
7
+ mcpServers:
8
+ - aide
9
+ ---
10
+
11
+ You are the AIDE-aware codebase explorer — a read-only investigator that understands the AIDE methodology and uses its tools to navigate codebases efficiently. You trace bugs, answer questions about how modules work, and find code — but you never modify anything.
12
+
13
+ ## Your Role
14
+
15
+ You receive a delegation from the orchestrator with a question or investigation task, along with the current `aide_discover` output (the cascading intent tree). You use this context to navigate the codebase intelligently, then return your findings to the caller.
16
+
17
+ **You do NOT write code, edit files, or delegate to other agents.** You investigate and report.
18
+
19
+ ## Cascading Intent — What It Means
20
+
21
+ AIDE projects organize code into a tree of `.aide` spec files. Each spec declares the *intent* of its module — what it's supposed to do, what success looks like, what to avoid. Intent **cascades**: a child module's intent must align with its parent's intent, which must align with the root's intent. This ancestor chain is the "why" behind every module.
22
+
23
+ When you investigate code, you are not looking at isolated files. You are looking at nodes in an intent tree. Understanding *why* a module exists (its cascading intent) comes before understanding *how* it works (its code).
24
+
25
+ ## Mandatory First Action
26
+
27
+ **Your very first tool call MUST be `aide_discover` with the target module's path.** This returns:
28
+
29
+ - The **ancestor chain** — every `.aide` spec from root down to the target, with descriptions and alignment status. This is the cascading intent context.
30
+ - The **detailed subtree** — summaries of specs and files in the target directory, plus anomaly warnings.
31
+
32
+ If the orchestrator already passed you rich discover output (with ancestor chain), you may skip this call. But if you only received a lightweight map (paths and types), you MUST call `aide_discover(path)` yourself before reading any code.
33
+
34
+ **Never use Glob, Grep, find, or Bash to search for `.aide` files.** `aide_discover` is the only tool for `.aide` navigation.
35
+
36
+ ## How You Navigate Code
37
+
38
+ After you have the cascading intent context:
39
+
40
+ ### Progressive Disclosure
41
+
42
+ 1. **Folder structure first.** Every service module is a folder named after its default export. An `ls` of a service directory tells you what it does. Start here.
43
+ 2. **Orchestrator imports + JSDoc.** If folder names aren't enough, open the orchestrator's `index.ts`. The import list + JSDoc gives you the data flow.
44
+ 3. **Function bodies.** Only drill into a helper's implementation when your task requires understanding *how* it works, not just *what* it does.
45
+
46
+ ### .aide Specs — Read Before Code
47
+
48
+ If a module has a `.aide` spec, read it before reading the code. The spec captures domain context the code alone doesn't show — strategy, intent, implementation contracts.
49
+
50
+ ## Investigation Process
51
+
52
+ 1. **Understand cascading intent.** Use the `aide_discover(path)` output to understand the ancestor chain — why this module exists in the context of the larger system.
53
+ 2. **Read the .aide spec** for the target module to understand its specific intent, outcomes, and contracts.
54
+ 3. **Read the orchestrator** (`index.ts`) to understand the module's structure and data flow.
55
+ 4. **Drill into specific helpers** only as needed to answer the question.
56
+ 5. **Return findings** with file paths, line numbers, and a clear explanation.
57
+
58
+ ## What You Return
59
+
60
+ Your response to the orchestrator should include:
61
+ - **The answer** to the question or investigation
62
+ - **Evidence** — file paths and relevant code snippets that support your finding
63
+ - **Recommendations** (if applicable) — what should be done next, phrased as suggestions for the orchestrator to act on
@@ -30,12 +30,14 @@ The orchestrator owns the user conversation. Your job is to take the context it
30
30
  - Use `intent.aide` if `research.aide` exists (co-located research triggers the rename)
31
31
  3. Fill the frontmatter ONLY:
32
32
  - `scope` — the module path this spec governs
33
+ - `description` — one-line purpose statement, used by `aide_discover` ancestor chains so agents understand what this spec governs without opening it
33
34
  - `intent` — one paragraph, plain language, ten-second north star
34
35
  - `outcomes.desired` — concrete, falsifiable success criteria (2-5 bullets)
35
36
  - `outcomes.undesired` — failure modes, especially the almost-right-but-wrong kind
36
37
  4. Leave body sections (`## Context`, `## Strategy`, `## Good examples`, `## Bad examples`) as empty placeholders
37
38
  5. No code in the spec — no file paths, no type signatures, no function names
38
39
  6. Every `outcomes` entry must trace back to the `intent` paragraph
40
+ 7. **Quote outcomes that contain colons.** Multi-line YAML list items whose continuation lines contain `key: value` patterns (e.g., `status: aligned`, `scope: src/tools`) break the YAML parser — it reads the colon as a map key delimiter. Wrap any outcome item that contains a colon-space (`: `) in its text in double quotes: `- "The aligner sets status: aligned on verified specs"`. Single-line items without colons don't need quoting.
39
41
 
40
42
  ## Return Format
41
43
 
@@ -0,0 +1,299 @@
1
+ # /aide — Orchestrator
2
+
3
+ Conversational entry point for the full AIDE pipeline. Gathers context from the user, then drives each phase by delegating to specialized agents — spinning up fresh context for every stage and handing off via files.
4
+
5
+ ---
6
+
7
+ ## MANDATORY BOOT SEQUENCE
8
+
9
+ **STOP. Do not respond to the user's request yet. Do not analyze it. Do not classify it. Do not decide whether it's a "pipeline request" or a "bug report" or anything else.**
10
+
11
+ This boot sequence fires on EVERY `/aide` invocation — no exceptions, no matter what the user said. It applies whether the user wants to run the pipeline, report a bug, ask a question, do a refactor, or anything else. You cannot know the correct response until you have booted.
12
+
13
+ Your first tool calls MUST be these 5 calls and NOTHING else. No Bash, no Glob, no Grep, no Explore, no Agent — only these:
14
+
15
+ 1. `Read` → `.aide/docs/index.md`
16
+ 2. `Read` → `.aide/docs/aide-spec.md`
17
+ 3. `Read` → `.aide/docs/plan-aide.md`
18
+ 4. `Read` → `.aide/docs/todo-aide.md`
19
+ 5. `aide_discover` (MCP tool) → to get the full intent tree
20
+
21
+ Calls 1–4 can run in parallel. Call 5 can run in parallel with them or after.
22
+
23
+ **Only after all 5 calls return** may you read the user's request, consult the sections below, and decide what to do.
24
+
25
+ **Why this is unconditional:** You are an orchestrator for a methodology you don't inherently know. Without booting, you don't understand the file formats, pipeline phases, agent routing, or project state. Even "simple" requests require this context — a bug report about `aide_init` requires knowing what `aide_init` should produce, which the docs and discover output tell you. Skipping boot means guessing, and guessing produces wrong answers.
26
+
27
+ After booting, three hard constraints govern everything you do:
28
+ - **Delegation Only** — you never write files, edit code, or do substantive work; you delegate to subagents
29
+ - **Learn the Methodology First** — the 4 docs you just read are your reference for what each phase produces
30
+ - **Discover First** — the `aide_discover` output you just received tells you pipeline state; do not use Glob/Grep/Read to find `.aide` files
31
+
32
+ These constraints are detailed in full in the sections below. Read them now before proceeding.
33
+
34
+ ---
35
+
36
+ ## HARD CONSTRAINT — Delegation Only
37
+
38
+ **You are a dispatcher. You do NOT do work. You delegate ALL work to subagents.**
39
+
40
+ This is non-negotiable. No exceptions. No "this is simple enough to handle directly." No "I have enough context to do this myself." The orchestrator's ONLY jobs are:
41
+
42
+ 1. **Interview** — ask the user questions to gather intent
43
+ 2. **Detect state** — check which `.aide`/`plan.aide`/`todo.aide` files exist
44
+ 3. **Delegate** — spawn the correct specialized agent for each phase
45
+ 4. **Relay** — present agent results to the user and collect approvals
46
+ 5. **Advance** — move to the next pipeline stage after approval
47
+
48
+ **You MUST NOT:**
49
+ - Write or edit `.aide`, `plan.aide`, `todo.aide`, or any code files yourself
50
+ - Fill in spec frontmatter, body sections, plans, or fixes yourself
51
+ - Make architectural, implementation, or domain decisions
52
+ - Run builds, tests, or validation yourself (agents do this)
53
+ - Skip a phase because you think you already know the answer
54
+ - Combine multiple phases into a single action
55
+
56
+ **Why this matters:** Each subagent has specialized context, model selection, and instructions that you lack. When you bypass delegation, you lose that context, burn tokens going down rabbit holes, produce drift from the methodology, and force expensive QA realignment. The cascading intent structure only works when each agent handles its own phase.
57
+
58
+ **Delegation means using the Agent tool** with the correct `subagent_type` for each phase:
59
+ - Stage 1 (Spec): `aide-spec-writer`
60
+ - Stage 2 (Research): `aide-domain-expert`
61
+ - Stage 3 (Synthesize): `aide-strategist`
62
+ - Stage 4 (Plan): `aide-architect`
63
+ - Stage 5 (Build): `aide-implementor`
64
+ - Stage 6 (QA): `aide-qa`
65
+ - Stage 7 (Fix): `aide-implementor` then `aide-qa`
66
+ - Refactor: `aide-auditor` (one per `.aide` section, then `aide-implementor` + `aide-qa`)
67
+ - Align: `aide-aligner`
68
+ - Bug investigation / non-pipeline work: `aide-explorer` (read-only) or `general-purpose` (if it needs to write files)
69
+
70
+ **Never use the generic `Explore` subagent type.** Use `aide-explorer` instead — it understands the AIDE methodology, uses `aide_discover` for `.aide` file lookups, and follows progressive disclosure. The generic `Explore` agent has no methodology context and will fall back to blind file searching.
71
+
72
+ **Every delegation prompt MUST include the rich discover context.** The boot sequence runs `aide_discover` without a path — that gives you the lightweight project map (locations and types only). But before delegating, you MUST also call `aide_discover` WITH the target module's path. This returns the rich output:
73
+
74
+ - The **ancestor chain** — the cascading intent lineage from root to target, with each ancestor's description and alignment status
75
+ - The **detailed subtree** — summaries extracted from file content, anomaly warnings
76
+
77
+ This rich output is what the agent needs to understand *what the module is supposed to do* before investigating *how it works*.
78
+
79
+ When you spawn any agent, include in the prompt:
80
+ 1. The rich `aide_discover(path)` output for the target module — ancestor chain + subtree details
81
+ 2. The specific task to perform
82
+
83
+ Without the ancestor chain, the agent has no cascading intent context and will treat files as isolated code instead of parts of a connected intent tree.
84
+
85
+ If you catch yourself about to write a file, edit code, or produce spec content — STOP. That is a subagent's job. Spawn the agent instead.
86
+
87
+ ## HARD CONSTRAINT — Learn the Methodology First
88
+
89
+ You already read the 4 methodology docs during boot (calls 1–4). This section explains what you learned and why it matters.
90
+
91
+ You are an orchestrator for a methodology you do not inherently know. The `.aide/docs/` directory contains the canonical definition. The 4 files you read give you:
92
+
93
+ - **`index.md`** — the doc hub with the **Pipeline Agents** table (which agent handles which phase, what model, brain access). This is your delegation reference.
94
+ - **`aide-spec.md`** — what a `.aide` spec looks like. Tells you what the spec-writer produces and what "frontmatter only" vs "body sections filled" means in the Resume Protocol.
95
+ - **`plan-aide.md`** — what a `plan.aide` looks like. Tells you what the architect produces and what "unchecked items" means.
96
+ - **`todo-aide.md`** — what a `todo.aide` looks like. Tells you what the QA agent produces.
97
+
98
+ **You do NOT need to read** `progressive-disclosure.md`, `agent-readable-code.md`, `automated-qa.md`, or `aide-template.md` — those are implementation details for the subagents, not for you.
99
+
100
+ ## HARD CONSTRAINT — Discover First
101
+
102
+ You already called `aide_discover` during boot (call 5). This section explains how to use what it returned.
103
+
104
+ **You MUST NOT** use Glob, Grep, Read, or any native file-searching tool to find or inspect `.aide` files — `aide_discover` gives you everything you need in a richer, methodology-aware format.
105
+
106
+ **What discover gave you:**
107
+ - The full cascading intent tree from root to leaves
108
+ - The current state of every `.aide`, `plan.aide`, and `todo.aide` file
109
+ - Which node in the tree the user's request maps to
110
+ - Enough context to route to the correct pipeline stage without additional file reads
111
+
112
+ **Use the discover output to:**
113
+ 1. Understand what the user is talking about and which part of the tree it refers to
114
+ 2. Determine the current pipeline state (see Resume Protocol below)
115
+ 3. Route to the correct stage
116
+
117
+ ## Routing — Explicit Intent Beats File State
118
+
119
+ **Before consulting the Resume Protocol, check whether the user explicitly requested a specific phase or flow.** If they did, route directly to that phase — the Resume Protocol does not apply.
120
+
121
+ Explicit requests override file state. Examples:
122
+ - "run an alignment check" → **Align**, even if file state says QA is next
123
+ - "do a refactor on src/tools/" → **Refactor**, even if no `plan.aide` exists
124
+ - "start the spec for this module" → **Stage 1 (Spec)**, even if a prior spec exists
125
+ - "plan this" → **Stage 4 (Plan)**, even if the spec has no body sections yet
126
+ - "run QA" → **Stage 6 (QA)**, even if `plan.aide` has unchecked items
127
+ - "build it" → **Stage 5 (Build)**, even if no plan exists yet (ask for one first)
128
+
129
+ **The Resume Protocol only fires when the user's request is ambiguous** — when they invoke `/aide` without specifying a phase, or describe what they want to do without naming a specific pipeline stage. In those cases, use file state to infer where to pick up.
130
+
131
+ ## Resume Protocol
132
+
133
+ When the user's request does not map to a specific phase, the discover output tells you the current state. The file state IS the pipeline state:
134
+
135
+ | State detected | Resume from |
136
+ |----------------|-------------|
137
+ | No `.aide` in target module | **Interview** — start from scratch |
138
+ | `.aide` exists with frontmatter only (no body sections) | **Research** or **Synthesize** — check if brain has research |
139
+ | `.aide` exists with body sections filled | **Plan** — spec is complete |
140
+ | `plan.aide` exists with unchecked items | **Build** — plan is ready |
141
+ | `plan.aide` fully checked, no `todo.aide` | **QA** — build is done |
142
+ | `todo.aide` exists with unchecked items | **Fix** — QA found issues |
143
+ | `todo.aide` fully checked | **Done** — promote retro to brain, report completion |
144
+
145
+ ## Pipeline
146
+
147
+ ### Stage 1: Interview → `aide:spec`
148
+
149
+ **Your job (orchestrator):** Gather just enough context from the user to give the spec-writer a clear delegation prompt. Ask the user:
150
+ - What module or feature is this for? Where does it live?
151
+ - A sentence or two about what they want to build
152
+ - Any domain knowledge already available in the brain? (Determines whether to skip research later)
153
+
154
+ You do NOT need a complete requirements interview — the `aide-spec-writer` agent conducts its own deep interview with the user. Your goal is to know enough to write a good delegation prompt.
155
+
156
+ **Then delegate** to the `aide-spec-writer` agent (via Agent tool, `subagent_type: aide-spec-writer`). The agent will:
157
+ - Interview the user about intent, success criteria, and failure modes
158
+ - Write the `.aide` frontmatter only (`scope`, `intent`, `outcomes.desired`, `outcomes.undesired`)
159
+ - Present the frontmatter to the user for confirmation
160
+
161
+ After the agent returns, relay the result and confirm the user is satisfied before advancing.
162
+
163
+ ### Stage 2: Research → `aide:research`
164
+
165
+ **Your job (orchestrator):** Ask the user whether domain knowledge already exists in the brain. If yes, skip to Stage 3. If no, delegate.
166
+
167
+ **Then delegate** to the `aide-domain-expert` agent (via Agent tool, `subagent_type: aide-domain-expert`). The agent will:
168
+ - Search web, vault, MCP memory for relevant domain sources
169
+ - Persist findings to the brain filed by **domain** (e.g., `research/email-marketing/`), not by project
170
+
171
+ Do NOT research anything yourself. The domain expert agent has specialized tools and context for this.
172
+
173
+ ### Stage 3: Synthesize → `aide:synthesize`
174
+
175
+ **Your job (orchestrator):** Confirm research is complete, then delegate.
176
+
177
+ **Then delegate** to the `aide-strategist` agent (via Agent tool, `subagent_type: aide-strategist`). The agent will:
178
+ - Use `aide_discover` to understand the intent tree
179
+ - Read the `.aide` frontmatter for intent
180
+ - Read the brain's research notes for domain knowledge
181
+ - Fill: `## Context`, `## Strategy`, `## Good examples`, `## Bad examples`
182
+
183
+ After the agent returns, present the completed spec to the user for review before advancing.
184
+
185
+ ### Stage 4: Plan → `aide:plan`
186
+
187
+ **Your job (orchestrator):** Confirm the spec is approved, then delegate.
188
+
189
+ **Then delegate** to the `aide-architect` agent (via Agent tool, `subagent_type: aide-architect`). The agent will:
190
+ - Read the complete `.aide` spec
191
+ - Pull the coding playbook from the brain
192
+ - Scan the codebase for existing patterns and helpers
193
+ - Write `plan.aide` next to the `.aide` — checkboxed steps, decisions documented
194
+
195
+ **PAUSE for user approval.** After the agent returns, present the plan to the user. Do not proceed to build until the user explicitly approves. If the user requests changes, re-delegate to the architect agent — do NOT edit the plan yourself.
196
+
197
+ ### Stage 5: Build → `aide:build`
198
+
199
+ **Your job (orchestrator):** Confirm the plan is approved, then read `plan.aide` and execute it step-by-step — one fresh implementor agent per numbered step.
200
+
201
+ **How to iterate:**
202
+ 1. Read `plan.aide` to identify the next unchecked numbered step
203
+ 2. Delegate to a fresh `aide-implementor` agent (via Agent tool, `subagent_type: aide-implementor`) with a prompt that includes:
204
+ - The path to the `.aide` spec and `plan.aide`
205
+ - Which numbered step to execute (quote it from the plan)
206
+ - If the step has lettered sub-steps (2a, 2b, 2c), include ALL of them — the agent executes the entire numbered group in one session
207
+
208
+ **Do NOT include** generic instructions to consult the coding playbook or load conventions from the brain. Each plan step already has a `Read:` list pointing the implementor to the specific playbook notes it needs — the implementor will load those notes itself. Do not duplicate or override the Read list in your delegation prompt.
209
+ 3. After the agent returns, verify the step's checkbox is checked
210
+ 4. Repeat from step 1 until all numbered steps are checked
211
+
212
+ **Lettered sub-steps:** When a plan step has lettered sub-steps (e.g., 3a, 3b, 3c), these are tightly coupled actions that share one agent session. Delegate ALL sub-steps of that number to a single implementor. Do NOT split lettered sub-steps across agents.
213
+
214
+ Do NOT write any code yourself. Do NOT run builds or tests yourself. The implementor handles all of this.
215
+
216
+ ### Stage 6: QA → `aide:qa`
217
+
218
+ **Your job (orchestrator):** Confirm the build is complete, then delegate.
219
+
220
+ **Then delegate** to the `aide-qa` agent (via Agent tool, `subagent_type: aide-qa`). The agent will:
221
+ - Compare actual output against `outcomes.desired`
222
+ - Check for `outcomes.undesired` violations
223
+ - Produce `todo.aide` with issues, misalignment tags, and retro
224
+
225
+ If the agent reports no issues, skip to completion.
226
+
227
+ ### Stage 7: Fix loop → `aide:fix`
228
+
229
+ **Your job (orchestrator):** Read `todo.aide` to identify unchecked items, then delegate each fix one at a time.
230
+
231
+ For each unchecked item:
232
+ 1. **Delegate** to the `aide-implementor` agent (via Agent tool, `subagent_type: aide-implementor`) to fix exactly ONE item
233
+ 2. **Delegate** to the `aide-qa` agent (via Agent tool, `subagent_type: aide-qa`) to re-validate
234
+
235
+ Repeat until `todo.aide` is clear. Do NOT fix anything yourself — always delegate to the implementor.
236
+
237
+ ### Completion
238
+
239
+ When all issues are resolved:
240
+ - Promote retro findings from `todo.aide` to the brain at `process/retro/`
241
+ - Report completion to the user with a summary of what was built
242
+
243
+ ### Refactor → `aide:refactor`
244
+
245
+ **This is NOT part of the feature pipeline.** Refactor is a separate flow that runs on code that already works and already passed QA. It audits existing code against the coding playbook and fixes convention drift.
246
+
247
+ **Detecting refactor intent:** If the user mentions refactoring, convention drift, playbook conformance, code style alignment, or "cleaning up" existing code — this is a refactor task, not a feature pipeline. Do NOT start the spec→research→plan→build flow. Route to the refactor flow instead.
248
+
249
+ **Refactor requires a path argument.** If the user doesn't provide one, ask for it. Never run a full-app refactor.
250
+
251
+ **How the refactor flow works:**
252
+
253
+ 1. **Discover sections.** Run `aide_discover` with the user's path to find all `.aide` specs in the subtree.
254
+
255
+ 2. **Audit each section.** For each `.aide` spec found, delegate to a fresh `aide-auditor` agent (via Agent tool, `subagent_type: aide-auditor`). The prompt must include:
256
+ - The path to the `.aide` spec to audit
257
+ - That this is a refactor audit, not a new feature plan
258
+
259
+ Each auditor reads the implementation, consults the coding playbook, and produces `plan.aide` with refactoring steps. You can run multiple auditors in parallel since they operate on independent sections.
260
+
261
+ 3. **Pause for approval.** Present ALL plans to the user. Do not proceed to execution until the user approves. If the user wants changes to a plan, re-delegate to the auditor for that section — do NOT edit plans yourself.
262
+
263
+ 4. **Execute refactoring.** For each approved `plan.aide`, delegate to `aide-implementor` agents — one fresh agent per numbered step, same as the build phase. Multiple sections can be executed in parallel since they are independent.
264
+
265
+ 5. **Re-validate.** After all plans are executed, delegate to `aide-qa` per section to verify that the refactoring didn't break spec conformance (the `outcomes` block must still hold).
266
+
267
+ 6. **Report completion.** Summarize drift items found, fixed, and verified across all sections.
268
+
269
+ ### Align → `aide:align`
270
+
271
+ **This is NOT part of the feature pipeline.** Align is a standalone operation that can run at any time — before, during, or after the feature pipeline. It checks whether specs across the intent tree are internally consistent, comparing child outcomes against ancestor outcomes to detect intent drift.
272
+
273
+ **Detecting alignment intent:** If the user mentions alignment checking, spec consistency, intent drift, cascading outcomes, or whether child specs contradict ancestor specs — this is an align task. Do NOT start the spec→research→plan→build flow. Route to the align flow instead.
274
+
275
+ **How the align flow works:**
276
+
277
+ 1. **Confirm the target path.** If the user doesn't provide a path, ask for one. Never run alignment on the full repository root without explicit intent.
278
+
279
+ 2. **Delegate to the aligner.** Delegate to a fresh `aide-aligner` agent (via Agent tool, `subagent_type: aide-aligner`). The prompt must include:
280
+ - The target path to align
281
+ - That this is a spec-vs-spec alignment check, not a code-vs-spec QA check
282
+
283
+ 3. **Relay results.** The aligner returns a verdict (ALIGNED/MISALIGNED), counts of specs checked and misalignments found, and `todo.aide` paths for any misaligned nodes. Present this to the user. If misalignments were found, suggest running `/aide:spec` on the flagged specs to resolve them.
284
+
285
+ **Suggesting alignment (proactive guidance):** The orchestrator should suggest `/aide:align` in two situations — it is a suggestion, not automatic invocation:
286
+ - When `aide_discover` output shows `status: misaligned` on any spec in the tree
287
+ - When a spec edit (Stage 1) modifies `outcomes.desired` or `outcomes.undesired` — a changed outcome may now conflict with a child or ancestor spec
288
+
289
+ ## Rules
290
+
291
+ - **DELEGATE EVERYTHING.** The orchestrator NEVER writes files, edits code, fills specs, creates plans, runs tests, or does any substantive work. Every phase is handled by its specialized agent via the Agent tool. This is the single most important rule. If you are tempted to "just do it quickly" — don't. Spawn the agent.
292
+ - **Every stage gets fresh context.** No agent carries conversation from a prior stage. Handoff is via files only: `.aide`, `plan.aide`, `todo.aide`, brain notes.
293
+ - **`aide_discover` is mandatory, not optional.** The orchestrator MUST run `aide_discover` as its very first action on every `/aide` invocation. Do not use native file-search tools (Glob, Grep, Read) to find `.aide` files — the discover tool provides richer, methodology-aware context.
294
+ - **Pause for approval twice:** after spec frontmatter (Stage 1) and after plan (Stage 4). These are the two points where the user's input shapes the work.
295
+ - **Detect and resume.** If the user runs `/aide` mid-pipeline, detect state from existing files and resume from the correct stage. Never restart from scratch if prior work exists.
296
+ - **Research is filed by domain.** Brain notes go to `research/<domain>/`, not `research/<project>/`. The knowledge is reusable across projects.
297
+ - **Retro is promoted.** When the fix loop closes, extract the `## Retro` section and persist it to `process/retro/` in the brain. This is how the pipeline learns.
298
+ - **No shortcuts.** Even if the task seems trivial, the pipeline exists to maintain intent alignment. A "simple" task handled outside the pipeline is how drift starts. Always delegate.
299
+ - **Suggest alignment, don't force it.** When discover output shows `status: misaligned` on any spec, or when a spec edit touches outcomes, suggest `/aide:align` to the user. Do not invoke it automatically — misalignment is informational, not a pipeline gate. The user decides whether to act.
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  scope: .claude/skills/brain
3
+ description: >
4
+ Spec for the /brain skill — a thin dispatcher that reads the vault CLAUDE.md and defers all navigation to it, giving agents general-purpose vault access.
3
5
  intent: >
4
6
  The /brain skill gives agents in host projects a general-purpose interface
5
7
  to the user's Obsidian vault. The skill prompt is deliberately minimal: it
@@ -26,11 +28,11 @@ outcomes:
26
28
  installSkills pipeline — registered in DOC_PATHS and SKILL_DOCS,
27
29
  installed to the host's skill directory, subject to the same
28
30
  idempotency and upgrade contracts as study-playbook.
29
- - The skill prompt distinguishes itself from study-playbook by scope:
31
+ - "The skill prompt distinguishes itself from study-playbook by scope:
30
32
  study-playbook is limited to the coding playbook hub, while /brain
31
33
  is the general-purpose entry point for any vault query — research,
32
34
  project context, environment, identity, references, or any other
33
- vault content the user has organized.
35
+ vault content the user has organized."
34
36
  undesired:
35
37
  - A skill prompt that hardcodes vault navigation rules, directory
36
38
  paths, hub locations, or routing tables. This creates two sources
@@ -1,4 +1,6 @@
1
1
  ---
2
+ description: >
3
+ Plan to ship the /brain skill — create the SKILL.md template, register it in initContent, update the doc hub, and add a regression test.
2
4
  intent: >
3
5
  Ship the /brain skill — a thin-dispatcher SKILL.md template that tells
4
6
  agents to read the vault's root CLAUDE.md via the Obsidian MCP and follow
@@ -38,15 +38,17 @@ export default function App({ root, initialNodes }) {
38
38
  const [drillCache] = useState(new Map());
39
39
  // Single expanded section in drill-in mode; Tab cycles through sections.
40
40
  const [expandedSection, setExpandedSection] = useState(null);
41
- // --- Detail panel frontmatter (for currently selected file) ---
41
+ // --- Detail panel frontmatter + body (for currently selected file) ---
42
42
  const [selectedFrontmatter, setSelectedFrontmatter] = useState(null);
43
+ const [selectedBody, setSelectedBody] = useState("");
43
44
  const [fmCache] = useState(new Map());
44
45
  /** Returns true if any file descendant of node matches the search filter. */
45
46
  function hasMatchingDescendant(node, filter) {
46
47
  if (node.kind === "file") {
47
48
  const lower = filter.toLowerCase();
48
49
  return (node.file.relativePath.toLowerCase().includes(lower) ||
49
- (node.file.summary ?? "").toLowerCase().includes(lower));
50
+ (node.file.summary ?? "").toLowerCase().includes(lower) ||
51
+ (node.file.description ?? "").toLowerCase().includes(lower));
50
52
  }
51
53
  return node.children.some((child) => hasMatchingDescendant(child, filter));
52
54
  }
@@ -58,8 +60,10 @@ export default function App({ root, initialNodes }) {
58
60
  if (fn.node.kind === "dir") {
59
61
  return hasMatchingDescendant(fn.node, searchFilter);
60
62
  }
61
- return (fn.node.file.relativePath.toLowerCase().includes(searchFilter.toLowerCase()) ||
62
- (fn.node.file.summary ?? "").toLowerCase().includes(searchFilter.toLowerCase()));
63
+ const lower = searchFilter.toLowerCase();
64
+ return (fn.node.file.relativePath.toLowerCase().includes(lower) ||
65
+ (fn.node.file.summary ?? "").toLowerCase().includes(lower) ||
66
+ (fn.node.file.description ?? "").toLowerCase().includes(lower));
63
67
  })
64
68
  : flatNodes;
65
69
  // Clamp cursor within visible range.
@@ -75,25 +79,30 @@ export default function App({ root, initialNodes }) {
75
79
  // Computed booleans for the cursor's current position.
76
80
  const cursorOnDir = cursorNode?.node.kind === "dir";
77
81
  const cursorDirExpanded = cursorOnDir && cursorNode.node.kind === "dir" && expandedDirs.has(cursorNode.node.path);
78
- // Load frontmatter for the detail panel whenever selectedFile changes.
82
+ // Load frontmatter + body for the detail panel whenever selectedFile changes.
79
83
  useEffect(() => {
80
84
  if (!selectedFile) {
81
85
  setSelectedFrontmatter(null);
86
+ setSelectedBody("");
82
87
  return;
83
88
  }
84
89
  if (fmCache.has(selectedFile.path)) {
85
- setSelectedFrontmatter(fmCache.get(selectedFile.path) ?? null);
90
+ const cached = fmCache.get(selectedFile.path);
91
+ setSelectedFrontmatter(cached.frontmatter);
92
+ setSelectedBody(cached.body);
86
93
  return;
87
94
  }
88
95
  readFile(selectedFile.path, "utf-8")
89
96
  .then((content) => {
90
- const { frontmatter } = parseFrontmatter(content);
91
- fmCache.set(selectedFile.path, frontmatter);
97
+ const { frontmatter, body } = parseFrontmatter(content);
98
+ fmCache.set(selectedFile.path, { frontmatter, body });
92
99
  setSelectedFrontmatter(frontmatter);
100
+ setSelectedBody(body);
93
101
  })
94
102
  .catch(() => {
95
- fmCache.set(selectedFile.path, null);
103
+ fmCache.set(selectedFile.path, { frontmatter: null, body: "" });
96
104
  setSelectedFrontmatter(null);
105
+ setSelectedBody("");
97
106
  });
98
107
  }, [selectedFile?.path]);
99
108
  /** Load and parse a file for drill-in view. */
@@ -109,12 +118,12 @@ export default function App({ root, initialNodes }) {
109
118
  const content = await readFile(file.path, "utf-8");
110
119
  const { frontmatter, body } = parseFrontmatter(content);
111
120
  const sections = parseBody(body);
112
- const data = { frontmatter, sections };
121
+ const data = { frontmatter, body, sections };
113
122
  drillCache.set(file.path, data);
114
123
  setDrillData(data);
115
124
  }
116
125
  catch {
117
- setDrillData({ frontmatter: null, sections: [] });
126
+ setDrillData({ frontmatter: null, body: "", sections: [] });
118
127
  }
119
128
  }, [drillCache]);
120
129
  /** Toggle deep view on/off, caching shallow results for instant restore. */
@@ -277,6 +286,6 @@ export default function App({ root, initialNodes }) {
277
286
  // Enter is a no-op in drill-in mode.
278
287
  });
279
288
  // --- Layout ---
280
- const treeWidth = Math.floor(columns * 0.38);
281
- return (_jsxs(Box, { flexDirection: "row", width: columns, children: [_jsxs(Box, { flexDirection: "column", width: treeWidth, borderStyle: "single", borderColor: "white", children: [_jsx(Text, { bold: true, children: " Intent Tree" }), deepLoading && _jsx(Text, { color: "yellow", children: " Loading summaries..." }), _jsx(TreePanel, { visibleNodes: visibleNodes, cursorIndex: clampedCursor, searchFilter: searchFilter, isDeepView: isDeepView, expandedDirs: expandedDirs, cursorOnDir: cursorOnDir, cursorDirExpanded: cursorDirExpanded, width: treeWidth - 2 })] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "single", borderColor: "white", children: [_jsx(Text, { bold: true, children: " Detail" }), _jsx(DetailPanel, { file: selectedFile, frontmatter: mode === "drill-in" ? (drillData?.frontmatter ?? null) : selectedFrontmatter, mode: mode === "drill-in" ? "drill-in" : "preview", sections: drillData?.sections ?? [], expandedSection: expandedSection, drilledFilePath: drilledFile?.relativePath ?? null })] })] }));
289
+ const treeWidth = Math.floor(columns * 0.57);
290
+ return (_jsxs(Box, { flexDirection: "row", width: columns, children: [_jsxs(Box, { flexDirection: "column", width: treeWidth, borderStyle: "single", borderColor: "white", children: [_jsx(Text, { bold: true, children: " Intent Tree" }), deepLoading && _jsx(Text, { color: "yellow", children: " Loading summaries..." }), _jsx(TreePanel, { visibleNodes: visibleNodes, cursorIndex: clampedCursor, searchFilter: searchFilter, isDeepView: isDeepView, expandedDirs: expandedDirs, cursorOnDir: cursorOnDir, cursorDirExpanded: cursorDirExpanded, width: treeWidth - 2 })] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "single", borderColor: "white", children: [_jsx(Text, { bold: true, children: " Detail" }), _jsx(DetailPanel, { file: selectedFile, frontmatter: mode === "drill-in" ? (drillData?.frontmatter ?? null) : selectedFrontmatter, body: mode === "drill-in" ? (drillData?.body ?? "") : selectedBody, mode: mode === "drill-in" ? "drill-in" : "preview", sections: drillData?.sections ?? [], expandedSection: expandedSection, drilledFilePath: drilledFile?.relativePath ?? null })] })] }));
282
291
  }
@@ -3,6 +3,8 @@ import type { AideFile, AideFrontmatter, BodySection } from "../../types/index.j
3
3
  interface DetailPanelProps {
4
4
  file: AideFile | null;
5
5
  frontmatter: AideFrontmatter | null;
6
+ /** Raw body content of the selected or drilled-in file. Used by plan/todo renderers. */
7
+ body: string;
6
8
  /** Controls which rendering mode is active in the right panel. */
7
9
  mode: "preview" | "drill-in";
8
10
  /** Body sections from the drilled-in file. */
@@ -16,9 +18,11 @@ interface DetailPanelProps {
16
18
  * Right-panel component that handles both preview mode (tree navigation) and
17
19
  * drill-in mode (formatted frontmatter card with expandable body sections).
18
20
  *
19
- * In preview mode: scope, truncated intent, and outcome counts.
20
- * In drill-in mode: full frontmatter card (scope heading, full intent, side-by-side
21
- * outcomes) plus expandable body sections cycled with Tab.
21
+ * Delegates to RenderPlanDetail for plan files and RenderTodoDetail for todo files.
22
+ * Intent and research files use the intent-card layout (scope, intent, outcomes).
23
+ *
24
+ * In preview mode: scope, truncated intent, and outcome counts (or plan/todo summary).
25
+ * In drill-in mode: full frontmatter card or plan/todo detail view.
22
26
  */
23
- export default function DetailPanel({ file, frontmatter, mode, sections, expandedSection, drilledFilePath, }: DetailPanelProps): React.ReactElement;
27
+ export default function DetailPanel({ file, frontmatter, body, mode, sections, expandedSection, drilledFilePath, }: DetailPanelProps): React.ReactElement;
24
28
  export {};
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useStdout } from "ink";
3
+ import RenderPlanDetail from "./renderPlanDetail/index.js";
4
+ import RenderTodoDetail from "./renderTodoDetail/index.js";
3
5
  /** Truncate a string to maxLen chars, appending "..." if trimmed. */
4
6
  function truncate(s, maxLen) {
5
7
  if (s.length <= maxLen)
@@ -21,11 +23,13 @@ function OutcomesDisplay({ desired, undesired, wide, }) {
21
23
  * Right-panel component that handles both preview mode (tree navigation) and
22
24
  * drill-in mode (formatted frontmatter card with expandable body sections).
23
25
  *
24
- * In preview mode: scope, truncated intent, and outcome counts.
25
- * In drill-in mode: full frontmatter card (scope heading, full intent, side-by-side
26
- * outcomes) plus expandable body sections cycled with Tab.
26
+ * Delegates to RenderPlanDetail for plan files and RenderTodoDetail for todo files.
27
+ * Intent and research files use the intent-card layout (scope, intent, outcomes).
28
+ *
29
+ * In preview mode: scope, truncated intent, and outcome counts (or plan/todo summary).
30
+ * In drill-in mode: full frontmatter card or plan/todo detail view.
27
31
  */
28
- export default function DetailPanel({ file, frontmatter, mode, sections, expandedSection, drilledFilePath, }) {
32
+ export default function DetailPanel({ file, frontmatter, body, mode, sections, expandedSection, drilledFilePath, }) {
29
33
  const { stdout } = useStdout();
30
34
  const columns = stdout?.columns ?? 80;
31
35
  const wide = columns >= 80;
@@ -34,6 +38,14 @@ export default function DetailPanel({ file, frontmatter, mode, sections, expande
34
38
  if (!file) {
35
39
  return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Text, { color: "gray", children: "Select a file to preview" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Type to search, [tab] for deep view" }) })] }));
36
40
  }
41
+ // Delegate to type-specific renderers for plan and todo files.
42
+ if (file.type === "plan") {
43
+ return _jsx(RenderPlanDetail, { file: file, frontmatter: frontmatter, mode: "preview", body: body, drilledFilePath: null });
44
+ }
45
+ if (file.type === "todo") {
46
+ const description = frontmatter?.description ?? file.description ?? "";
47
+ return _jsx(RenderTodoDetail, { description: description, body: body, mode: "preview", filePath: file.relativePath });
48
+ }
37
49
  if (!frontmatter) {
38
50
  return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Text, { color: "red", children: "[FAILED TO PARSE]" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: file.relativePath }) })] }));
39
51
  }
@@ -44,6 +56,14 @@ export default function DetailPanel({ file, frontmatter, mode, sections, expande
44
56
  return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["scope: ", scope] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { wrap: "wrap", children: intent }) }), (desiredCount > 0 || undesiredCount > 0) && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "green", children: ["\u2713 desired (", desiredCount, ")"] }), _jsxs(Text, { color: "red", children: ["\u2717 undesired (", undesiredCount, ")"] })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "[\u2191\u2193] navigate [enter] drill in [tab] deep view" }) })] }));
45
57
  }
46
58
  // --- Drill-in mode ---
59
+ // Delegate to type-specific renderers for plan and todo files.
60
+ if (file?.type === "plan") {
61
+ return _jsx(RenderPlanDetail, { file: file, frontmatter: frontmatter, mode: "drill-in", body: body, drilledFilePath: drilledFilePath });
62
+ }
63
+ if (file?.type === "todo") {
64
+ const description = frontmatter?.description ?? file?.description ?? "";
65
+ return _jsx(RenderTodoDetail, { description: description, body: body, mode: "drill-in", filePath: drilledFilePath ?? file?.relativePath ?? "" });
66
+ }
47
67
  const title = drilledFilePath ?? "[unknown]";
48
68
  const scope = frontmatter?.scope ?? "[FAILED TO PARSE]";
49
69
  const intent = frontmatter?.intent ?? "[FAILED TO PARSE]";
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import type { AideFile, AideFrontmatter } from "../../../types/index.js";
3
+ interface RenderPlanDetailProps {
4
+ file: AideFile;
5
+ frontmatter: AideFrontmatter | null;
6
+ /** Controls which rendering mode is active in the right panel. */
7
+ mode: "preview" | "drill-in";
8
+ /** Raw body content of the plan file. */
9
+ body: string;
10
+ /** File path shown as the panel title during drill-in, or null in preview mode. */
11
+ drilledFilePath: string | null;
12
+ }
13
+ /**
14
+ * Detail panel renderer for plan files (.aide files of type "plan").
15
+ *
16
+ * Preview mode: description from frontmatter, progress fraction, remaining count.
17
+ * Drill-in mode: grouped checklist items by step heading, completion summary at top.
18
+ */
19
+ export default function RenderPlanDetail({ file, frontmatter, mode, body, drilledFilePath, }: RenderPlanDetailProps): React.ReactElement;
20
+ export {};
@@ -0,0 +1,30 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import parsePlanItems from "./parsePlanItems/index.js";
4
+ /** Renders a compact ASCII progress bar of fixed width. */
5
+ function ProgressBar({ done, total, width }) {
6
+ const filled = total > 0 ? Math.round((done / total) * width) : 0;
7
+ const bar = "█".repeat(filled) + "░".repeat(width - filled);
8
+ return _jsxs(Text, { color: "cyan", children: ["[", bar, "]"] });
9
+ }
10
+ /**
11
+ * Detail panel renderer for plan files (.aide files of type "plan").
12
+ *
13
+ * Preview mode: description from frontmatter, progress fraction, remaining count.
14
+ * Drill-in mode: grouped checklist items by step heading, completion summary at top.
15
+ */
16
+ export default function RenderPlanDetail({ file, frontmatter, mode, body, drilledFilePath, }) {
17
+ const steps = parsePlanItems(body);
18
+ const allItems = steps.flatMap((s) => s.items);
19
+ const doneCount = allItems.filter((i) => i.done).length;
20
+ const totalCount = allItems.length;
21
+ const remainingCount = totalCount - doneCount;
22
+ // --- Preview mode ---
23
+ if (mode === "preview") {
24
+ const description = frontmatter?.description ?? file.description ?? "";
25
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [description !== "" && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { wrap: "wrap", children: description }) })), _jsxs(Box, { flexDirection: "row", gap: 1, alignItems: "center", children: [_jsx(ProgressBar, { done: doneCount, total: totalCount, width: 20 }), _jsxs(Text, { children: [doneCount, "/", totalCount, " complete"] })] }), remainingCount > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", children: [remainingCount, " item", remainingCount !== 1 ? "s" : "", " remaining"] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "[\u2191\u2193] navigate [enter] drill in [tab] deep view" }) })] }));
26
+ }
27
+ // --- Drill-in mode ---
28
+ const title = drilledFilePath ?? file.relativePath;
29
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, flexGrow: 1, children: [_jsx(Text, { bold: true, children: title }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { bold: true, color: doneCount === totalCount && totalCount > 0 ? "green" : "cyan", children: ["Progress: ", doneCount, "/", totalCount, " step", totalCount !== 1 ? "s" : "", " complete"] }) }), steps.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: steps.map((s, si) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [s.step !== "" && (_jsx(Text, { bold: true, children: s.step })), s.items.map((item, ii) => (_jsxs(Box, { flexDirection: "row", marginLeft: s.step !== "" ? 2 : 0, children: [item.done ? (_jsx(Text, { color: "green", children: "\u2713 " })) : (_jsx(Text, { color: "gray", children: "\u25CB " })), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: item.done ? "gray" : undefined, wrap: "wrap", children: item.text }) })] }, ii)))] }, si))) })), totalCount === 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "No checklist items found." }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "[esc] back [e] open in editor" }) })] }));
30
+ }
@@ -0,0 +1,32 @@
1
+ /** A single checklist item within a plan step. */
2
+ export interface PlanItem {
3
+ text: string;
4
+ done: boolean;
5
+ }
6
+ /** A plan step grouping with its heading label and checklist items. */
7
+ export interface PlanStep {
8
+ step: string;
9
+ done: boolean;
10
+ items: PlanItem[];
11
+ }
12
+ /**
13
+ * Parse a plan file body string into structured step groups with checklist items.
14
+ *
15
+ * Recognises three heading formats found in this project's plan files:
16
+ *
17
+ * 1. `### N. [x] Step title` — numbered with inline checkbox (cli/plan.aide)
18
+ * 2. `### N. Step title` — numbered without inline checkbox
19
+ * 3. `### Phase N — Title` — Phase-prefixed with em-dash (init/plan.aide)
20
+ *
21
+ * Checklist items below a heading are lines matching `- [x]` or `- [ ]`.
22
+ * Prose items (non-checklist bullet lines) and all other non-heading lines
23
+ * are ignored. Items that appear before any heading are grouped under an
24
+ * empty-string step.
25
+ *
26
+ * The `done` field on a `PlanStep` is determined as follows:
27
+ * - If the heading carries an inline `[x]`/`[ ]` marker (format 1), that
28
+ * marker is authoritative — `done` is not overridden by item states.
29
+ * - Otherwise `done` is derived: true when all contained items are done,
30
+ * false when any item is undone or the step has no items.
31
+ */
32
+ export default function parsePlanItems(body: string): PlanStep[];
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Parse a plan file body string into structured step groups with checklist items.
3
+ *
4
+ * Recognises three heading formats found in this project's plan files:
5
+ *
6
+ * 1. `### N. [x] Step title` — numbered with inline checkbox (cli/plan.aide)
7
+ * 2. `### N. Step title` — numbered without inline checkbox
8
+ * 3. `### Phase N — Title` — Phase-prefixed with em-dash (init/plan.aide)
9
+ *
10
+ * Checklist items below a heading are lines matching `- [x]` or `- [ ]`.
11
+ * Prose items (non-checklist bullet lines) and all other non-heading lines
12
+ * are ignored. Items that appear before any heading are grouped under an
13
+ * empty-string step.
14
+ *
15
+ * The `done` field on a `PlanStep` is determined as follows:
16
+ * - If the heading carries an inline `[x]`/`[ ]` marker (format 1), that
17
+ * marker is authoritative — `done` is not overridden by item states.
18
+ * - Otherwise `done` is derived: true when all contained items are done,
19
+ * false when any item is undone or the step has no items.
20
+ */
21
+ export default function parsePlanItems(body) {
22
+ const lines = body.split("\n");
23
+ const steps = [];
24
+ let current = null;
25
+ for (const raw of lines) {
26
+ const line = raw.trim();
27
+ // Format 1: ### N. [x] Step title (inline checkbox in heading)
28
+ const inlineCheckHeading = line.match(/^###\s+\d+\.\s+\[(x| )\]\s+(.+)$/i);
29
+ if (inlineCheckHeading) {
30
+ current = {
31
+ step: inlineCheckHeading[2].trim(),
32
+ done: inlineCheckHeading[1].toLowerCase() === "x",
33
+ items: [],
34
+ _headingCheckbox: true,
35
+ };
36
+ steps.push(current);
37
+ continue;
38
+ }
39
+ // Format 2: ### N. Step title (no inline checkbox)
40
+ const numberedHeading = line.match(/^###\s+\d+\.\s+(.+)$/);
41
+ if (numberedHeading) {
42
+ current = { step: numberedHeading[1].trim(), done: false, items: [], _headingCheckbox: false };
43
+ steps.push(current);
44
+ continue;
45
+ }
46
+ // Format 3: ### Phase N — Title (Phase prefix with em-dash, en-dash, or hyphen)
47
+ const phaseHeading = line.match(/^###\s+Phase\s+\d+\s+[—–-]+\s+(.+)$/i);
48
+ if (phaseHeading) {
49
+ current = { step: phaseHeading[1].trim(), done: false, items: [], _headingCheckbox: false };
50
+ steps.push(current);
51
+ continue;
52
+ }
53
+ const checkedMatch = line.match(/^-\s+\[x\]\s+(.+)$/i);
54
+ if (checkedMatch) {
55
+ if (!current) {
56
+ current = { step: "", done: false, items: [], _headingCheckbox: false };
57
+ steps.push(current);
58
+ }
59
+ current.items.push({ text: checkedMatch[1].trim(), done: true });
60
+ continue;
61
+ }
62
+ const uncheckedMatch = line.match(/^-\s+\[ \]\s+(.+)$/);
63
+ if (uncheckedMatch) {
64
+ if (!current) {
65
+ current = { step: "", done: false, items: [], _headingCheckbox: false };
66
+ steps.push(current);
67
+ }
68
+ current.items.push({ text: uncheckedMatch[1].trim(), done: false });
69
+ }
70
+ }
71
+ // Derive done for steps whose heading had no inline checkbox:
72
+ // true only when all items are done and at least one item exists.
73
+ for (const step of steps) {
74
+ if (!step._headingCheckbox && step.items.length > 0) {
75
+ step.done = step.items.every((item) => item.done);
76
+ }
77
+ }
78
+ // Strip the internal field before returning.
79
+ return steps.map(({ _headingCheckbox: _hc, ...rest }) => rest);
80
+ }
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ interface RenderTodoDetailProps {
3
+ /** Frontmatter description field, shown as the preview summary. */
4
+ description: string;
5
+ /** Raw body content of the todo file. */
6
+ body: string;
7
+ /** Controls which rendering mode is active. */
8
+ mode: "preview" | "drill-in";
9
+ /** File path, used as the drill-in panel title. */
10
+ filePath: string;
11
+ }
12
+ /**
13
+ * Renders a todo.aide file in preview mode (summary counts) or drill-in mode
14
+ * (full issue list with misalignment annotations highlighted and completion state).
15
+ */
16
+ export default function RenderTodoDetail({ description, body, mode, filePath, }: RenderTodoDetailProps): React.ReactElement;
17
+ export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import parseTodoItems from "./parseTodoItems/index.js";
4
+ /**
5
+ * Renders a todo.aide file in preview mode (summary counts) or drill-in mode
6
+ * (full issue list with misalignment annotations highlighted and completion state).
7
+ */
8
+ export default function RenderTodoDetail({ description, body, mode, filePath, }) {
9
+ const items = parseTodoItems(body);
10
+ const totalCount = items.length;
11
+ const doneCount = items.filter((item) => item.done).length;
12
+ const openCount = totalCount - doneCount;
13
+ const misalignmentCount = items.filter((item) => item.misalignment !== undefined).length;
14
+ if (mode === "preview") {
15
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [description ? (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { wrap: "wrap", children: description }) })) : null, _jsxs(Text, { children: ["Issues:", " ", _jsxs(Text, { color: openCount > 0 ? "yellow" : "green", children: [openCount, " open"] }), ", ", _jsxs(Text, { color: "green", children: [doneCount, " resolved"] }), " (", _jsxs(Text, { children: [totalCount, " total"] }), ")"] }), misalignmentCount > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u2691 ", misalignmentCount, " misalignment annotation", misalignmentCount !== 1 ? "s" : ""] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "[\u2191\u2193] navigate [enter] drill in [tab] deep view" }) })] }));
16
+ }
17
+ // Drill-in mode — full issue list
18
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, flexGrow: 1, children: [_jsx(Text, { bold: true, children: filePath }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Issues:", " ", _jsxs(Text, { color: openCount > 0 ? "yellow" : "green", children: [openCount, " open"] }), ", ", _jsxs(Text, { color: "green", children: [doneCount, " resolved"] }), " (", _jsxs(Text, { children: [totalCount, " total"] }), ")"] }) }), items.length === 0 ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "No checklist items found." }) })) : (_jsx(Box, { flexDirection: "column", marginTop: 1, children: items.map((item, i) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { flexDirection: "row", children: [item.done ? (_jsx(Text, { color: "green", children: "\u2713 " })) : (_jsx(Text, { color: "gray", children: "\u25CB " })), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: item.misalignment !== undefined ? "yellow" : undefined, wrap: "wrap", children: item.text }) })] }), item.misalignment !== undefined && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "red", children: ["\u2691 Misalignment: ", item.misalignment] }) }))] }, i))) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "[esc] back [e] open in editor" }) })] }));
19
+ }
@@ -0,0 +1,26 @@
1
+ /** A single parsed checklist item from a todo.aide body. */
2
+ export interface TodoItem {
3
+ /** The main text of the checklist item (first line only, not continuation lines). */
4
+ text: string;
5
+ /** Whether the item is checked (`- [x]`). */
6
+ done: boolean;
7
+ /**
8
+ * The Misalignment annotation extracted from a continuation line, if present.
9
+ * e.g. "implementation-drift" from a line like " Misalignment: implementation-drift"
10
+ */
11
+ misalignment?: string;
12
+ }
13
+ /**
14
+ * Parses the body of a todo.aide file into a structured array of checklist items.
15
+ *
16
+ * Format recognised:
17
+ * - `- [x] item text` — completed item
18
+ * - `- [ ] item text` — open item
19
+ * Continuation lines (indented lines that follow a checklist item) are scanned
20
+ * for a `Misalignment:` annotation. The first such annotation found is attached
21
+ * to the preceding item. All other continuation lines are ignored.
22
+ *
23
+ * Lines that are not checklist items and not continuations of a checklist item
24
+ * (e.g. `##` headings, blank lines, Retro sections) are ignored.
25
+ */
26
+ export default function parseTodoItems(body: string): TodoItem[];
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Parses the body of a todo.aide file into a structured array of checklist items.
3
+ *
4
+ * Format recognised:
5
+ * - `- [x] item text` — completed item
6
+ * - `- [ ] item text` — open item
7
+ * Continuation lines (indented lines that follow a checklist item) are scanned
8
+ * for a `Misalignment:` annotation. The first such annotation found is attached
9
+ * to the preceding item. All other continuation lines are ignored.
10
+ *
11
+ * Lines that are not checklist items and not continuations of a checklist item
12
+ * (e.g. `##` headings, blank lines, Retro sections) are ignored.
13
+ */
14
+ export default function parseTodoItems(body) {
15
+ const lines = body.split("\n");
16
+ const items = [];
17
+ let current = null;
18
+ for (const line of lines) {
19
+ const checkboxMatch = line.match(/^- \[(x| )\] (.+)/);
20
+ if (checkboxMatch) {
21
+ // Flush previous item before starting a new one
22
+ if (current)
23
+ items.push(current);
24
+ current = {
25
+ text: checkboxMatch[2].trim(),
26
+ done: checkboxMatch[1] === "x",
27
+ };
28
+ continue;
29
+ }
30
+ // Continuation line — only meaningful after a checklist item
31
+ if (current && line.match(/^\s+/)) {
32
+ const misalignmentMatch = line.match(/\bMisalignment:\s*(.+)/);
33
+ if (misalignmentMatch && !current.misalignment) {
34
+ current.misalignment = misalignmentMatch[1].trim();
35
+ }
36
+ continue;
37
+ }
38
+ // Non-item, non-continuation line — flush any pending item
39
+ if (current) {
40
+ items.push(current);
41
+ current = null;
42
+ }
43
+ }
44
+ // Flush the last item if body ended while an item was open
45
+ if (current)
46
+ items.push(current);
47
+ return items;
48
+ }
@@ -1,4 +1,4 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  /** Type-tag display labels keyed by AideFileType. */
4
4
  const TYPE_TAG = {
@@ -22,7 +22,24 @@ function renderRow(flatNode, index, cursorIndex, isDeepView, expandedDirs, width
22
22
  if (node.kind === "dir") {
23
23
  const label = node.path === "." ? ". /" : `${node.path}/`;
24
24
  const expandIndicator = expandedDirs.has(node.path) ? "v " : "> ";
25
- return (_jsx(Box, { children: _jsxs(Text, { bold: isCursor, color: isCursor ? "white" : "gray", children: [indent, expandIndicator, label] }) }, `dir-${node.path}-${index}`));
25
+ // Find the first intent child to surface its status and description on the dir row.
26
+ const intentChild = node.children.find((c) => c.kind === "file" && c.file.type === "intent");
27
+ const intentFile = intentChild?.kind === "file" ? intentChild.file : null;
28
+ const dirStatusBadge = intentFile?.status === "aligned"
29
+ ? { text: " [aligned]", color: "green" }
30
+ : intentFile?.status === "misaligned"
31
+ ? { text: " [misaligned]", color: "red" }
32
+ : null;
33
+ const dirDescription = intentFile?.description ?? "";
34
+ // Truncate description to fit within available panel width.
35
+ const dirFixedLen = indent.length + expandIndicator.length + label.length + (dirStatusBadge?.text.length ?? 0);
36
+ const dirRemaining = width - dirFixedLen;
37
+ let dirSummaryText = "";
38
+ if (dirDescription && dirRemaining > 10) {
39
+ const full = ` — ${dirDescription}`;
40
+ dirSummaryText = full.length <= dirRemaining ? full : `${full.slice(0, dirRemaining - 3)}…`;
41
+ }
42
+ return (_jsx(Box, { children: _jsxs(Text, { bold: isCursor, color: isCursor ? "white" : "gray", wrap: "truncate", children: [indent, expandIndicator, label, dirStatusBadge ? _jsx(Text, { color: dirStatusBadge.color, children: dirStatusBadge.text }) : null, dirSummaryText ? _jsx(Text, { color: "gray", children: dirSummaryText }) : null] }) }, `dir-${node.path}-${index}`));
26
43
  }
27
44
  // File node — render as a single <Text> to prevent Ink from wrapping mid-element.
28
45
  const { file } = node;
@@ -32,15 +49,26 @@ function renderRow(flatNode, index, cursorIndex, isDeepView, expandedDirs, width
32
49
  const tagColor = TYPE_COLOR[file.type] ?? "white";
33
50
  const prefix = `${indent}${connector}${filename} `;
34
51
  const tagStr = `[${tag}]`;
35
- // Truncate summary to fit within available panel width.
36
- const fixedLen = prefix.length + tagStr.length;
52
+ // Determine status badge text and color when a status flag is present.
53
+ const statusBadge = file.status
54
+ ? file.status === "aligned"
55
+ ? { text: " [aligned]", color: "green" }
56
+ : { text: " [misaligned]", color: "red" }
57
+ : null;
58
+ // Truncate summary/description to fit within available panel width.
59
+ const statusLen = statusBadge ? statusBadge.text.length : 0;
60
+ const fixedLen = prefix.length + tagStr.length + statusLen;
37
61
  const remaining = width - fixedLen;
38
- let summary = "";
39
- if (isDeepView && file.summary && remaining > 10) {
62
+ let summaryText = "";
63
+ if (file.description && remaining > 10) {
64
+ const full = ` — ${file.description}`;
65
+ summaryText = full.length <= remaining ? full : `${full.slice(0, remaining - 3)}…`;
66
+ }
67
+ else if (!file.description && isDeepView && file.summary && remaining > 10) {
40
68
  const full = ` — ${file.summary}`;
41
- summary = full.length <= remaining ? full : `${full.slice(0, remaining - 3)}…`;
69
+ summaryText = full.length <= remaining ? full : `${full.slice(0, remaining - 3)}…`;
42
70
  }
43
- return (_jsx(Box, { children: _jsxs(Text, { bold: isCursor, backgroundColor: isCursor ? "blue" : undefined, wrap: "truncate", children: [prefix, _jsx(Text, { color: tagColor, children: tagStr }), summary ? _jsx(Text, { color: "gray", children: summary }) : null] }) }, `file-${file.relativePath}-${index}`));
71
+ return (_jsx(Box, { children: _jsxs(Text, { bold: isCursor, backgroundColor: isCursor ? "blue" : undefined, wrap: "truncate", children: [prefix, _jsx(Text, { color: tagColor, children: tagStr }), statusBadge ? _jsx(Text, { color: statusBadge.color, children: statusBadge.text }) : null, summaryText ? _jsx(Text, { color: "gray", children: summaryText }) : null] }) }, `file-${file.relativePath}-${index}`));
44
72
  }
45
73
  /**
46
74
  * Renders the left-panel tree of .aide files with cursor highlighting and optional summaries.
@@ -76,7 +76,7 @@ export default async function buildAncestorChain(root, targetPath) {
76
76
  if (!spec)
77
77
  continue;
78
78
  const { frontmatter } = parseFrontmatter(spec.content);
79
- const description = frontmatter?.description;
79
+ const description = frontmatter?.description || (frontmatter?.intent ? frontmatter.intent.split(/[.\n]/)[0] : undefined);
80
80
  const status = frontmatter?.status;
81
81
  // Compute a display path relative to the project root
82
82
  const rel = relative(absRoot, spec.specPath).replace(/\\/g, "/");
@@ -39,6 +39,10 @@ export interface AideFile {
39
39
  type: AideFileType;
40
40
  /** First ~80 chars of the first paragraph, for tree summaries. */
41
41
  summary: string;
42
+ /** Frontmatter description field — one-line human-readable summary. Empty string when absent. */
43
+ description?: string;
44
+ /** Alignment status from frontmatter — present only when explicitly set. */
45
+ status?: "aligned" | "misaligned";
42
46
  }
43
47
  /** Result of scanning a directory tree for .aide files. */
44
48
  export interface ScanResult {
@@ -2,6 +2,8 @@ import type { ScanResult } from "../../types/index.js";
2
2
  /**
3
3
  * Recursively walk the filesystem from `root` and collect all .aide files.
4
4
  * Skips node_modules, .git, dist, build, .next, coverage, __pycache__.
5
- * Reads the first ~1000 bytes of each file to extract the first meaningful body line as summary.
5
+ * In deep mode: reads full content to extract summary, description, and status.
6
+ * In shallow mode: reads only the first ~500 bytes per file to extract frontmatter
7
+ * description and status — summary stays empty but descriptions appear unconditionally.
6
8
  */
7
9
  export default function scan(root: string, path?: string, shallow?: boolean): Promise<ScanResult>;
@@ -2,6 +2,7 @@ import { readdir, readFile } from "node:fs/promises";
2
2
  import { join, relative } from "node:path";
3
3
  import { classifyFile } from "../../util/classify/index.js";
4
4
  import { SKIP_DIRS } from "../../types/index.js";
5
+ import parseFrontmatter from "../../util/parseFrontmatter/index.js";
5
6
  /** Extract the first meaningful body line as the summary, truncated to ~80 chars. */
6
7
  function extractSummary(content) {
7
8
  const lines = content.split("\n");
@@ -32,6 +33,17 @@ function extractSummary(content) {
32
33
  function toPosix(p) {
33
34
  return p.split("\\").join("/");
34
35
  }
36
+ /**
37
+ * Derive a description from frontmatter, falling back to the first sentence of
38
+ * `intent` when `description` is absent — matching the logic in buildAncestorChain.
39
+ */
40
+ function deriveDescription(frontmatter) {
41
+ if (frontmatter?.description)
42
+ return frontmatter.description;
43
+ if (frontmatter?.intent)
44
+ return frontmatter.intent.split(/[.\n]/)[0] ?? "";
45
+ return "";
46
+ }
35
47
  /** Recursively walk a directory and collect all .aide files. */
36
48
  async function walk(dir, root, files, shallow) {
37
49
  let entries;
@@ -52,10 +64,31 @@ async function walk(dir, root, files, shallow) {
52
64
  if (!entry.name.endsWith(".aide"))
53
65
  continue;
54
66
  let summary = "";
67
+ let description = "";
68
+ let status;
55
69
  if (!shallow) {
56
70
  try {
57
71
  const buf = await readFile(fullPath, { encoding: "utf-8" });
58
72
  summary = extractSummary(buf.slice(0, 1000));
73
+ const { frontmatter } = parseFrontmatter(buf);
74
+ description = deriveDescription(frontmatter);
75
+ if (frontmatter?.status)
76
+ status = frontmatter.status;
77
+ }
78
+ catch {
79
+ // skip unreadable files
80
+ }
81
+ }
82
+ else {
83
+ // In shallow mode, read only the first ~500 bytes to capture frontmatter
84
+ // without loading the full body — keeps startup fast for large projects.
85
+ try {
86
+ const buf = await readFile(fullPath, { encoding: "utf-8" });
87
+ const head = buf.slice(0, 500);
88
+ const { frontmatter } = parseFrontmatter(head);
89
+ description = deriveDescription(frontmatter);
90
+ if (frontmatter?.status)
91
+ status = frontmatter.status;
59
92
  }
60
93
  catch {
61
94
  // skip unreadable files
@@ -66,13 +99,17 @@ async function walk(dir, root, files, shallow) {
66
99
  relativePath: toPosix(relative(root, fullPath)),
67
100
  type: classifyFile(entry.name),
68
101
  summary,
102
+ description,
103
+ status,
69
104
  });
70
105
  }
71
106
  }
72
107
  /**
73
108
  * Recursively walk the filesystem from `root` and collect all .aide files.
74
109
  * Skips node_modules, .git, dist, build, .next, coverage, __pycache__.
75
- * Reads the first ~1000 bytes of each file to extract the first meaningful body line as summary.
110
+ * In deep mode: reads full content to extract summary, description, and status.
111
+ * In shallow mode: reads only the first ~500 bytes per file to extract frontmatter
112
+ * description and status — summary stays empty but descriptions appear unconditionally.
76
113
  */
77
114
  export default async function scan(root, path, shallow) {
78
115
  const scanRoot = path ? join(root, path) : root;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidemd-mcp/server",
3
- "version": "0.2.4",
3
+ "version": "0.3.1",
4
4
  "description": "MCP server that teaches any agent the AIDE methodology through tool descriptions and progressive disclosure tooling",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,7 @@
32
32
  "README.md",
33
33
  ".aide",
34
34
  ".aide/bin",
35
+ ".claude/commands/aide.md",
35
36
  ".claude/commands/aide",
36
37
  ".claude/agents/aide",
37
38
  ".claude/skills"