@codemcp/ade 0.2.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.
Files changed (150) hide show
  1. package/.ade/skills/adr-nygard/SKILL.md +45 -0
  2. package/.ade/skills/conventional-commits/SKILL.md +36 -0
  3. package/.ade/skills/tanstack-architecture/SKILL.md +25 -0
  4. package/.ade/skills/tanstack-code/SKILL.md +25 -0
  5. package/.ade/skills/tanstack-design/SKILL.md +24 -0
  6. package/.ade/skills/tanstack-testing/SKILL.md +24 -0
  7. package/.agentskills/skills/adr-nygard/SKILL.md +45 -0
  8. package/.agentskills/skills/commit/SKILL.md +20 -0
  9. package/.agentskills/skills/tdd/SKILL.md +10 -0
  10. package/.beads/README.md +85 -0
  11. package/.beads/config.yaml +63 -0
  12. package/.beads/interactions.jsonl +0 -0
  13. package/.beads/issues.jsonl +46 -0
  14. package/.beads/last-touched +1 -0
  15. package/.beads/metadata.json +4 -0
  16. package/.claude/settings.json +16 -0
  17. package/.claude/skills/extending-catalog/SKILL.md +41 -0
  18. package/.cursor/mcp.json +16 -0
  19. package/.cursor/rules/ade.mdc +10 -0
  20. package/.github/agents/ade.agent.md +28 -0
  21. package/.github/copilot-instructions.md +11 -0
  22. package/.github/workflows/pr.yml +38 -0
  23. package/.github/workflows/release.yml +124 -0
  24. package/.husky/post-checkout +2 -0
  25. package/.husky/post-merge +2 -0
  26. package/.husky/pre-commit +2 -0
  27. package/.husky/pre-push +8 -0
  28. package/.kiro/agents/ade.json +20 -0
  29. package/.kiro/settings/mcp.json +14 -0
  30. package/.knowledge/.prettierignore +1 -0
  31. package/.knowledge/config.yaml +9 -0
  32. package/.lintstagedrc.js +4 -0
  33. package/.mcp.json +20 -0
  34. package/.opencode/agents/ade.md +118 -0
  35. package/.prettierignore +2 -0
  36. package/.prettierrc.yaml +3 -0
  37. package/.vibe/beads-state-ade-autonomy-facet-46zodk.json +29 -0
  38. package/.vibe/beads-state-ade-fix-no-arch-selected-hvfiio.json +34 -0
  39. package/.vibe/development-plan-autonomy-facet.md +214 -0
  40. package/.vibe/development-plan-fix-no-arch-selected.md +103 -0
  41. package/.vscode/mcp.json +24 -0
  42. package/LICENSE +21 -0
  43. package/README.md +293 -0
  44. package/config.lock.yaml +118 -0
  45. package/config.yaml +10 -0
  46. package/docs/CLI-PRD.md +251 -0
  47. package/docs/CLI-design.md +646 -0
  48. package/docs/adrs/0001-tui-framework-selection.md +77 -0
  49. package/eslint.config.mjs +38 -0
  50. package/opencode.json +17 -0
  51. package/package.json +79 -0
  52. package/packages/cli/.prettierignore +1 -0
  53. package/packages/cli/dist/commands/install.js +39 -0
  54. package/packages/cli/dist/commands/setup.js +177 -0
  55. package/packages/cli/dist/index.js +43 -0
  56. package/packages/cli/dist/knowledge-installer.js +38 -0
  57. package/packages/cli/dist/version.js +1 -0
  58. package/packages/cli/eslint.config.mjs +40 -0
  59. package/packages/cli/nodemon.json +7 -0
  60. package/packages/cli/package.json +40 -0
  61. package/packages/cli/src/commands/conventions.integration.spec.ts +267 -0
  62. package/packages/cli/src/commands/install.integration.spec.ts +123 -0
  63. package/packages/cli/src/commands/install.spec.ts +169 -0
  64. package/packages/cli/src/commands/install.ts +63 -0
  65. package/packages/cli/src/commands/knowledge.integration.spec.ts +129 -0
  66. package/packages/cli/src/commands/setup.integration.spec.ts +148 -0
  67. package/packages/cli/src/commands/setup.spec.ts +442 -0
  68. package/packages/cli/src/commands/setup.ts +252 -0
  69. package/packages/cli/src/index.ts +52 -0
  70. package/packages/cli/src/knowledge-installer.spec.ts +111 -0
  71. package/packages/cli/src/knowledge-installer.ts +54 -0
  72. package/packages/cli/src/version.ts +1 -0
  73. package/packages/cli/tsconfig.build.json +8 -0
  74. package/packages/cli/tsconfig.json +10 -0
  75. package/packages/cli/tsconfig.vitest.json +7 -0
  76. package/packages/cli/vitest.config.ts +5 -0
  77. package/packages/core/.prettierignore +1 -0
  78. package/packages/core/eslint.config.mjs +40 -0
  79. package/packages/core/nodemon.json +7 -0
  80. package/packages/core/package.json +34 -0
  81. package/packages/core/src/catalog/catalog.spec.ts +570 -0
  82. package/packages/core/src/catalog/facets/architecture.ts +438 -0
  83. package/packages/core/src/catalog/facets/autonomy.ts +106 -0
  84. package/packages/core/src/catalog/facets/backpressure.ts +143 -0
  85. package/packages/core/src/catalog/facets/practices.ts +173 -0
  86. package/packages/core/src/catalog/facets/process.ts +50 -0
  87. package/packages/core/src/catalog/index.ts +93 -0
  88. package/packages/core/src/config.spec.ts +165 -0
  89. package/packages/core/src/config.ts +39 -0
  90. package/packages/core/src/index.ts +55 -0
  91. package/packages/core/src/registry.spec.ts +145 -0
  92. package/packages/core/src/registry.ts +70 -0
  93. package/packages/core/src/resolver.spec.ts +626 -0
  94. package/packages/core/src/resolver.ts +214 -0
  95. package/packages/core/src/types.ts +179 -0
  96. package/packages/core/src/writers/git-hooks.ts +9 -0
  97. package/packages/core/src/writers/instruction.spec.ts +42 -0
  98. package/packages/core/src/writers/instruction.ts +8 -0
  99. package/packages/core/src/writers/knowledge.spec.ts +26 -0
  100. package/packages/core/src/writers/knowledge.ts +15 -0
  101. package/packages/core/src/writers/permission-policy.ts +8 -0
  102. package/packages/core/src/writers/setup-note.ts +9 -0
  103. package/packages/core/src/writers/skills.spec.ts +109 -0
  104. package/packages/core/src/writers/skills.ts +9 -0
  105. package/packages/core/src/writers/workflows.spec.ts +72 -0
  106. package/packages/core/src/writers/workflows.ts +26 -0
  107. package/packages/core/tsconfig.build.json +8 -0
  108. package/packages/core/tsconfig.json +7 -0
  109. package/packages/core/tsconfig.vitest.json +7 -0
  110. package/packages/core/vitest.config.ts +5 -0
  111. package/packages/harnesses/.prettierignore +1 -0
  112. package/packages/harnesses/eslint.config.mjs +40 -0
  113. package/packages/harnesses/package.json +35 -0
  114. package/packages/harnesses/src/index.spec.ts +45 -0
  115. package/packages/harnesses/src/index.ts +47 -0
  116. package/packages/harnesses/src/permission-policy.ts +173 -0
  117. package/packages/harnesses/src/skills-installer.ts +54 -0
  118. package/packages/harnesses/src/types.ts +12 -0
  119. package/packages/harnesses/src/util.ts +221 -0
  120. package/packages/harnesses/src/writers/claude-code.spec.ts +320 -0
  121. package/packages/harnesses/src/writers/claude-code.ts +107 -0
  122. package/packages/harnesses/src/writers/cline.spec.ts +212 -0
  123. package/packages/harnesses/src/writers/cline.ts +24 -0
  124. package/packages/harnesses/src/writers/copilot.spec.ts +258 -0
  125. package/packages/harnesses/src/writers/copilot.ts +105 -0
  126. package/packages/harnesses/src/writers/cursor.spec.ts +219 -0
  127. package/packages/harnesses/src/writers/cursor.ts +95 -0
  128. package/packages/harnesses/src/writers/kiro.spec.ts +228 -0
  129. package/packages/harnesses/src/writers/kiro.ts +89 -0
  130. package/packages/harnesses/src/writers/opencode.spec.ts +258 -0
  131. package/packages/harnesses/src/writers/opencode.ts +67 -0
  132. package/packages/harnesses/src/writers/roo-code.spec.ts +197 -0
  133. package/packages/harnesses/src/writers/roo-code.ts +71 -0
  134. package/packages/harnesses/src/writers/universal.spec.ts +134 -0
  135. package/packages/harnesses/src/writers/universal.ts +84 -0
  136. package/packages/harnesses/src/writers/windsurf.spec.ts +178 -0
  137. package/packages/harnesses/src/writers/windsurf.ts +89 -0
  138. package/packages/harnesses/tsconfig.build.json +8 -0
  139. package/packages/harnesses/tsconfig.json +7 -0
  140. package/packages/harnesses/tsconfig.vitest.json +7 -0
  141. package/packages/harnesses/vitest.config.ts +5 -0
  142. package/pnpm-workspace.yaml +2 -0
  143. package/scripts/rename-packages.sh +23 -0
  144. package/skills-lock.json +20 -0
  145. package/tsconfig.base.json +25 -0
  146. package/tsconfig.build.json +7 -0
  147. package/tsconfig.json +13 -0
  148. package/turbo.json +47 -0
  149. package/vitest.config.ts +22 -0
  150. package/vitest.setup.ts +0 -0
@@ -0,0 +1,646 @@
1
+ # ADE CLI — Design Document
2
+
3
+ > **Scope.** This document covers the **ADE CLI** — the setup and
4
+ > configuration tool. It does not cover the runtime MCP servers
5
+ > (`@codemcp/workflows-server`, `@codemcp/knowledge-server`) or the broader
6
+ > ADE information architecture. For the overall ADE vision, see the project
7
+ > README.
8
+
9
+ ## Package Structure
10
+
11
+ Two packages with clear responsibilities:
12
+
13
+ ### `@ade/core` (`packages/core`)
14
+
15
+ All types, logic, and built-in writers. No CLI framework, no TUI, no user
16
+ interaction. Independently importable for programmatic use (CI scripts,
17
+ other tools).
18
+
19
+ ```
20
+ core/src/
21
+ types.ts # all interfaces and type definitions
22
+ config.ts # read/write config.yaml and config.lock.yaml
23
+ resolver.ts # config + catalog → LogicalConfig
24
+ registry.ts # writer registry (provision + agent)
25
+ catalog/
26
+ index.ts # catalog assembly, exports all facets
27
+ facets/
28
+ process.ts # workflow delivery method
29
+ architecture.ts # stack-specific conventions (e.g. TanStack)
30
+ practices.ts # composable practices (commits, TDD, ADR)
31
+ writers/ # built-in provision writers
32
+ workflows.ts
33
+ skills.ts
34
+ knowledge.ts
35
+ instruction.ts
36
+ agents/ # built-in agent writers
37
+ claude-code.ts # AGENTS.md, .claude/settings.json, skill files
38
+ ```
39
+
40
+ ### `@ade/cli` (`packages/cli`)
41
+
42
+ Thin shell: CLI framework wiring and interactive TUI. All business logic
43
+ lives in core; CLI commands are thin handlers that parse args and delegate.
44
+
45
+ ```
46
+ cli/src/
47
+ index.ts # entry point, arg parser, command routing
48
+ skills-installer.ts # calls @codemcp/skills API to install skills
49
+ knowledge-installer.ts # calls @codemcp/knowledge API to install docsets
50
+ commands/
51
+ setup.ts # interactive TUI setup
52
+ install.ts # resolve + generate (idempotent)
53
+ ```
54
+
55
+ `@ade/cli` depends on `@ade/core`. Nothing depends on `@ade/cli`.
56
+
57
+ ## Architecture Overview
58
+
59
+ ```
60
+ ┌──────────────────────────────────────────────────────────────┐
61
+ │ @ade/cli │
62
+ │ ade setup · ade install │
63
+ │ TUI prompts · skills-installer · knowledge-installer │
64
+ └──────────────────────────┬───────────────────────────────────┘
65
+ │ delegates to
66
+ ┌──────────────────────────▼───────────────────────────────────┐
67
+ │ @ade/core │
68
+ │ │
69
+ │ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
70
+ │ │ Catalog │──▶│ Resolver │──▶│ Writer Registry │ │
71
+ │ │ (facets) │ │ │ │ │ │
72
+ │ └──────────┘ └────┬─────┘ │ provision: Map<id,W> │ │
73
+ │ │ │ agents: Map<id,W> │ │
74
+ │ ▼ └───────────┬────────────┘ │
75
+ │ ┌──────────────┐ │ │
76
+ │ │ LogicalConfig│◀────────────┘ │
77
+ │ └──────┬───────┘ merge fragments │
78
+ │ │ │
79
+ │ ▼ │
80
+ │ agent-specific files │
81
+ └──────────────────────────────────────────────────────────────┘
82
+ ```
83
+
84
+ ## Data Flow
85
+
86
+ ### 1. Setup: TUI → config.yaml + config.lock.yaml + agent files
87
+
88
+ ```
89
+ read existing config.yaml (if any) for default selections
90
+ → walk facets interactively:
91
+ → pre-select previous choice as default (if still valid)
92
+ → warn if previous choice references a stale option
93
+ → collect new user choices
94
+ → collect docsets from all selected options
95
+ → present docset confirmation (opt-out multiselect)
96
+ → resolve choices + catalog → LogicalConfig
97
+ → write config.yaml (user choices)
98
+ → write config.lock.yaml (resolved LogicalConfig snapshot)
99
+ → run agent writer (generate AGENTS.md, settings.json, etc.)
100
+ → install skills via @codemcp/skills API
101
+ → install knowledge via @codemcp/knowledge API
102
+ ```
103
+
104
+ Resolution expands each selected option's recipe provisions into
105
+ LogicalConfig fragments, deduplicates docsets by id, filters by
106
+ `excluded_docsets`, maps enabled docsets to `knowledge_sources`, adds the
107
+ `@codemcp/knowledge-server` MCP entry if knowledge sources are present,
108
+ merges the custom section, and deduplicates MCP servers by ref.
109
+
110
+ For **multi-select facets**, each selected option's recipe is resolved
111
+ independently and their LogicalConfig fragments are merged.
112
+
113
+ ### 2. Install: config.lock.yaml → agent files (idempotent)
114
+
115
+ ```
116
+ read config.lock.yaml
117
+ → select agent writer (default: claude-code)
118
+ → apply logical_config from lock file (no re-resolution)
119
+ → run agent writer
120
+ → install skills
121
+ → install knowledge
122
+ ```
123
+
124
+ `ade install` does **not** re-resolve from `config.yaml`. It treats the
125
+ lock file as the source of truth, like `npm ci` treats `package-lock.json`.
126
+ To change selections, re-run `ade setup`.
127
+
128
+ The target agent is a **generation-time parameter** (`--agent` flag),
129
+ not stored in `config.yaml`. There is no auto-detection. This keeps the
130
+ config agent-agnostic — the same choices can produce output for any
131
+ supported agent.
132
+
133
+ ### 3. Package API calls from CLI installers
134
+
135
+ Skills and knowledge installation delegates to sibling packages. ADE imports
136
+ them as TypeScript dependencies rather than shelling out, giving type safety
137
+ and avoiding CLI flag contracts.
138
+
139
+ ```
140
+ skills-installer:
141
+ → import { runAdd } from "@codemcp/skills/api"
142
+ → for each skill: runAdd([source], { yes: true, all: true })
143
+ → skills package writes SKILL.md files and skills-lock.json
144
+
145
+ knowledge-installer:
146
+ → import { createDocset, initDocset }
147
+ from "@codemcp/knowledge/packages/cli/dist/exports.js"
148
+ → for each knowledge_source:
149
+ createDocset({ id, name, preset: "git-repo", url: origin }, { cwd })
150
+ initDocset({ docsetId: id, cwd })
151
+ → knowledge package manages .knowledge/ directory and docset artifacts
152
+ ```
153
+
154
+ Where direct import is impractical (e.g. the dependency isn't TypeScript or
155
+ has incompatible runtimes), CLI subprocess invocation is the fallback.
156
+
157
+ ## Entity Model
158
+
159
+ ### Catalog Structure
160
+
161
+ The catalog is TypeScript code, not YAML. This gives us type safety, registry
162
+ patterns, and explicit references between options.
163
+
164
+ ```typescript
165
+ interface Catalog {
166
+ facets: Facet[];
167
+ }
168
+
169
+ interface Facet {
170
+ id: string; // e.g. "process"
171
+ label: string; // e.g. "Process Guidance"
172
+ description: string;
173
+ required: boolean; // false = skippable
174
+ multiSelect?: boolean; // true = user can pick multiple options
175
+ options: Option[];
176
+ }
177
+
178
+ interface Option {
179
+ id: string; // e.g. "codemcp"
180
+ label: string; // e.g. "CodeMCP Workflows"
181
+ description: string;
182
+ recipe: Provision[]; // multiple provisions per option is common
183
+ docsets?: DocsetDef[]; // recommended documentation for this option
184
+ }
185
+
186
+ // Documentation as a weak entity on Option. Docsets are derived from
187
+ // upstream selections — picking "TanStack" in architecture implies
188
+ // TanStack docs, picking "GitHub Actions CI/CD" in practices implies
189
+ // GH Actions docs. The TUI presents all implied docsets as pre-selected
190
+ // defaults and allows the user to deselect. This is opt-out, not opt-in.
191
+ //
192
+ // The resolver collects docsets from all selected options, deduplicates
193
+ // by id, filters by excluded_docsets from UserConfig, and maps enabled
194
+ // docsets directly to knowledge_sources in LogicalConfig.
195
+ interface DocsetDef {
196
+ id: string; // unique key for dedup, e.g. "tanstack-query-docs"
197
+ label: string; // display name, e.g. "TanStack Query Reference"
198
+ origin: string; // URL, path, or package ref
199
+ description: string; // shown in TUI
200
+ }
201
+
202
+ // A recipe typically contains multiple provisions for different writers.
203
+ // Example: the "codemcp" workflow option produces:
204
+ // 1. workflows provision → registers @codemcp/workflows-server as MCP server
205
+ // 2. instruction provision → adds workflow usage guidance to agent instructions
206
+ // This is how one logical concept materializes across different output channels.
207
+
208
+ interface Provision {
209
+ writer: string; // references a registered ProvisionWriterDef.id
210
+ config: Record<string, unknown>; // writer-specific, validated at boundary
211
+ }
212
+
213
+ // Passed to provision writers for future cross-facet context.
214
+ // Currently passed as { resolved: {} }.
215
+ interface ResolutionContext {
216
+ resolved: Record<string, unknown>;
217
+ }
218
+ ```
219
+
220
+ ### LogicalConfig (intermediate representation)
221
+
222
+ ```typescript
223
+ interface LogicalConfig {
224
+ mcp_servers: McpServerEntry[];
225
+ instructions: string[];
226
+ skills: SkillDefinition[];
227
+ knowledge_sources: KnowledgeSource[];
228
+ }
229
+
230
+ interface McpServerEntry {
231
+ ref: string; // unique key for dedup/update
232
+ command: string; // e.g. "npx"
233
+ args: string[]; // e.g. ["-y", "@codemcp/workflows-server"]
234
+ env: Record<string, string>;
235
+ }
236
+
237
+ interface KnowledgeSource {
238
+ name: string; // e.g. "tanstack"
239
+ origin: string; // URL, path, or package ref
240
+ description: string;
241
+ }
242
+ ```
243
+
244
+ ### Config Files
245
+
246
+ ```typescript
247
+ // config.yaml — mostly CLI-managed, agent-agnostic
248
+ interface UserConfig {
249
+ choices: Record<string, string | string[]>; // single-select: string, multi-select: string[]
250
+ excluded_docsets?: string[]; // docset IDs the user opted out of
251
+ custom?: {
252
+ // user-managed section
253
+ mcp_servers?: McpServerEntry[];
254
+ instructions?: string[];
255
+ };
256
+ }
257
+
258
+ // config.lock.yaml — generated, never hand-edited
259
+ interface LockFile {
260
+ version: 1;
261
+ generated_at: string; // ISO timestamp
262
+ choices: Record<string, string>; // snapshot of selections
263
+ logical_config: LogicalConfig;
264
+ }
265
+ ```
266
+
267
+ ## Extensibility and Type Safety
268
+
269
+ ### Design Tension
270
+
271
+ Provision and agent writers need two properties that pull in opposite
272
+ directions:
273
+
274
+ 1. **Type safety** — built-in writers should have typed configs, not
275
+ `Record<string, unknown>` everywhere.
276
+ 2. **Runtime extensibility** — future packages must be able to register
277
+ new writers without modifying core's source.
278
+
279
+ ### Solution: Interfaces for Contracts, Registries for Dispatch
280
+
281
+ Writers are defined as **interfaces** (open contracts, implementable by
282
+ anyone) and collected in **runtime registries** (`Map`-based, open for
283
+ insertion). Built-in writers get typed configs internally while conforming
284
+ to the open interface at the boundary.
285
+
286
+ ```typescript
287
+ // --- Writer contracts (open, any package can implement) ---
288
+
289
+ interface ProvisionWriterDef {
290
+ id: string;
291
+ write(
292
+ config: Record<string, unknown>,
293
+ context: ResolutionContext
294
+ ): Promise<Partial<LogicalConfig>>;
295
+ }
296
+
297
+ interface AgentWriterDef {
298
+ id: string;
299
+ install(config: LogicalConfig, projectRoot: string): Promise<void>;
300
+ }
301
+
302
+ // --- Writer registry (open at runtime) ---
303
+
304
+ interface WriterRegistry {
305
+ provisions: Map<string, ProvisionWriterDef>;
306
+ agents: Map<string, AgentWriterDef>;
307
+ }
308
+ ```
309
+
310
+ ### How Built-In Writers Get Type Safety
311
+
312
+ Each built-in writer defines a typed config interface and validates/narrows
313
+ at the boundary. The registry doesn't care — it passes
314
+ `Record<string, unknown>` through. The writer narrows internally:
315
+
316
+ ```typescript
317
+ // writers/workflows.ts
318
+ interface WorkflowsConfig {
319
+ package: string;
320
+ env?: Record<string, string>;
321
+ }
322
+
323
+ export const workflowsWriter: ProvisionWriterDef = {
324
+ id: "workflows",
325
+ async write(config, _context) {
326
+ const c = config as WorkflowsConfig; // validated at boundary
327
+ return {
328
+ mcp_servers: [
329
+ {
330
+ ref: c.package,
331
+ command: "npx",
332
+ args: ["-y", c.package],
333
+ env: c.env ?? {}
334
+ }
335
+ ]
336
+ };
337
+ }
338
+ };
339
+ ```
340
+
341
+ The catalog definitions reference writers by string ID, not by import.
342
+ This is what makes the system open — a provision `{ writer: "my-custom", config: {...} }`
343
+ works as long as `"my-custom"` is registered before resolution runs.
344
+
345
+ ### Registry Lifecycle
346
+
347
+ Core ships a `createDefaultRegistry()` that pre-registers all built-in
348
+ writers. The CLI calls this at startup. A future plugin would call
349
+ `registry.provisions.set("my-writer", myWriter)` before resolution.
350
+
351
+ ```typescript
352
+ function createDefaultRegistry(): WriterRegistry {
353
+ const registry = createRegistry();
354
+
355
+ registerProvisionWriter(registry, instructionWriter);
356
+ registerProvisionWriter(registry, workflowsWriter);
357
+ registerProvisionWriter(registry, skillsWriter);
358
+ registerProvisionWriter(registry, knowledgeWriter);
359
+
360
+ registerAgentWriter(registry, claudeCodeWriter);
361
+
362
+ return registry;
363
+ }
364
+ ```
365
+
366
+ ### Why Not Pure Functions + Discriminated Unions?
367
+
368
+ A discriminated union (`type Provision = { writer: "workflows", config: WorkflowsConfig } | ...`)
369
+ gives excellent compile-time safety but is a **closed set**. Adding a writer
370
+ from another package means modifying the union in core, which defeats
371
+ extensibility.
372
+
373
+ The interface-based registry trades compile-time exhaustiveness for runtime
374
+ openness. The `Provision.writer` field is `string`, not a union — the
375
+ registry validates at resolution time that the writer exists. Built-in
376
+ writers still get internal type safety via their own config interfaces.
377
+
378
+ ### Built-In Provision Config Types
379
+
380
+ For reference, the typed configs used internally by built-in writers:
381
+
382
+ ```typescript
383
+ interface WorkflowsConfig {
384
+ package: string;
385
+ ref?: string;
386
+ env?: Record<string, string>;
387
+ }
388
+
389
+ interface SkillsConfig {
390
+ skills: SkillDefinition[];
391
+ }
392
+
393
+ interface KnowledgeConfig {
394
+ name: string;
395
+ origin: string; // must be a valid .git URL
396
+ description: string;
397
+ }
398
+
399
+ interface InstructionConfig {
400
+ text: string;
401
+ }
402
+ ```
403
+
404
+ These are not exported as part of the public contract. They are
405
+ implementation details of the built-in writers.
406
+
407
+ ## Agent Writers
408
+
409
+ Each agent writer implements `AgentWriterDef`. The writer has full ownership
410
+ of how to translate LogicalConfig into agent-specific files. It reads
411
+ existing files when needed to perform incremental updates.
412
+
413
+ ### Claude Code Writer (v1)
414
+
415
+ Produces agent-specific config files for Claude Code:
416
+
417
+ - **`AGENTS.md`** — ADE-managed section with resolved instructions
418
+ - **`.claude/settings.json`** — MCP server entries (merged with existing)
419
+ - **`.ade/skills/<name>/SKILL.md`** — Inline skill files (staging area for
420
+ `@codemcp/skills` installation)
421
+
422
+ Future agent writers: OpenCode, Copilot, Kiro.
423
+
424
+ ### ADE-Managed Section Delimiters
425
+
426
+ Agent writers that produce markdown or text files (instructions, AGENTS.md,
427
+ etc.) use delimiters to mark ADE-managed sections. This allows the writer to
428
+ update its sections without clobbering user-authored content.
429
+
430
+ ```markdown
431
+ <!-- ade:begin -->
432
+
433
+ (ADE-managed content — do not edit manually)
434
+ ...
435
+
436
+ <!-- ade:end -->
437
+ ```
438
+
439
+ For JSON config files (e.g. settings.json), the writer manages a top-level
440
+ key or object scope and merges with existing content.
441
+
442
+ ## Provision Writers
443
+
444
+ Each provision writer implements `ProvisionWriterDef`. Writers receive a
445
+ `ResolutionContext` containing the resolved options from dependent facets,
446
+ allowing them to adapt output based on sibling selections.
447
+
448
+ ### `workflows` writer
449
+
450
+ ```typescript
451
+ // provision config
452
+ { package: "@codemcp/workflows-server", env: { WORKFLOW_DIR: "./workflows" } }
453
+ ```
454
+
455
+ Produces: one `McpServerEntry` with `command: "npx"`,
456
+ `args: ["-y", "@codemcp/workflows-server"]`, and the given env vars.
457
+
458
+ ### `skills` writer
459
+
460
+ ```typescript
461
+ {
462
+ skills: [
463
+ { name: "tanstack-architecture", description: "...", body: "..." },
464
+ {
465
+ name: "playwright-cli",
466
+ source: "microsoft/playwright-cli/skills/playwright-cli"
467
+ }
468
+ ];
469
+ }
470
+ ```
471
+
472
+ Passes skill definitions (inline or external) through to LogicalConfig.
473
+ Inline skills include a `body` field; external skills reference a `source`.
474
+ The actual installation (writing SKILL.md files and calling `@codemcp/skills`
475
+ API) is handled by the agent writer and CLI's `skills-installer`.
476
+
477
+ ### `knowledge` writer
478
+
479
+ ```typescript
480
+ { name: "tanstack-query-docs", origin: "https://github.com/TanStack/query.git", description: "Server state management" }
481
+ ```
482
+
483
+ Produces a `KnowledgeSource` entry in LogicalConfig. The actual installation
484
+ (calling `@codemcp/knowledge` API) is handled by the CLI's
485
+ `knowledge-installer`. Origins must be valid `.git` URLs for the `git-repo`
486
+ preset.
487
+
488
+ ### `mcp-server` writer
489
+
490
+ ```typescript
491
+ { ref: "my-server", command: "npx", args: ["-y", "@acme/mcp-server"], env: { API_KEY: "${API_KEY}" } }
492
+ ```
493
+
494
+ Pass-through: produces one `McpServerEntry` directly.
495
+
496
+ ### `instruction` writer
497
+
498
+ ```typescript
499
+ {
500
+ text: "Always use pnpm, never npm.";
501
+ }
502
+ ```
503
+
504
+ Produces: one `instructions` entry.
505
+
506
+ ## V1 Catalog (TypeScript)
507
+
508
+ Example of how the catalog is defined in code:
509
+
510
+ ```typescript
511
+ // catalog/facets/process.ts
512
+ export const processFacet: Facet = {
513
+ id: "process",
514
+ label: "Process Guidance",
515
+ description: "How the agent receives workflow and process instructions",
516
+ required: false,
517
+ options: [
518
+ {
519
+ id: "codemcp-workflows",
520
+ label: "CodeMCP Workflows",
521
+ description:
522
+ "Structured EPCC workflows via @codemcp/workflows-server MCP",
523
+ recipe: [
524
+ {
525
+ writer: "workflows",
526
+ config: { package: "@codemcp/workflows-server" }
527
+ },
528
+ {
529
+ writer: "instruction",
530
+ config: { text: "Use the workflows MCP server..." }
531
+ }
532
+ ]
533
+ },
534
+ {
535
+ id: "native-agents-md",
536
+ label: "Native AGENTS.md",
537
+ description: "Inline EPCC instructions in AGENTS.md, no MCP dependency",
538
+ recipe: [
539
+ {
540
+ writer: "instruction",
541
+ config: { text: "Follow the EPCC workflow..." }
542
+ }
543
+ ]
544
+ }
545
+ ]
546
+ };
547
+
548
+ // catalog/facets/architecture.ts — options carry skills + docsets
549
+ export const architectureFacet: Facet = {
550
+ id: "architecture",
551
+ label: "Architecture",
552
+ description:
553
+ "Stack and framework conventions that shape your project structure",
554
+ required: false,
555
+ options: [
556
+ {
557
+ id: "tanstack",
558
+ label: "TanStack",
559
+ description:
560
+ "Full-stack conventions for TanStack (Router, Query, Form, Table)",
561
+ recipe: [
562
+ {
563
+ writer: "skills",
564
+ config: {
565
+ skills: [
566
+ {
567
+ name: "tanstack-architecture",
568
+ description: "...",
569
+ body: "..."
570
+ },
571
+ {
572
+ name: "playwright-cli",
573
+ source: "microsoft/playwright-cli/skills/playwright-cli"
574
+ }
575
+ ]
576
+ }
577
+ },
578
+ {
579
+ writer: "instruction",
580
+ config: { text: "This project follows TanStack conventions..." }
581
+ }
582
+ ],
583
+ docsets: [
584
+ {
585
+ id: "tanstack-router-docs",
586
+ label: "TanStack Router",
587
+ origin: "https://github.com/TanStack/router.git",
588
+ description: "File-based routing, loaders, and search params"
589
+ },
590
+ {
591
+ id: "tanstack-query-docs",
592
+ label: "TanStack Query",
593
+ origin: "https://github.com/TanStack/query.git",
594
+ description: "Server state management, caching, and mutations"
595
+ }
596
+ // ... form, table
597
+ ]
598
+ }
599
+ ]
600
+ };
601
+ ```
602
+
603
+ ## Design Decisions
604
+
605
+ 1. **Two packages: `@ade/core` + `@ade/cli`.** Core owns all types, logic,
606
+ catalog, and writers. CLI is a thin shell for arg parsing and TUI. Core
607
+ is independently importable for programmatic use. No MCP server package —
608
+ runtime MCP servers are separate projects.
609
+
610
+ 2. **Interfaces for contracts, registries for dispatch.** Writer contracts
611
+ are open interfaces (`ProvisionWriterDef`, `AgentWriterDef`). Dispatch
612
+ uses `Map`-based registries, open at runtime. This enables future
613
+ extensibility from other packages without modifying core.
614
+
615
+ 3. **Built-in writers get internal type safety.** Each built-in writer
616
+ defines its own typed config interface and narrows from
617
+ `Record<string, unknown>` at the boundary. The registry contract stays
618
+ generic; the implementation is specific.
619
+
620
+ 4. **Catalog is TypeScript code.** No YAML catalog files. Facets, options,
621
+ and recipes are defined as typed objects in `core/src/catalog/`. This
622
+ gives type safety, IDE support, and natural versioning with the package.
623
+ Kept inside core for now; extractable to a separate package later along
624
+ the `Catalog` interface seam.
625
+
626
+ 5. **Direct package imports over CLI subprocesses.** The CLI's installers
627
+ import `@codemcp/skills` and `@codemcp/knowledge` as TypeScript
628
+ dependencies and call their programmatic APIs (`runAdd`, `createDocset`,
629
+ `initDocset`). CLI subprocess invocation is the fallback for
630
+ non-TypeScript or cross-runtime cases.
631
+
632
+ 6. **`custom` section isolates user edits.** Only the `custom` block in
633
+ `config.yaml` is user-managed. The rest is CLI-managed. This eliminates
634
+ merge conflicts: the CLI never touches `custom`, and users never touch
635
+ the rest. Agent writers merge both sections when generating output.
636
+
637
+ 7. **Docsets are a weak entity on Option, not a separate facet.** Documentation
638
+ sources are always implied by an upstream selection (architecture or
639
+ practices). Making documentation a standalone facet would create a hollow
640
+ indirection whose options just mirror upstream choices 1:1. Instead, each
641
+ `Option` declares its recommended `docsets[]`. The resolver collects and
642
+ deduplicates them; the TUI presents them as a confirmation step (opt-out,
643
+ not opt-in). Config stores `excluded_docsets` (what the user opted out of)
644
+ rather than selected docsets, keeping the common case (accept all
645
+ recommendations) zero-config. When knowledge sources are present, the
646
+ resolver automatically adds a `@codemcp/knowledge-server` MCP server entry.