omniagent 0.1.2 → 0.1.4

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.
@@ -0,0 +1,56 @@
1
+ # Contributing
2
+
3
+ This document is for contributors and maintainers working on the `omniagent` codebase.
4
+
5
+ If you are using `omniagent` as an npm package consumer, start with [`README.md`](README.md).
6
+
7
+ ## Local Setup
8
+
9
+ - Node.js 18+
10
+ - npm
11
+
12
+ Install dependencies:
13
+
14
+ ```bash
15
+ npm ci
16
+ ```
17
+
18
+ ## Local Validation
19
+
20
+ Run the same checks used by CI before opening a PR:
21
+
22
+ ```bash
23
+ npm run check
24
+ npm run typecheck
25
+ npm test
26
+ npm run build
27
+ ```
28
+
29
+ ## Docs Changes
30
+
31
+ When updating docs, keep root `README.md` consumer-focused.
32
+
33
+ - End-user usage and product behavior belong in `README.md` and `docs/*.md`.
34
+ - Development and contribution workflows belong in `CONTRIBUTING.md`.
35
+ - Update docs assertions in `tests/docs/readme.test.ts` when docs architecture changes.
36
+
37
+ ## CLI Shim E2E (Contributor Workflow)
38
+
39
+ CLI shim E2E is a contributor-only verification flow and is not required for normal package usage.
40
+
41
+ Detailed guide:
42
+
43
+ - [`docs/cli-shim-e2e.md`](docs/cli-shim-e2e.md)
44
+
45
+ Quick commands:
46
+
47
+ ```bash
48
+ # Build first
49
+ npm run build
50
+
51
+ # Record baseline outputs from real CLIs
52
+ OA_E2E_RECORD_BASELINE=1 npm test -- tests/e2e/cli-shim/cli-shim.e2e.test.ts
53
+
54
+ # Compare shim output to recorded baselines
55
+ OA_E2E=1 npm test -- tests/e2e/cli-shim/cli-shim.e2e.test.ts
56
+ ```
package/README.md CHANGED
@@ -1,339 +1,168 @@
1
1
  # omniagent
2
2
 
3
- One config, many agents.
3
+ One source of truth for agent config across Claude, Codex, Gemini, and Copilot (and [any other agent](docs/custom-targets.md))
4
4
 
5
- omniagent lets teams stay in sync while everyone uses their tool of choice. Define agent
6
- content once and sync it to Claude Code, OpenAI Codex, GitHub Copilot CLI, and Gemini CLI.
5
+ Define canonical agent files once in `agents/`, then run `sync` to compile target-specific outputs.
7
6
 
8
- ```text
9
- # Before (manual drift)
10
- .claude/agents/release-helper.md
11
- .codex/skills/release-helper/SKILL.md
12
- .gemini/skills/release-helper/SKILL.md
13
- .copilot/skills/release-helper/SKILL.md
14
-
15
- # After (single source of truth)
16
- agents/agents/release-helper.md
17
- npx omniagent@latest sync
18
- ```
7
+ - Teams can keep one shared agent configuration while each teammate uses their preferred CLI.
8
+ - Agent enthusiasts can try out the newest agents, and switch back, without manually porting all their config.
19
9
 
20
- ## Quick start
10
+ ![Sync hero image](./design/sync-hero-image/output/sv-cast-with-agents.png)
21
11
 
22
- Create a Claude subagent once, then sync everywhere:
12
+ ## Quickstart
13
+
14
+ Author once in `agents/`, sync everywhere.
15
+
16
+ Subagents example:
17
+
18
+ ```md
19
+ # ./agents/agents/release-helper.md
23
20
 
24
- ```bash
25
- mkdir -p agents/agents
26
- cat > agents/agents/release-helper.md <<'AGENT'
27
21
  ---
22
+
28
23
  name: release-helper
29
24
  description: "Help draft release plans and checklists."
25
+
30
26
  ---
31
- Draft a release plan with milestones and owners.
32
- AGENT
33
27
 
34
- npx omniagent@latest sync --only claude,codex,gemini,copilot
28
+ Draft a release plan with milestones and owners.
35
29
  ```
36
30
 
37
- Outputs:
31
+ Codex does not support subagents. Omniagent
32
+ converts the canonical file into Codex's skill format (and the equivalent format for other
33
+ supported CLIs).
34
+
35
+ After `sync`, outputs include:
38
36
 
39
37
  ```text
40
- .claude/agents/release-helper.md
41
- .codex/skills/release-helper/SKILL.md
42
- .gemini/skills/release-helper/SKILL.md
43
- .copilot/skills/release-helper/SKILL.md
38
+ .claude/
39
+ agents/
40
+ release-helper.md
41
+ .codex/
42
+ skills/
43
+ release-helper/
44
+ SKILL.md
44
45
  ```
45
46
 
46
- Only Claude supports native subagents. Other targets receive converted skills so they still work.
47
+ ## How It Works
47
48
 
48
- ## CLI shim (interactive + one-shot)
49
+ 1. Author canonical sources in `agents/` (and optional repo `AGENTS.md`).
50
+ 2. Run `omniagent sync`.
51
+ 3. Omniagent writes target-specific files, converting unsupported surfaces when needed.
49
52
 
50
- `omniagent` without a subcommand acts as a shim to agent CLIs. Select an agent explicitly with
51
- `--agent` or set a `defaultAgent` in `agents/omniagent.config.*`.
53
+ ## Common Commands
52
54
 
53
55
  ```bash
54
- # Interactive (default)
55
- omniagent --agent codex
56
-
57
- # One-shot prompt
58
- omniagent -p "Summarize the repo" --agent codex --output json
59
-
60
- # Piped stdin
61
- echo "Summarize the repo" | omniagent --agent codex
62
-
63
- # Passthrough to agent CLI
64
- omniagent --agent codex -- --some-agent-flag --model gpt-5
65
- ```
66
-
67
- Shared flags:
68
-
69
- - `--approval <prompt|auto-edit|yolo>` (aliases: `--auto-edit`, `--yolo`)
70
- - `--sandbox <workspace-write|off>` (defaults to `off` when `--yolo` is set and `--sandbox` is
71
- not explicit)
72
- - `--output <text|json|stream-json>` (aliases: `--json`, `--stream-json`)
73
- - `--model <name>`
74
- - `--web <on|off|true|false|1|0>` (bare `--web` enables)
75
-
76
- Notes:
77
-
78
- - `--` passthrough is only valid after `--agent`.
79
- - Unsupported shared flags emit a warning and are ignored.
80
- - Agent output is passed through unmodified for all output formats.
81
- - Some approval values are agent-specific (for example, Claude ignores `--approval auto-edit`
82
- and warns).
83
- - Output formats are only supported in one-shot mode for agents that expose them; interactive runs
84
- warn when explicitly set.
85
-
86
- ### Shared-flag capability matrix
87
-
88
- | Agent | Approval | Sandbox | Output | Model | Web |
89
- |---------|----------|---------|--------|-------|-----|
90
- | codex | ✓ | ✓ | ✓ | ✓ | ✓ |
91
- | claude | ✓ | ✗ | ✓ | ✓ | ✗ |
92
- | gemini | ✓ | ✓ | ✓ | ✓ | ✓ |
93
- | copilot | ✓ | ✗ | ✗ | ✓ | ✗ |
56
+ # Sync all supported agent CLIs installed on your system
57
+ npx omniagent@latest sync
94
58
 
95
- ## What you can sync
59
+ # Sync specific targets
60
+ npx omniagent@latest sync --only claude,codex
96
61
 
97
- ### Subagents (Claude format converted skills elsewhere)
62
+ # Skip a target for this run
63
+ npx omniagent@latest sync --skip codex
98
64
 
99
- ```text
100
- agents/agents/release-helper.md
101
- ---
102
- name: release-helper
103
- description: "Help draft release plans and checklists."
104
- ---
105
- Draft a release plan with milestones and owners.
106
- ```
65
+ # Use a non-default agents directory
66
+ npx omniagent@latest sync --agentsDir ./my-custom-agents
107
67
 
108
- ### Skills
68
+ # Show local-only overrides and exit
69
+ npx omniagent@latest sync --list-local
109
70
 
110
- ```text
111
- agents/skills/review-helper/SKILL.md
112
- You are a reviewer. Focus on risks, edge cases, and missing tests.
71
+ # Shim mode (no subcommand)
72
+ omniagent --agent codex
73
+ omniagent -p "Summarize this repo" --agent codex --output json
113
74
  ```
114
75
 
115
- ### Slash commands
76
+ ## Local Overrides (`.local`)
116
77
 
117
- ```text
118
- agents/commands/review.md
119
- ---
120
- description: "Review a diff with a strict checklist."
121
- ---
122
- Summarize issues by severity with file/line references.
123
- ```
124
-
125
- ### Instruction files
78
+ Use `.local` files for personal variants that should not become team defaults.
126
79
 
127
80
  ```text
128
- AGENTS.md
129
- Global team instructions for all agents.
81
+ agents/
82
+ AGENTS.local.md # opinionated personal override
83
+ commands/
84
+ deploy.md # committed to git
85
+ deploy.local.md # opinionated personal override
86
+ skills/
87
+ ppt/
88
+ SKILL.md # committed to git
89
+ SKILL.local.md # opinionated personal override
130
90
  ```
131
91
 
132
- ## How it works
133
-
134
- 1. Author canonical files in `agents/` (and/or repo `AGENTS.md`).
135
- 2. Run `omniagent sync`.
136
- 3. Omniagent writes the right files for each target tool.
137
-
138
- ## Supported targets
139
-
140
- - Claude Code (native subagents + skills + slash commands)
141
- - OpenAI Codex (skills + global slash-command prompts; subagents converted to skills)
142
- - GitHub Copilot CLI (skills; slash commands + subagents converted to skills)
143
- - Gemini CLI (skills require `experimental.skills`; slash commands project/global;
144
- subagents converted to skills)
145
-
146
- ## Repo layout (canonical sources)
92
+ `./agents/.local/` is also supported. This can be used for libraries for your personal tooling, that should not be shared with the team:
147
93
 
148
94
  ```text
149
95
  agents/
150
- agents/ # subagents (Claude format)
151
- skills/ # skills (one folder per skill)
152
- commands/ # slash commands
153
- .local/ # personal overrides (ignored in outputs)
154
- AGENTS.md # repo-wide instructions (optional)
96
+ .local/
97
+ commands/my-personal-command.md
98
+ skills/my-personal-skill/SKILL.md
155
99
  ```
156
100
 
157
- Default agents directory is `agents/`. Override it with `--agentsDir` (relative to the project
158
- root, or an absolute path).
159
-
160
- ## Use cases
161
-
162
- - **Keep a team-wide review assistant consistent** while each person uses their preferred tool.
163
- - **Ship one release-helper subagent** that works everywhere.
164
- - **Avoid tool wars** by supporting Claude, Codex, Gemini, and Copilot from one source of truth.
165
- - **Layer personal tweaks** without polluting the repo using `.local` overrides.
166
-
167
- ## Requirements
168
-
169
- - Node.js 18+
170
-
171
- ## Local validation
172
-
173
- Run the same steps as CI:
174
-
175
- 1. `npm ci`
176
- 2. `npm run check`
177
- 3. `npm run typecheck`
178
- 4. `npm test`
179
- 5. `npm run build`
101
+ If a `.local` item matches a shared item name, the local item wins for your sync run. Generated
102
+ outputs do not keep the `.local` suffix.
180
103
 
181
- ## Advanced
104
+ Use `--list-local` to see active local items, or `--exclude-local` to ignore them for a run.
182
105
 
183
- ### Targeting via frontmatter
106
+ Example `.gitignore` entries:
184
107
 
185
- ```yaml
186
- ---
187
- name: release-helper
188
- targets: [claude, gemini]
189
- ---
108
+ ```gitignore
109
+ agents/.local/
110
+ agents/**/*.local*
190
111
  ```
191
112
 
192
- - `targets` / `targetAgents`: `claude`, `gemini`, `codex`, `copilot`.
193
- - `name`: overrides filename when supported.
194
- - `description`: optional metadata.
195
-
196
- ### Custom targets (omniagent.config.*)
197
-
198
- Define custom targets in the agents directory. The CLI auto-discovers the first match in:
199
- `omniagent.config.ts`, `.mts`, `.cts`, `.js`, `.mjs`, `.cjs`.
200
-
201
- ```ts
202
- const config = {
203
- targets: [
204
- {
205
- id: "acme",
206
- displayName: "Acme Agent",
207
- outputs: {
208
- skills: "{repoRoot}/.acme/skills/{itemName}",
209
- subagents: "{repoRoot}/.acme/agents/{itemName}.md",
210
- commands: {
211
- projectPath: "{repoRoot}/.acme/commands/{itemName}.md",
212
- userPath: "{homeDir}/.acme/commands/{itemName}.md",
213
- },
214
- instructions: "AGENTS.md",
215
- },
216
- },
217
- ],
218
- disableTargets: ["copilot"],
219
- };
220
-
221
- export default config;
222
- ```
113
+ ## Basic Templating
223
114
 
224
- - Built-in IDs require `override: true` or `inherits: "claude"` to avoid collisions.
225
- - `disableTargets` removes built-ins from the active target set.
226
- - Placeholders: `{repoRoot}`, `{homeDir}`, `{agentsDir}`, `{targetId}`, `{itemName}`,
227
- `{commandLocation}`.
228
- - When multiple targets resolve to the same output file, default writers handle
229
- skills/subagents/instructions. Command collisions are errors.
115
+ Use `<agents ...>` blocks when some text should render only for specific targets.
230
116
 
231
- ### Instruction templates (per-target outputs)
117
+ ```md
118
+ Shared guidance for all targets.
232
119
 
233
- ```text
234
- /agents/guide.AGENTS.md
235
- ---
236
- outPutPath: docs/
237
- ---
238
- <agents include="claude,gemini">
239
- # Team Instructions
120
+ <agents claude,codex>
121
+ Extra instructions only for Claude and Codex.
240
122
  </agents>
241
123
  ```
242
124
 
243
- - Templates live under `/agents/**` and can target specific outputs.
244
- - `outPutPath` is treated as a directory; filename is ignored if supplied.
245
-
246
- ### Local overrides (personal, never synced)
247
-
248
- ```text
249
- agents/commands/deploy.local.md
250
- agents/skills/review-helper.local/SKILL.md
251
- ```
252
-
253
- Local items override shared items with the same name. Outputs never include `.local`.
254
-
255
- ### Agent-scoped templating
256
-
257
- ```text
258
- Shared content.
259
-
260
- <agents claude,codex>
261
- Only Claude and Codex see this.
262
- </agents>
125
+ For advanced templating and dynamic scripts (`<nodejs>`, `<shell>`), see
126
+ [`docs/templating.md`](docs/templating.md).
263
127
 
264
- <agents not:claude,gemini>
265
- Everyone except Claude and Gemini see this.
266
- </agents>
267
- ```
128
+ ## Agent CLI Shim
268
129
 
269
- ### Dynamic template scripts (`<nodejs>` and `<shell>`)
130
+ Omniagent provides a CLI shim (`omniagent` without a subcommand) for working with agent CLIs via a unified interface.
270
131
 
271
- `sync` can execute inline script blocks in canonical templates before agent templating/rendering.
132
+ This can be useful for CI/CD and shell scripts, while maintaining full portability between agents:
272
133
 
273
- Node.js blocks evaluate JavaScript and inject the returned value:
134
+ ```bash
135
+ # code-review.sh
136
+ #!/usr/bin/env bash
137
+ set -euo pipefail
138
+ agent="${1:-claude}"
274
139
 
275
- ```md
276
- Current docs:
277
- <nodejs>
278
- const fs = require("node:fs");
279
- const path = require("node:path");
280
-
281
- const docsDir = path.join(process.cwd(), "docs");
282
- const pages = fs
283
- .readdirSync(docsDir)
284
- .filter((name) => name.endsWith(".md"))
285
- .sort();
286
-
287
- return pages.map((name) => `- ${name}`).join("\n");
288
- </nodejs>
140
+ omniagent -p "Perform comprehensive code review for this branch against main" --agent "$agent"
289
141
  ```
290
142
 
291
- Shell blocks execute in the user's shell and inject stdout:
143
+ Example usage:
292
144
 
293
- ```md
294
- Current docs:
295
- <shell>
296
- for file in docs/*.md; do
297
- [ -f "$file" ] || continue
298
- printf -- "- %s\n" "$(basename "$file")"
299
- done | sort
300
- </shell>
145
+ ```bash
146
+ ./code-review.sh
147
+ ./code-review.sh codex
301
148
  ```
302
149
 
303
- Behavior:
150
+ ## Documentation
304
151
 
305
- - Scripts run once per template per sync run and cached results are reused across targets.
306
- - Each script block runs in an isolated process (Node subprocess for `<nodejs>`, shell process for `<shell>`).
307
- - `<nodejs>` blocks can use `require`, `__dirname`, and `__filename`.
308
- - `<shell>` blocks run with the user's shell (`$SHELL` on Unix, `cmd.exe` on Windows fallback).
309
- - `<nodejs>` return values are normalized as: string unchanged, object/array JSON text, other values via
310
- `String(value)`, `null`/`undefined` as empty output.
311
- - `<shell>` blocks render raw stdout.
312
- - Static template text around script blocks is preserved.
313
- - Script failures stop sync before managed writes are applied.
314
- - Long-running scripts emit periodic `still running` warnings every 30 seconds.
315
- - Routine per-script telemetry is quiet by default and shown only with `sync --verbose`.
152
+ - Docs index: [`docs/README.md`](docs/README.md)
153
+ - Getting started: [`docs/getting-started.md`](docs/getting-started.md)
154
+ - Sync basics: [`docs/sync-basics.md`](docs/sync-basics.md)
155
+ - CLI shim details: [`docs/cli-shim.md`](docs/cli-shim.md)
156
+ - Custom targets (custom agents): [`docs/custom-targets.md`](docs/custom-targets.md)
157
+ - Local overrides: [`docs/local-overrides.md`](docs/local-overrides.md)
158
+ - Templating and dynamic scripts: [`docs/templating.md`](docs/templating.md)
159
+ - Command reference: [`docs/reference.md`](docs/reference.md)
160
+ - Troubleshooting: [`docs/troubleshooting.md`](docs/troubleshooting.md)
316
161
 
317
- ## CLI reference
162
+ ## Requirements
318
163
 
319
- ```bash
320
- npx omniagent@latest sync
321
- npx omniagent@latest sync --only claude
322
- npx omniagent@latest sync --skip codex
323
- npx omniagent@latest sync --exclude-local
324
- npx omniagent@latest sync --exclude-local=skills,commands
325
- npx omniagent@latest sync --agentsDir ./my-custom-agents
326
- npx omniagent@latest sync --list-local
327
- npx omniagent@latest sync --yes
328
- npx omniagent@latest sync --verbose
329
- npx omniagent@latest sync --json
330
- ```
164
+ - Node.js 18+
331
165
 
332
- Run-level overrides:
166
+ ## Contributing
333
167
 
334
- - `--only` replaces per-file frontmatter defaults for this run.
335
- - `--skip` filters the active target set (frontmatter defaults or all targets).
336
- - `--exclude-local` omits local sources entirely (or only for the listed categories).
337
- - `--list-local` prints detected local items and exits.
338
- - `--agentsDir` points to the agents directory (default `agents/`, resolved from the repo root).
339
- - If both are provided, `--only` applies first, then `--skip`.
168
+ Development and test workflows are documented in [`CONTRIBUTING.md`](CONTRIBUTING.md).
package/dist/cli.js CHANGED
@@ -826,7 +826,7 @@ const codexTarget = {
826
826
  fallback: { mode: "convert", targetType: "skills" }
827
827
  },
828
828
  commands: {
829
- userPath: "{homeDir}/.codex/prompts/{itemName}.md"
829
+ fallback: { mode: "convert", targetType: "skills" }
830
830
  },
831
831
  instructions: {
832
832
  filename: "AGENTS.md",
@@ -4653,12 +4653,18 @@ async function syncSlashCommands(request) {
4653
4653
  const managedManifest = await readManagedOutputs(request.repoRoot, homeDir) ?? { entries: [] };
4654
4654
  const nextManaged = /* @__PURE__ */ new Map();
4655
4655
  const activeOutputPaths = /* @__PURE__ */ new Set();
4656
+ const activeSourcesWithOutputs = /* @__PURE__ */ new Map();
4656
4657
  const countsByTarget = /* @__PURE__ */ new Map();
4657
4658
  const getCounts = (targetId) => {
4658
4659
  const existing = countsByTarget.get(targetId) ?? emptyResultCounts();
4659
4660
  countsByTarget.set(targetId, existing);
4660
4661
  return existing;
4661
4662
  };
4663
+ const recordSourceOutput = (targetId, sourceId) => {
4664
+ const sources = activeSourcesWithOutputs.get(targetId) ?? /* @__PURE__ */ new Set();
4665
+ sources.add(sourceId);
4666
+ activeSourcesWithOutputs.set(targetId, sources);
4667
+ };
4662
4668
  const converterRegistry = /* @__PURE__ */ new Map();
4663
4669
  const writerRegistry = /* @__PURE__ */ new Map();
4664
4670
  const validAgents = request.validAgents ?? buildSupportedAgentNames(request.targets);
@@ -4812,6 +4818,7 @@ async function syncSlashCommands(request) {
4812
4818
  const managedKey = buildManagedOutputKey(entry2);
4813
4819
  nextManaged.set(managedKey, entry2);
4814
4820
  activeOutputPaths.add(normalizeManagedOutputPath(entry2.outputPath));
4821
+ recordSourceOutput(entry2.targetId, entry2.sourceId);
4815
4822
  };
4816
4823
  const counts = getCounts(target.id);
4817
4824
  let converterActive = false;
@@ -4997,16 +5004,18 @@ async function syncSlashCommands(request) {
4997
5004
  if (nextManaged.has(key)) {
4998
5005
  continue;
4999
5006
  }
5007
+ const outputKey = normalizeManagedOutputPath(entry2.outputPath);
5008
+ if (activeOutputPaths.has(outputKey)) {
5009
+ continue;
5010
+ }
5000
5011
  const activeSources = activeSourcesByTarget.get(entry2.targetId);
5001
5012
  const sourceStillActive = activeSources?.has(entry2.sourceId) ?? false;
5002
- if (!removeMissing || sourceStillActive) {
5013
+ const currentSources = activeSourcesWithOutputs.get(entry2.targetId);
5014
+ const sourceHasCurrentOutput = currentSources?.has(entry2.sourceId) ?? false;
5015
+ if (!removeMissing || sourceStillActive && !sourceHasCurrentOutput) {
5003
5016
  updatedEntries.push(entry2);
5004
5017
  continue;
5005
5018
  }
5006
- const outputKey = normalizeManagedOutputPath(entry2.outputPath);
5007
- if (activeOutputPaths.has(outputKey)) {
5008
- continue;
5009
- }
5010
5019
  const existingHash = await hashOutputPath(entry2.outputPath);
5011
5020
  if (!existingHash) {
5012
5021
  continue;
@@ -6425,7 +6434,8 @@ function validateCommandOutputDefinition(output, label, errors) {
6425
6434
  errors.push(`${label} must be a string or an object.`);
6426
6435
  return;
6427
6436
  }
6428
- if (!output.projectPath && !output.userPath) {
6437
+ const fallbackConvertsToSkills = output.fallback?.mode === "convert" && output.fallback.targetType === "skills";
6438
+ if (!output.projectPath && !output.userPath && !fallbackConvertsToSkills) {
6429
6439
  errors.push(`${label} must include projectPath or userPath.`);
6430
6440
  }
6431
6441
  if (output.projectPath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omniagent",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Unified agent configuration CLI that compiles canonical agent configs to multiple runtimes.",
5
5
  "type": "module",
6
6
  "bin": {
package/tasks.md ADDED
@@ -0,0 +1,25 @@
1
+ # README Docs Refactor Tasks
2
+
3
+ - [x] Create concise onboarding-first `README.md` for the 90% sync workflow.
4
+ - [x] Add advanced docs pages and move complex README content into `/docs`.
5
+ - [x] Move custom targets/custom agent declaration guidance to `docs/custom-targets.md`.
6
+ - [x] Move templating and dynamic script guidance to `docs/templating.md`.
7
+ - [x] Add a docs index and link advanced docs from `README.md`.
8
+ - [x] Update docs tests to match the new README/docs structure.
9
+ - [x] Run validation (`npm run check` and `npm test`).
10
+
11
+ # Contributor/Consumer Split Follow-up
12
+
13
+ - [x] Remove development-only validation details from root `README.md`.
14
+ - [x] Add `CONTRIBUTING.md` with local development and validation guidance.
15
+ - [x] Move CLI shim E2E guidance under contributing docs flow.
16
+ - [x] Remove contributor-only links from end-user docs indexes.
17
+ - [x] Update docs tests for the new contributing boundary.
18
+ - [x] Run validation (`npm run check` and `npm test`).
19
+
20
+ # README Basics Follow-up
21
+
22
+ - [x] Add simple `.local` override explanation to root `README.md`.
23
+ - [x] Add simple basic templating explanation to root `README.md`.
24
+ - [x] Update docs tests to assert these root README basics.
25
+ - [x] Run validation (`npm run check` and `npm test`).