@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.
- package/.ade/skills/adr-nygard/SKILL.md +45 -0
- package/.ade/skills/conventional-commits/SKILL.md +36 -0
- package/.ade/skills/tanstack-architecture/SKILL.md +25 -0
- package/.ade/skills/tanstack-code/SKILL.md +25 -0
- package/.ade/skills/tanstack-design/SKILL.md +24 -0
- package/.ade/skills/tanstack-testing/SKILL.md +24 -0
- package/.agentskills/skills/adr-nygard/SKILL.md +45 -0
- package/.agentskills/skills/commit/SKILL.md +20 -0
- package/.agentskills/skills/tdd/SKILL.md +10 -0
- package/.beads/README.md +85 -0
- package/.beads/config.yaml +63 -0
- package/.beads/interactions.jsonl +0 -0
- package/.beads/issues.jsonl +46 -0
- package/.beads/last-touched +1 -0
- package/.beads/metadata.json +4 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/extending-catalog/SKILL.md +41 -0
- package/.cursor/mcp.json +16 -0
- package/.cursor/rules/ade.mdc +10 -0
- package/.github/agents/ade.agent.md +28 -0
- package/.github/copilot-instructions.md +11 -0
- package/.github/workflows/pr.yml +38 -0
- package/.github/workflows/release.yml +124 -0
- package/.husky/post-checkout +2 -0
- package/.husky/post-merge +2 -0
- package/.husky/pre-commit +2 -0
- package/.husky/pre-push +8 -0
- package/.kiro/agents/ade.json +20 -0
- package/.kiro/settings/mcp.json +14 -0
- package/.knowledge/.prettierignore +1 -0
- package/.knowledge/config.yaml +9 -0
- package/.lintstagedrc.js +4 -0
- package/.mcp.json +20 -0
- package/.opencode/agents/ade.md +118 -0
- package/.prettierignore +2 -0
- package/.prettierrc.yaml +3 -0
- package/.vibe/beads-state-ade-autonomy-facet-46zodk.json +29 -0
- package/.vibe/beads-state-ade-fix-no-arch-selected-hvfiio.json +34 -0
- package/.vibe/development-plan-autonomy-facet.md +214 -0
- package/.vibe/development-plan-fix-no-arch-selected.md +103 -0
- package/.vscode/mcp.json +24 -0
- package/LICENSE +21 -0
- package/README.md +293 -0
- package/config.lock.yaml +118 -0
- package/config.yaml +10 -0
- package/docs/CLI-PRD.md +251 -0
- package/docs/CLI-design.md +646 -0
- package/docs/adrs/0001-tui-framework-selection.md +77 -0
- package/eslint.config.mjs +38 -0
- package/opencode.json +17 -0
- package/package.json +79 -0
- package/packages/cli/.prettierignore +1 -0
- package/packages/cli/dist/commands/install.js +39 -0
- package/packages/cli/dist/commands/setup.js +177 -0
- package/packages/cli/dist/index.js +43 -0
- package/packages/cli/dist/knowledge-installer.js +38 -0
- package/packages/cli/dist/version.js +1 -0
- package/packages/cli/eslint.config.mjs +40 -0
- package/packages/cli/nodemon.json +7 -0
- package/packages/cli/package.json +40 -0
- package/packages/cli/src/commands/conventions.integration.spec.ts +267 -0
- package/packages/cli/src/commands/install.integration.spec.ts +123 -0
- package/packages/cli/src/commands/install.spec.ts +169 -0
- package/packages/cli/src/commands/install.ts +63 -0
- package/packages/cli/src/commands/knowledge.integration.spec.ts +129 -0
- package/packages/cli/src/commands/setup.integration.spec.ts +148 -0
- package/packages/cli/src/commands/setup.spec.ts +442 -0
- package/packages/cli/src/commands/setup.ts +252 -0
- package/packages/cli/src/index.ts +52 -0
- package/packages/cli/src/knowledge-installer.spec.ts +111 -0
- package/packages/cli/src/knowledge-installer.ts +54 -0
- package/packages/cli/src/version.ts +1 -0
- package/packages/cli/tsconfig.build.json +8 -0
- package/packages/cli/tsconfig.json +10 -0
- package/packages/cli/tsconfig.vitest.json +7 -0
- package/packages/cli/vitest.config.ts +5 -0
- package/packages/core/.prettierignore +1 -0
- package/packages/core/eslint.config.mjs +40 -0
- package/packages/core/nodemon.json +7 -0
- package/packages/core/package.json +34 -0
- package/packages/core/src/catalog/catalog.spec.ts +570 -0
- package/packages/core/src/catalog/facets/architecture.ts +438 -0
- package/packages/core/src/catalog/facets/autonomy.ts +106 -0
- package/packages/core/src/catalog/facets/backpressure.ts +143 -0
- package/packages/core/src/catalog/facets/practices.ts +173 -0
- package/packages/core/src/catalog/facets/process.ts +50 -0
- package/packages/core/src/catalog/index.ts +93 -0
- package/packages/core/src/config.spec.ts +165 -0
- package/packages/core/src/config.ts +39 -0
- package/packages/core/src/index.ts +55 -0
- package/packages/core/src/registry.spec.ts +145 -0
- package/packages/core/src/registry.ts +70 -0
- package/packages/core/src/resolver.spec.ts +626 -0
- package/packages/core/src/resolver.ts +214 -0
- package/packages/core/src/types.ts +179 -0
- package/packages/core/src/writers/git-hooks.ts +9 -0
- package/packages/core/src/writers/instruction.spec.ts +42 -0
- package/packages/core/src/writers/instruction.ts +8 -0
- package/packages/core/src/writers/knowledge.spec.ts +26 -0
- package/packages/core/src/writers/knowledge.ts +15 -0
- package/packages/core/src/writers/permission-policy.ts +8 -0
- package/packages/core/src/writers/setup-note.ts +9 -0
- package/packages/core/src/writers/skills.spec.ts +109 -0
- package/packages/core/src/writers/skills.ts +9 -0
- package/packages/core/src/writers/workflows.spec.ts +72 -0
- package/packages/core/src/writers/workflows.ts +26 -0
- package/packages/core/tsconfig.build.json +8 -0
- package/packages/core/tsconfig.json +7 -0
- package/packages/core/tsconfig.vitest.json +7 -0
- package/packages/core/vitest.config.ts +5 -0
- package/packages/harnesses/.prettierignore +1 -0
- package/packages/harnesses/eslint.config.mjs +40 -0
- package/packages/harnesses/package.json +35 -0
- package/packages/harnesses/src/index.spec.ts +45 -0
- package/packages/harnesses/src/index.ts +47 -0
- package/packages/harnesses/src/permission-policy.ts +173 -0
- package/packages/harnesses/src/skills-installer.ts +54 -0
- package/packages/harnesses/src/types.ts +12 -0
- package/packages/harnesses/src/util.ts +221 -0
- package/packages/harnesses/src/writers/claude-code.spec.ts +320 -0
- package/packages/harnesses/src/writers/claude-code.ts +107 -0
- package/packages/harnesses/src/writers/cline.spec.ts +212 -0
- package/packages/harnesses/src/writers/cline.ts +24 -0
- package/packages/harnesses/src/writers/copilot.spec.ts +258 -0
- package/packages/harnesses/src/writers/copilot.ts +105 -0
- package/packages/harnesses/src/writers/cursor.spec.ts +219 -0
- package/packages/harnesses/src/writers/cursor.ts +95 -0
- package/packages/harnesses/src/writers/kiro.spec.ts +228 -0
- package/packages/harnesses/src/writers/kiro.ts +89 -0
- package/packages/harnesses/src/writers/opencode.spec.ts +258 -0
- package/packages/harnesses/src/writers/opencode.ts +67 -0
- package/packages/harnesses/src/writers/roo-code.spec.ts +197 -0
- package/packages/harnesses/src/writers/roo-code.ts +71 -0
- package/packages/harnesses/src/writers/universal.spec.ts +134 -0
- package/packages/harnesses/src/writers/universal.ts +84 -0
- package/packages/harnesses/src/writers/windsurf.spec.ts +178 -0
- package/packages/harnesses/src/writers/windsurf.ts +89 -0
- package/packages/harnesses/tsconfig.build.json +8 -0
- package/packages/harnesses/tsconfig.json +7 -0
- package/packages/harnesses/tsconfig.vitest.json +7 -0
- package/packages/harnesses/vitest.config.ts +5 -0
- package/pnpm-workspace.yaml +2 -0
- package/scripts/rename-packages.sh +23 -0
- package/skills-lock.json +20 -0
- package/tsconfig.base.json +25 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +13 -0
- package/turbo.json +47 -0
- package/vitest.config.ts +22 -0
- 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.
|