@kuznai/inception-engine 0.21.0 → 0.23.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/README.md CHANGED
@@ -50,9 +50,11 @@ Before executing, the deploy command runs preflight analysis on instruction file
50
50
  | Skills (SKILL.md) | All agents via manifest and CLI | All agents |
51
51
  | File write | All agents via manifest and CLI | All agents |
52
52
  | Config patch (JSON merge) | All agents via manifest and CLI | All agents |
53
- | MCP Servers | claude-code (`scope: "global"` → `~/.claude.json`; `scope: "repo"` → `{repo}/.claude/mcp.json`; `scope: "workspace"` → `{workspace}/.claude/mcp.json`), gemini-cli, codex, antigravity, opencode; github-copilot with `scope: "repo"` deploys to `{repo}/.vscode/mcp.json` and `scope: "workspace"` deploys to `{workspace}/.vscode/mcp.json`; github-copilot with `scope: "global"` (default) is unsupported and warns | claude-code, gemini-cli, codex, antigravity, opencode, github-copilot |
54
- | Global/Repo/Workspace Rules Files | `scope: "global"` and `scope: "repo"` are supported on the implemented agent surfaces; `scope: "workspace"` is supported for `claude-code`, `codex`, and `gemini-cli`; `github-copilot` reads Claude-native rules via `claude-code` and has no separate rules deployment target | All supported agents |
53
+ | MCP Servers | claude-code (`scope: "global"` → `~/.claude.json`; `scope: "repo"` → `{repo}/.claude/mcp.json`; `scope: "workspace"` → `{workspace}/.claude/mcp.json`), gemini-cli, codex, antigravity (`scope: "global"` → `~/.gemini/antigravity/mcp_config.json`; `scope: "repo"` → `{repo}/.agents/rules/{name}.md`), opencode; github-copilot with `scope: "repo"` deploys to `{repo}/.vscode/mcp.json` and `scope: "workspace"` deploys to `{workspace}/.vscode/mcp.json`; github-copilot with `scope: "global"` (default) is unsupported and warns | claude-code, gemini-cli, codex, antigravity, opencode, github-copilot |
54
+ | Global/Repo/Workspace Rules Files | `scope: "global"` and `scope: "repo"` are supported on the implemented agent surfaces; `scope: "workspace"` is supported for `claude-code`, `codex`, and `gemini-cli`; `github-copilot` reads Claude-native rules via `claude-code` (shared-via) and also supports native `scope: "copilot-repo"` (`{repo}/.github/copilot-instructions.md`) and `scope: "copilot-scoped"` (`{repo}/.github/instructions/{name}.instructions.md`) | All supported agents |
55
55
  | Permissions / Approval Config | claude-code (`~/.claude/settings.json`), codex (`~/.codex/config.toml`), opencode (`~/.config/opencode/opencode.json` on POSIX, `%APPDATA%\\opencode\\opencode.json` on Windows); other agents are warned and skipped | claude-code, codex, opencode |
56
+ | Execution Hooks | claude-code (`~/.claude/settings.json`), github-copilot (`planned`); other agents are warned and skipped | claude-code |
57
+ | Execution / Safety Config | gemini-cli (`~/.gemini/settings.json`); other agents are warned and skipped | gemini-cli |
56
58
  | Agent Definitions | claude-code (`{repo}/.claude/agents/{name}.md`), gemini-cli (`{repo}/.gemini/agents/{name}.md` or `.toml`, plus `scope: "global"` to `~/.gemini/agents/{name}.md` or `.toml`), antigravity (`{repo}/.agents/rules/{name}.md`), opencode (`{repo}/.opencode/agents/{name}.md`, plus `scope: "global"` to the user config dir), github-copilot (`{repo}/.github/copilot/agents/{name}.md`, with migration from legacy `.github/agents/{name}.agent.md`); codex is warned and skipped | All supported agents |
57
59
  | `init` manifest generation | Scans `SKILL.md` directories (`skills`), `.md` files with Claude-first agent mapping (`agentRules`), `mcp-servers.json` (`mcpServers`), and agent-definition Markdown files (`agentDefinitions`); shared surfaces default to the primary deploy target instead of shared riders; emits hints for `files/` and `configs/` directories | N/A |
58
60
  | Instruction preflight analysis | Emits capability warnings for implementation-only, planned, unsupported, and shared-through surfaces used by the manifest; emits `precedence` warnings when an agent has multiple `agentRules` scopes active simultaneously or the same source file is deployed to multiple scopes; emits `budget` warnings when `agentRules` or `agentDefinitions` source files exceed 50 KB; emits GitHub Copilot enterprise-policy warnings when local configuration may be overridden; emits a `config-authority` warning when Gemini CLI's `settings.json` contains an `instructionFilename` override that differs from the deploy target | N/A |
@@ -135,6 +137,36 @@ Create an `inception.json` file at the root of your skills directory:
135
137
  "path": "agents/code-reviewer.md",
136
138
  "agents": ["claude-code", "opencode", "github-copilot"]
137
139
  }
140
+ ],
141
+ "hooks": [
142
+ {
143
+ "name": "pre-exec-check",
144
+ "agents": ["claude-code"],
145
+ "config": {
146
+ "hooks": {
147
+ "PreToolUse": [
148
+ {
149
+ "matcher": "Bash",
150
+ "hooks": [{ "type": "command", "command": "scripts/check-env.sh" }]
151
+ }
152
+ ],
153
+ "Stop": [
154
+ {
155
+ "hooks": [{ "type": "command", "command": "scripts/notify.sh" }]
156
+ }
157
+ ]
158
+ }
159
+ }
160
+ }
161
+ ],
162
+ "executionConfigs": [
163
+ {
164
+ "name": "gemini-safety",
165
+ "agents": ["gemini-cli"],
166
+ "config": {
167
+ "safeMode": true
168
+ }
169
+ }
138
170
  ]
139
171
  }
140
172
  ```
@@ -166,17 +198,18 @@ Each **mcpServer** entry registers an MCP server into the agent's config file by
166
198
  - **name** - Unique identifier (same format as skill names); used as the server's key in the config
167
199
  - **agents** - Array of agent IDs to register this server with
168
200
  - **config** - Raw server descriptor object. For the currently supported JSON-backed adapters, inception-engine requires at least one non-empty `command` or `url` field, validates `args` as an array of strings when present, and validates `env` as a string-to-string object when present. Additional keys are passed through verbatim.
169
- - **scope** - `"global"` (default), `"repo"`, or `"workspace"`. For most agents this field is ignored (they have only a single user-level config path). For `github-copilot`, `scope` selects the target file:
201
+ - **scope** - `"global"` (default), `"repo"`, `"workspace"`, or `"devcontainer"`. For most agents this field is ignored (they have only a single user-level config path). For `github-copilot`, `scope` selects the target file:
170
202
  - `"global"` — unsupported; emits a warning and is skipped
171
203
  - `"repo"` — deploys to `{repo}/.vscode/mcp.json` under the `servers` key
172
204
  - `"workspace"` — deploys to `{workspace}/.vscode/mcp.json` under the `servers` key
205
+ - `"devcontainer"` — deploys to `{repo}/.devcontainer/devcontainer.json` under the `customizations.vscode.mcp.servers` key
173
206
 
174
207
  GitHub Copilot's `.vscode/mcp.json` uses `servers` (not `mcpServers`) as the top-level key and optionally accepts a `type` field (`"stdio"` | `"sse"` | `"http"`) in the server descriptor, which is passed through verbatim.
175
208
 
176
209
  MCP server registration is supported for all agents. Inception-engine automatically uses the correct adapter for each agent's configuration schema:
177
- - **JSON (Merge Patch)**: `claude-code` (`~/.claude.json` for `scope: "global"`; `{repo}/.claude/mcp.json` for `scope: "repo"`; `{workspace}/.claude/mcp.json` for `scope: "workspace"`), `gemini-cli` (`~/.gemini/settings.json`), `opencode` (`~/.config/opencode/opencode.json` using the custom `"mcp"` key), and `github-copilot` (`{repo}/.vscode/mcp.json` or `{workspace}/.vscode/mcp.json` using the `"servers"` key).
210
+ - **JSON (Merge Patch)**: `claude-code` (`~/.claude.json` for `scope: "global"`; `{repo}/.claude/mcp.json` for `scope: "repo"`; `{workspace}/.claude/mcp.json` for `scope: "workspace"`), `gemini-cli` (`~/.gemini/settings.json`), `antigravity` (`~/.gemini/antigravity/mcp_config.json` for `scope: "global"`), `opencode` (`~/.config/opencode/opencode.json` using the custom `"mcp"` key), and `github-copilot` (`{repo}/.vscode/mcp.json`, `{workspace}/.vscode/mcp.json`, or `{repo}/.devcontainer/devcontainer.json`).
178
211
  - **TOML (Patch)**: `codex` (`~/.codex/config.toml`).
179
- - **Markdown Frontmatter (Emit)**: `antigravity` (repo-local `.agents/rules/{name}.md` files).
212
+ - **Markdown Frontmatter (Emit)**: `antigravity` (`{repo}/.agents/rules/{name}.md` for `scope: "repo"`).
180
213
 
181
214
  For Markdown frontmatter targets, inception-engine now records patch-level provenance for the emitted frontmatter block. Deploy merges only the owned frontmatter keys, preserves unrelated frontmatter and Markdown body content, and `revert` removes only the engine-owned keys instead of deleting the whole file unless inception-engine originally created an otherwise-empty file.
182
215
 
@@ -189,10 +222,12 @@ Each **agentRules** entry deploys a Markdown instruction file to an agent's supp
189
222
  - **name** - Unique identifier (same format as skill names)
190
223
  - **path** - Relative path to the source Markdown file within the repo; supported rules adapters require a `.md` or `.markdown` source path
191
224
  - **agents** - Array of agent IDs to deploy this file to
192
- - **scope** - `"global"` (default), `"repo"`, or `"workspace"`. Controls which instruction surface is targeted:
225
+ - **scope** - `"global"` (default), `"repo"`, `"workspace"`, `"copilot-repo"`, or `"copilot-scoped"`. Controls which instruction surface is targeted:
193
226
  - `"global"` — deploys to the agent's home-directory instruction file when that surface is supported (e.g., `~/.claude/CLAUDE.md` for `claude-code`)
194
227
  - `"repo"` — deploys to the project-root instruction file inside the deployed repository when that surface is supported (e.g., `{repo}/CLAUDE.md` for `claude-code`)
195
228
  - `"workspace"` — deploys to the workspace-root instruction file when an agent exposes one (e.g., `{workspace}/CLAUDE.md` for `claude-code`); when unsupported, deployment is skipped with a warning
229
+ - `"copilot-repo"` — deploys to GitHub Copilot's native repo-level instruction file at `{repo}/.github/copilot-instructions.md` (`github-copilot` only; other agents are warned and skipped)
230
+ - `"copilot-scoped"` — deploys to `{repo}/.github/instructions/{name}.instructions.md` where `{name}` is the manifest entry name (`github-copilot` only; other agents are warned and skipped)
196
231
 
197
232
  Instruction rule deployment is supported for implemented global, repo, and workspace surfaces. The target path depends on the agent and the `scope`:
198
233
 
@@ -205,7 +240,13 @@ Instruction rule deployment is supported for implemented global, repo, and works
205
240
  | `opencode` | `~/.config/opencode/AGENTS.md` | `{repo}/AGENTS.md` | unsupported; warns and skips |
206
241
  | `github-copilot` | unsupported / Claude-first | deploy via `claude-code` | unsupported; deploy via `claude-code` with `scope: "workspace"` |
207
242
 
208
- For `antigravity`, `agentRules` now targets the shared GEMINI.md surface (`~/.gemini/GEMINI.md` for `global`, `{repo}/GEMINI.md` for `repo`) — the same paths used by `gemini-cli`. When both agents appear in the same entry, deduplication ensures only one write action is emitted. `workspace` scope is not supported and is skipped with a warning. For `github-copilot`, no separate deployment is needed — target it via the `claude-code` agentRules entry and it reaches Copilot automatically. Revert removes the deployed rules file.
243
+ GitHub Copilot also exposes two native instruction surfaces via dedicated scope values:
244
+
245
+ | Agent | `scope: "copilot-repo"` | `scope: "copilot-scoped"` |
246
+ |---|---|---|
247
+ | `github-copilot` | `{repo}/.github/copilot-instructions.md` | `{repo}/.github/instructions/{name}.instructions.md` |
248
+
249
+ For `antigravity`, `agentRules` now targets the shared GEMINI.md surface (`~/.gemini/GEMINI.md` for `global`, `{repo}/GEMINI.md` for `repo`) — the same paths used by `gemini-cli`. When both agents appear in the same entry, deduplication ensures only one write action is emitted. `workspace` scope is not supported and is skipped with a warning. For `github-copilot`, the Claude-first path (targeting via `claude-code` agentRules) remains the recommended approach for shared rules; the `copilot-repo` and `copilot-scoped` scopes are for Copilot-specific instructions that should not be shared with other agents. When both are present, preflight emits a precedence warning. Revert removes the deployed rules file.
209
250
 
210
251
  Each **permissions** entry deploys execution and safety-oriented configuration to an agent's permission or approval surface:
211
252
 
@@ -248,6 +289,40 @@ Valid `approval_policy` values are `"auto"`, `"manual"`, `"suggest"`, and `"on-f
248
289
 
249
290
  Revert restores the previous config values using the undo patch recorded at deploy time.
250
291
 
292
+ Each **hooks** entry deploys lifecycle-binding configurations to an agent's execution hook surface:
293
+
294
+ - **name** - Unique identifier (same format as skill names)
295
+ - **agents** - Array of agent IDs to deploy this entry to
296
+ - **config** - Hook configuration payload; shape is validated per agent (see below)
297
+
298
+ Hook deployment is currently supported for `claude-code`. For `github-copilot`, it is marked as `planned`. Other agents emit a warning and are skipped.
299
+
300
+ For `claude-code`, the config is merged into `~/.claude/settings.json`. Only the `hooks` key is accepted. Event names follow Claude Code's settings.json hooks surface (e.g. `PreToolUse`, `PostToolUse`, `Notification`, `Stop`, `SubagentStop`). Each event maps to an array of hook matchers; each matcher has an optional `matcher` string and a required `hooks` array of `{ type: "command", command: string }` objects:
301
+
302
+ ```json
303
+ {
304
+ "name": "pre-exec-check",
305
+ "agents": ["claude-code"],
306
+ "config": {
307
+ "hooks": {
308
+ "PreToolUse": [
309
+ {
310
+ "matcher": "Bash",
311
+ "hooks": [{ "type": "command", "command": "scripts/check-env.sh" }]
312
+ }
313
+ ],
314
+ "Stop": [
315
+ {
316
+ "hooks": [{ "type": "command", "command": "scripts/notify.sh" }]
317
+ }
318
+ ]
319
+ }
320
+ }
321
+ }
322
+ ```
323
+
324
+ Revert restores the previous config values using the undo patch recorded at deploy time.
325
+
251
326
  Each **agentDefinitions** entry deploys an agent-definition file to the agent-definition directory of each targeted agent. `scope: "repo"` is the default, and some agents also support `scope: "global"`:
252
327
 
253
328
  - **name** - Unique identifier (same format as skill names); used as the definition filename
@@ -303,7 +378,7 @@ Current `init` behavior:
303
378
  - Applies either the `--agents` list or all currently known agent IDs
304
379
  - Refuses to overwrite an existing `inception.json` unless `--force` is provided
305
380
  - Supports `--plan` so you can inspect the generated manifest before writing it
306
- - Discovers agent-rules Markdown files in the root and conventional subdirectories (`rules/`, `instructions/`, `.github/`), mapping them to agents using Claude-first portability conventions: `copilot-instructions.md` maps to `claude-code` (Copilot reads `CLAUDE.md` natively), and the fallback for unrecognized files excludes unsupported agents plus shared-surface riders that should default to their primary deploy target
381
+ - Discovers agent-rules Markdown files in the root and conventional subdirectories (`rules/`, `instructions/`, `.github/`), mapping them to agents using Claude-first portability conventions: `copilot-instructions.md` found outside `.github/` maps to `claude-code` (Copilot reads `CLAUDE.md` natively), `.github/copilot-instructions.md` maps to `github-copilot` with `scope: "copilot-repo"`, and `*.instructions.md` files in `.github/instructions/` map to `github-copilot` with `scope: "copilot-scoped"`; the fallback for unrecognized files excludes unsupported agents plus shared-surface riders that should default to their primary deploy target
307
382
  - Reads `mcp-servers.json` from the repo root (if present) and generates `mcpServers` entries; invalid entries are warned and skipped
308
383
  - Reads `files-manifest.json` from the repo root (if present) and generates `files` entries; invalid entries are warned and skipped
309
384
  - Reads `configs-manifest.json` from the repo root (if present) and generates `configs` entries; invalid entries are warned and skipped
@@ -18,6 +18,7 @@ export const AGENT_REGISTRY = [
18
18
  mcpConfig: "documented",
19
19
  agentRules: "documented",
20
20
  permissions: "documented",
21
+ hooks: "documented",
21
22
  agentDefinitions: "documented",
22
23
  },
23
24
  mcpSupport: {
@@ -68,6 +69,14 @@ export const AGENT_REGISTRY = [
68
69
  windows: ["{home}", ".claude", "settings.json"],
69
70
  },
70
71
  },
72
+ hooksSupport: {
73
+ status: "supported",
74
+ schemaLabel: "JSON hooks config",
75
+ path: {
76
+ posix: ["{home}", ".claude", "settings.json"],
77
+ windows: ["{home}", ".claude", "settings.json"],
78
+ },
79
+ },
71
80
  agentDefinitionsRepoSupport: {
72
81
  status: "supported",
73
82
  schemaLabel: "repo-local agent definition Markdown file",
@@ -103,6 +112,7 @@ export const AGENT_REGISTRY = [
103
112
  detectBinary: "documented",
104
113
  agentRules: "documented",
105
114
  permissions: "documented",
115
+ hooks: "provisional",
106
116
  },
107
117
  mcpSupport: {
108
118
  status: "supported",
@@ -136,6 +146,11 @@ export const AGENT_REGISTRY = [
136
146
  windows: ["{home}", ".codex", "config.toml"],
137
147
  },
138
148
  },
149
+ hooksSupport: {
150
+ status: "unsupported",
151
+ schemaLabel: "global hooks surface",
152
+ reason: "OpenAI Codex does not expose a documented lifecycle-hook config surface in config.toml",
153
+ },
139
154
  agentDefinitionsRepoSupport: {
140
155
  status: "unsupported",
141
156
  schemaLabel: "dedicated agent definition directory",
@@ -168,7 +183,9 @@ export const AGENT_REGISTRY = [
168
183
  detectBinary: "documented",
169
184
  mcpConfig: "documented",
170
185
  agentRules: "documented",
186
+ hooks: "provisional",
171
187
  agentDefinitions: "documented",
188
+ executionConfig: "provisional",
172
189
  },
173
190
  mcpSupport: {
174
191
  status: "supported",
@@ -202,6 +219,12 @@ export const AGENT_REGISTRY = [
202
219
  schemaLabel: "global permissions surface",
203
220
  reason: "Gemini CLI does not expose a documented global per-user permission or approval config surface",
204
221
  },
222
+ hooksSupport: {
223
+ status: "planned",
224
+ schemaLabel: "global hooks surface",
225
+ plannedSurface: "settings.json hooks field",
226
+ reason: "Gemini CLI execution hooks are emerging and not yet settled",
227
+ },
205
228
  agentDefinitionsSupport: {
206
229
  status: "supported",
207
230
  schemaLabel: "global agent definition Markdown file",
@@ -234,6 +257,14 @@ export const AGENT_REGISTRY = [
234
257
  windows: ["{repo}", ".gemini", "agents", "{name}.toml"],
235
258
  },
236
259
  },
260
+ executionConfigSupport: {
261
+ status: "supported",
262
+ schemaLabel: "Settings execution config",
263
+ path: {
264
+ posix: ["{home}", ".gemini", "settings.json"],
265
+ windows: ["{home}", ".gemini", "settings.json"],
266
+ },
267
+ },
237
268
  agentRulesWorkspaceSupport: {
238
269
  status: "supported",
239
270
  schemaLabel: "workspace-local GEMINI.md",
@@ -263,6 +294,14 @@ export const AGENT_REGISTRY = [
263
294
  agentDefinitions: "documented",
264
295
  },
265
296
  mcpSupport: {
297
+ status: "supported",
298
+ schemaLabel: "global mcp_config.json",
299
+ path: {
300
+ posix: ["{home}", ".gemini", "antigravity", "mcp_config.json"],
301
+ windows: ["{home}", ".gemini", "antigravity", "mcp_config.json"],
302
+ },
303
+ },
304
+ mcpRepoSupport: {
266
305
  status: "supported",
267
306
  schemaLabel: "repo-local frontmatter-emit MCP rules",
268
307
  path: {
@@ -296,6 +335,11 @@ export const AGENT_REGISTRY = [
296
335
  schemaLabel: "global permissions surface",
297
336
  reason: "Antigravity does not expose a documented global per-user permission or approval config surface",
298
337
  },
338
+ hooksSupport: {
339
+ status: "unsupported",
340
+ schemaLabel: "global hooks surface",
341
+ reason: "Antigravity does not expose a documented global per-user hook config surface",
342
+ },
299
343
  agentDefinitionsRepoSupport: {
300
344
  status: "supported",
301
345
  schemaLabel: "repo-local agent definition Markdown file",
@@ -330,6 +374,7 @@ export const AGENT_REGISTRY = [
330
374
  agentRules: "documented",
331
375
  agentDefinitions: "documented",
332
376
  permissions: "documented",
377
+ hooks: "provisional",
333
378
  },
334
379
  mcpSupport: {
335
380
  status: "supported",
@@ -364,6 +409,11 @@ export const AGENT_REGISTRY = [
364
409
  windows: ["{appdata}", "opencode", "opencode.json"],
365
410
  },
366
411
  },
412
+ hooksSupport: {
413
+ status: "unsupported",
414
+ schemaLabel: "global hooks surface",
415
+ reason: "OpenCode does not expose a documented lifecycle-hook surface",
416
+ },
367
417
  agentDefinitionsSupport: {
368
418
  status: "supported",
369
419
  schemaLabel: "global agent definition Markdown file",
@@ -402,8 +452,10 @@ export const AGENT_REGISTRY = [
402
452
  provenance: {
403
453
  detectPaths: "documented",
404
454
  detectBinary: "documented",
455
+ agentRules: "documented",
405
456
  agentDefinitions: "documented",
406
457
  mcpConfig: "documented",
458
+ hooks: "provisional",
407
459
  },
408
460
  mcpSupport: {
409
461
  status: "unsupported",
@@ -472,17 +524,55 @@ export const AGENT_REGISTRY = [
472
524
  windows: ["{workspace}", "CLAUDE.md"],
473
525
  },
474
526
  },
527
+ // GitHub Copilot native repo-level instruction file. Not shared via
528
+ // CLAUDE.md; this is Copilot's own .github/copilot-instructions.md surface
529
+ // deployed directly without the shared-via deduplication path.
530
+ agentRulesCopilotRepoSupport: {
531
+ status: "supported",
532
+ surfaceKind: { kind: "agent-specific" },
533
+ schemaLabel: "repo-local .github/copilot-instructions.md",
534
+ path: {
535
+ posix: ["{repo}", ".github", "copilot-instructions.md"],
536
+ windows: ["{repo}", ".github", "copilot-instructions.md"],
537
+ },
538
+ },
539
+ // GitHub Copilot scoped instruction files. Each entry deploys to
540
+ // .github/instructions/{name}.instructions.md where {name} comes from
541
+ // the manifest entry name field.
542
+ agentRulesCopilotScopedSupport: {
543
+ status: "supported",
544
+ surfaceKind: { kind: "agent-specific" },
545
+ schemaLabel: "scoped .github/instructions/{name}.instructions.md",
546
+ path: {
547
+ posix: ["{repo}", ".github", "instructions", "{name}.instructions.md"],
548
+ windows: [
549
+ "{repo}",
550
+ ".github",
551
+ "instructions",
552
+ "{name}.instructions.md",
553
+ ],
554
+ },
555
+ },
475
556
  mcpDevcontainerSupport: {
476
- status: "planned",
557
+ status: "supported",
477
558
  schemaLabel: "devcontainer.json MCP surface",
478
- plannedSurface: "devcontainer.json customizations.vscode.mcp.servers",
479
- reason: 'devcontainer.json MCP support is planned — use scope: "repo" or scope: "workspace" to target .vscode/mcp.json in the meantime',
559
+ mcpPatchKey: "customizations.vscode.mcp.servers",
560
+ path: {
561
+ posix: ["{repo}", ".devcontainer", "devcontainer.json"],
562
+ windows: ["{repo}", ".devcontainer", "devcontainer.json"],
563
+ },
480
564
  },
481
565
  permissionsSupport: {
482
566
  status: "unsupported",
483
567
  schemaLabel: "global permissions surface",
484
568
  reason: "GitHub Copilot permissions are managed via organization policy, not a deployable per-user config surface",
485
569
  },
570
+ hooksSupport: {
571
+ status: "planned",
572
+ schemaLabel: "binary execution hooks",
573
+ plannedSurface: "agent frontmatter pre_exec/post_exec hooks",
574
+ reason: "GitHub Copilot binary hook support is planned and requires further validation of the stdin/stdout contract",
575
+ },
486
576
  agentDefinitionsRepoSupport: {
487
577
  status: "supported",
488
578
  schemaLabel: "repo-local agent definition Markdown file",
@@ -504,14 +594,7 @@ export const AGENT_REGISTRY = [
504
594
  },
505
595
  },
506
596
  policyNote: "Organization policies may override locally deployed configuration. Verify with your GitHub org admin if deployed skills or rules are not active.",
507
- unsupportedSurfaces: [
508
- {
509
- status: "planned",
510
- schemaLabel: "devcontainer.json MCP surface",
511
- plannedSurface: "devcontainer.json customizations.vscode.mcp.servers",
512
- reason: 'devcontainer.json MCP support is planned — use scope: "repo" or scope: "workspace" to target .vscode/mcp.json in the meantime',
513
- },
514
- ],
597
+ unsupportedSurfaces: [],
515
598
  instructionFrontmatterRequired: true,
516
599
  enterprisePolicyDetection: true,
517
600
  },
@@ -0,0 +1,14 @@
1
+ import type { ExecutionConfigEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, PlanWarning } from "../../types.ts";
3
+ export interface ExecutionConfigAdapterResult {
4
+ actions: ConfigPatchDeployAction[];
5
+ warnings: PlanWarning[];
6
+ }
7
+ /**
8
+ * Compiles deploy actions for executionConfigs manifest entries.
9
+ *
10
+ * Execution configuration settings (like Gemini CLI's safeMode) are patched
11
+ * directly into the agent's primary settings file using config-patch actions.
12
+ */
13
+ export declare function compileExecutionConfigActions(entry: ExecutionConfigEntry, detectedAgents: AgentId[], home: string): ExecutionConfigAdapterResult;
14
+ export declare function compileExecutionConfigReverts(entry: ExecutionConfigEntry, agentFilter: AgentId[] | null, home: string): ConfigPatchRevertAction[];
@@ -0,0 +1,60 @@
1
+ import path from "node:path";
2
+ import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
3
+ import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
+ /**
5
+ * Compiles deploy actions for executionConfigs manifest entries.
6
+ *
7
+ * Execution configuration settings (like Gemini CLI's safeMode) are patched
8
+ * directly into the agent's primary settings file using config-patch actions.
9
+ */
10
+ export function compileExecutionConfigActions(entry, detectedAgents, home) {
11
+ const actions = [];
12
+ const warnings = [];
13
+ const platform = getPlatformKey();
14
+ for (const agentId of entry.agents) {
15
+ if (!detectedAgents.includes(agentId))
16
+ continue;
17
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
18
+ if (!agent?.executionConfigSupport ||
19
+ agent.executionConfigSupport.status !== "supported") {
20
+ warnings.push({
21
+ kind: "confidence",
22
+ message: `Agent "${agentId}" does not support modeled execution configuration surfaces — skipping "${entry.name}"`,
23
+ });
24
+ continue;
25
+ }
26
+ const rawTarget = resolvePlaceholders(agent.executionConfigSupport.path[platform], entry.name, home);
27
+ const target = path.resolve(rawTarget);
28
+ actions.push({
29
+ kind: "config-patch",
30
+ skill: entry.name,
31
+ agent: agentId,
32
+ target,
33
+ patch: entry.config,
34
+ confidence: "provisional",
35
+ });
36
+ }
37
+ return { actions, warnings };
38
+ }
39
+ export function compileExecutionConfigReverts(entry, agentFilter, home) {
40
+ const actions = [];
41
+ const platform = getPlatformKey();
42
+ for (const agentId of entry.agents) {
43
+ if (agentFilter && !agentFilter.includes(agentId))
44
+ continue;
45
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
46
+ if (!agent?.executionConfigSupport ||
47
+ agent.executionConfigSupport.status !== "supported") {
48
+ continue;
49
+ }
50
+ const rawTarget = resolvePlaceholders(agent.executionConfigSupport.path[platform], entry.name, home);
51
+ const target = path.resolve(rawTarget);
52
+ actions.push({
53
+ kind: "config-patch",
54
+ skill: entry.name,
55
+ agent: agentId,
56
+ target,
57
+ });
58
+ }
59
+ return actions;
60
+ }
@@ -0,0 +1,8 @@
1
+ import type { HookEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, PlanWarning, TomlPatchDeployAction, TomlPatchRevertAction } from "../../types.ts";
3
+ export interface HooksAdapterResult {
4
+ actions: Array<ConfigPatchDeployAction | TomlPatchDeployAction>;
5
+ warnings: PlanWarning[];
6
+ }
7
+ export declare function compileHookActions(entry: HookEntry, detectedAgents: AgentId[], home: string): HooksAdapterResult;
8
+ export declare function compileHookReverts(entry: HookEntry, agentFilter: AgentId[] | null, home: string): Array<ConfigPatchRevertAction | TomlPatchRevertAction>;
@@ -0,0 +1,86 @@
1
+ import path from "node:path";
2
+ import { planCapabilityForDeploy, resolveCapabilitySurface, } from "../capabilities.js";
3
+ import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
+ import { validateHookConfigShape } from "../validation.js";
5
+ function isTomlTarget(targetPath) {
6
+ return path.extname(targetPath).toLowerCase() === ".toml";
7
+ }
8
+ export function compileHookActions(entry, detectedAgents, home) {
9
+ const actions = [];
10
+ const warnings = [];
11
+ const platform = getPlatformKey();
12
+ for (const agentId of entry.agents) {
13
+ if (!detectedAgents.includes(agentId))
14
+ continue;
15
+ const plan = planCapabilityForDeploy({
16
+ agentId,
17
+ capability: "hooks",
18
+ entryName: entry.name,
19
+ targetAgentIds: entry.agents,
20
+ });
21
+ if (plan.outcome === "warn") {
22
+ warnings.push(plan.warning);
23
+ continue;
24
+ }
25
+ if (plan.outcome === "native" || plan.outcome === "redundant")
26
+ continue;
27
+ const support = resolveCapabilitySurface(agentId, "hooks").support;
28
+ if (!support)
29
+ continue;
30
+ validateHookConfigShape(entry.config, entry.name, agentId);
31
+ const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
32
+ const resolvedTarget = path.resolve(rawTarget);
33
+ const confidence = plan.confidence ?? "provisional";
34
+ if (isTomlTarget(resolvedTarget)) {
35
+ actions.push({
36
+ kind: "toml-patch",
37
+ skill: entry.name,
38
+ agent: agentId,
39
+ target: resolvedTarget,
40
+ config: entry.config,
41
+ confidence,
42
+ });
43
+ }
44
+ else {
45
+ actions.push({
46
+ kind: "config-patch",
47
+ skill: entry.name,
48
+ agent: agentId,
49
+ target: resolvedTarget,
50
+ patch: entry.config,
51
+ confidence,
52
+ });
53
+ }
54
+ }
55
+ return { actions, warnings };
56
+ }
57
+ export function compileHookReverts(entry, agentFilter, home) {
58
+ const actions = [];
59
+ const platform = getPlatformKey();
60
+ for (const agentId of entry.agents) {
61
+ if (agentFilter && !agentFilter.includes(agentId))
62
+ continue;
63
+ const support = resolveCapabilitySurface(agentId, "hooks").support;
64
+ if (!support)
65
+ continue;
66
+ const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
67
+ const target = path.resolve(rawTarget);
68
+ if (isTomlTarget(target)) {
69
+ actions.push({
70
+ kind: "toml-patch",
71
+ skill: entry.name,
72
+ agent: agentId,
73
+ target,
74
+ });
75
+ }
76
+ else {
77
+ actions.push({
78
+ kind: "config-patch",
79
+ skill: entry.name,
80
+ agent: agentId,
81
+ target,
82
+ });
83
+ }
84
+ }
85
+ return actions;
86
+ }
@@ -1,13 +1,15 @@
1
- import type { AgentDefinitionEntry, AgentRuleEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
1
+ import type { AgentDefinitionEntry, AgentRuleEntry, ExecutionConfigEntry, HookEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
2
2
  import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, FrontmatterEmitDeployAction, PlanWarning, TomlPatchDeployAction } from "../../types.ts";
3
3
  import { compileAgentDefinitionReverts } from "./agent-definitions.ts";
4
+ import { compileExecutionConfigReverts } from "./execution-config.ts";
5
+ import { compileHookReverts } from "./hooks.ts";
4
6
  import { compileMcpServerReverts } from "./mcp.ts";
5
7
  import { compilePermissionsReverts } from "./permissions.ts";
6
8
  import { compileAgentRuleReverts } from "./rules.ts";
7
- export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
9
+ export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileExecutionConfigReverts, compileHookReverts, compileMcpServerReverts, compilePermissionsReverts, };
8
10
  export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction;
9
11
  export interface AdapterResult {
10
12
  actions: AdapterAction[];
11
13
  warnings: PlanWarning[];
12
14
  }
13
- export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], permissions: PermissionsEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, agentDefinitions?: AgentDefinitionEntry[], workspace?: string): Promise<AdapterResult>;
15
+ export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], permissions: PermissionsEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string, agentDefinitions?: AgentDefinitionEntry[], workspace?: string, hooks?: HookEntry[], executionConfigs?: ExecutionConfigEntry[]): Promise<AdapterResult>;
@@ -1,8 +1,10 @@
1
1
  import { compileAgentDefinitionActions, compileAgentDefinitionReverts, } from "./agent-definitions.js";
2
+ import { compileExecutionConfigActions, compileExecutionConfigReverts, } from "./execution-config.js";
3
+ import { compileHookActions, compileHookReverts } from "./hooks.js";
2
4
  import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
3
5
  import { compilePermissionsActions, compilePermissionsReverts, } from "./permissions.js";
4
6
  import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
5
- export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
7
+ export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileExecutionConfigReverts, compileHookReverts, compileMcpServerReverts, compilePermissionsReverts, };
6
8
  async function compileAll(entries, fn) {
7
9
  const results = await Promise.all(entries.map(fn));
8
10
  return {
@@ -10,16 +12,18 @@ async function compileAll(entries, fn) {
10
12
  warnings: results.flatMap((r) => r.warnings),
11
13
  };
12
14
  }
13
- export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions, workspace) {
15
+ export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions, workspace, hooks = [], executionConfigs = []) {
14
16
  const actions = [];
15
17
  const warnings = [];
16
- const [mcp, rules, perms, defs] = await Promise.all([
18
+ const [mcp, rules, perms, defs, hookResults, execResults] = await Promise.all([
17
19
  compileAll(mcpServers, (entry) => compileMcpServerActions(entry, detectedAgents, home, repo, workspace)),
18
20
  compileAll(agentRules, (entry) => compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
19
21
  compileAll(permissions, (entry) => compilePermissionsActions(entry, detectedAgents, home)),
20
22
  compileAll(agentDefinitions ?? [], (entry) => compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, workspace)),
23
+ compileAll(hooks, (entry) => compileHookActions(entry, detectedAgents, home)),
24
+ compileAll(executionConfigs, (entry) => compileExecutionConfigActions(entry, detectedAgents, home)),
21
25
  ]);
22
- actions.push(...mcp.actions, ...rules.actions, ...perms.actions, ...defs.actions);
23
- warnings.push(...mcp.warnings, ...rules.warnings, ...perms.warnings, ...defs.warnings);
26
+ actions.push(...mcp.actions, ...rules.actions, ...perms.actions, ...defs.actions, ...hookResults.actions, ...execResults.actions);
27
+ warnings.push(...mcp.warnings, ...rules.warnings, ...perms.warnings, ...defs.warnings, ...hookResults.warnings, ...execResults.warnings);
24
28
  return { actions, warnings };
25
29
  }
@@ -16,6 +16,20 @@ function isMarkdownTarget(targetPath) {
16
16
  const ext = path.extname(targetPath).toLowerCase();
17
17
  return ext === ".md" || ext === ".markdown";
18
18
  }
19
+ /**
20
+ * Builds a nested object from a dot-separated key path.
21
+ * e.g. ("a.b", {c: 1}) -> {a: {b: {c: 1}}}
22
+ */
23
+ function buildNestedPatch(keyPath, leafValue) {
24
+ const parts = keyPath.split(".");
25
+ let current = {
26
+ [parts[parts.length - 1]]: leafValue,
27
+ };
28
+ for (let i = parts.length - 2; i >= 0; i--) {
29
+ current = { [parts[i]]: current };
30
+ }
31
+ return current;
32
+ }
19
33
  function buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPatchKey) {
20
34
  if (isMarkdownTarget(resolvedTarget)) {
21
35
  return {
@@ -42,7 +56,7 @@ function buildMcpDeployAction(entry, agentId, resolvedTarget, confidence, mcpPat
42
56
  skill: entry.name,
43
57
  agent: agentId,
44
58
  target: resolvedTarget,
45
- patch: { [mcpPatchKey]: { [entry.name]: entry.config } },
59
+ patch: buildNestedPatch(mcpPatchKey, { [entry.name]: entry.config }),
46
60
  confidence,
47
61
  };
48
62
  }