@kuznai/inception-engine 0.16.0 → 0.17.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
@@ -51,7 +51,8 @@ Managed skills overwrite their previous version. If a target exists but was not
51
51
  | MCP Servers | claude-code, gemini-cli, codex, antigravity, opencode; github-copilot repo-scoped surfaces are warned and skipped | claude-code, gemini-cli, codex, antigravity, opencode |
52
52
  | Global/Repo Rules Files | All agents (antigravity uses repo-local `.agents/rules/`); github-copilot reads CLAUDE.md natively (deploy via claude-code) | All agents |
53
53
  | Permissions / Approval Config | claude-code (`~/.claude/settings.json`), codex (`~/.codex/config.toml`); other agents are warned and skipped | claude-code, codex |
54
- | `init` manifest generation | Scans `SKILL.md` directories (`skills`), `.md` files with Claude-first agent mapping (`agentRules`), and `mcp-servers.json` (`mcpServers`); emits hints for `files/` and `configs/` directories | N/A |
54
+ | Agent Definitions | claude-code (`{repo}/.claude/agents/{name}.md`), gemini-cli (`{repo}/.gemini/agents/{name}.md`), antigravity (`{repo}/.agents/rules/{name}.md`), opencode (`{repo}/.opencode/agents/{name}.md`), github-copilot (`{repo}/.github/agents/{name}.agent.md`); codex is warned and skipped | All supported agents |
55
+ | `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`); emits hints for `files/` and `configs/` directories | N/A |
55
56
 
56
57
  Features that depend on agent-specific config surfaces are intentionally conservative: if a target path or schema is not implemented with enough confidence, inception-engine warns and skips it rather than guessing.
57
58
 
@@ -111,6 +112,13 @@ Create an `inception.json` file at the root of your skills directory:
111
112
  }
112
113
  }
113
114
  }
115
+ ],
116
+ "agentDefinitions": [
117
+ {
118
+ "name": "code-reviewer",
119
+ "path": "agents/code-reviewer.md",
120
+ "agents": ["claude-code", "opencode", "github-copilot"]
121
+ }
114
122
  ]
115
123
  }
116
124
  ```
@@ -199,6 +207,23 @@ Valid `approval_policy` values are `"auto"`, `"manual"`, `"suggest"`, and `"on-f
199
207
 
200
208
  Revert restores the previous config values using the undo patch recorded at deploy time.
201
209
 
210
+ Each **agentDefinitions** entry deploys a Markdown agent-definition file to the repo-local agent-definitions directory of each targeted agent:
211
+
212
+ - **name** - Unique identifier (same format as skill names); used as the definition filename
213
+ - **path** - Relative path to the source Markdown file within the repo; must be a `.md` or `.markdown` file
214
+ - **agents** - Array of agent IDs to deploy this definition to
215
+
216
+ Agent-definition deployment is supported for `claude-code`, `gemini-cli`, `antigravity`, `opencode`, and `github-copilot`. For `codex`, inception-engine emits a warning and skips the entry — use `agentRules` to deploy persona instructions to Codex instead.
217
+
218
+ All targets are repo-local (they land inside the repository being deployed, not the user's home directory):
219
+ - **claude-code**: `{repo}/.claude/agents/{name}.md`
220
+ - **gemini-cli**: `{repo}/.gemini/agents/{name}.md`
221
+ - **antigravity**: `{repo}/.agents/rules/{name}.md`
222
+ - **opencode**: `{repo}/.opencode/agents/{name}.md`
223
+ - **github-copilot**: `{repo}/.github/agents/{name}.agent.md` (note the `.agent.md` suffix)
224
+
225
+ Revert removes the deployed agent-definition file.
226
+
202
227
  ## Creating Skills
203
228
 
204
229
  Each skill is a directory containing at minimum a `SKILL.md` file with YAML frontmatter:
@@ -231,6 +256,7 @@ Current `init` behavior:
231
256
  - Reads `mcp-servers.json` from the repo root (if present) and generates `mcpServers` entries; invalid entries are warned and skipped
232
257
  - Reads `files-manifest.json` from the repo root (if present) and generates `files` entries; invalid entries are warned and skipped
233
258
  - Reads `configs-manifest.json` from the repo root (if present) and generates `configs` entries; invalid entries are warned and skipped
259
+ - Reads `agent-definitions-manifest.json` from the repo root (if present) and generates `agentDefinitions` entries; if absent, auto-discovers agent-definition Markdown files from `.claude/agents/`, `.gemini/agents/`, `.agents/rules/`, `.opencode/agents/`, and `.github/agents/`; invalid entries are warned and skipped
234
260
  - Emits guidance to create a sidecar manifest when a `files/` or `configs/` directory is detected but the corresponding sidecar file is absent
235
261
 
236
262
  Current `init` limitations:
@@ -280,6 +306,22 @@ Place a `configs-manifest.json` file at the repo root to have `init` populate th
280
306
 
281
307
  Invalid entries are warned and skipped; the rest are written into the generated manifest verbatim.
282
308
 
309
+ Place an `agent-definitions-manifest.json` file at the repo root to have `init` populate the `agentDefinitions` section automatically. The file must be a JSON array of agent-definition entries using the same schema as the `agentDefinitions` field in `inception.json`:
310
+
311
+ ```json
312
+ [
313
+ {
314
+ "name": "code-reviewer",
315
+ "path": "agents/code-reviewer.md",
316
+ "agents": ["claude-code", "opencode", "github-copilot"]
317
+ }
318
+ ]
319
+ ```
320
+
321
+ If no `agent-definitions-manifest.json` is present, `init` auto-discovers agent-definition Markdown files from five conventional subdirectories: `.claude/agents/`, `.gemini/agents/`, `.agents/rules/`, `.opencode/agents/`, and `.github/agents/`. Each discovered file is mapped to the owning agent(s). GitHub Copilot files named `{name}.agent.md` have the `.agent` infix stripped to derive the manifest name (e.g., `foo.agent.md` → name `foo`).
322
+
323
+ Invalid entries are warned and skipped; the rest are written into the generated manifest verbatim.
324
+
283
325
  ## CLI Reference
284
326
 
285
327
  ```
@@ -18,6 +18,7 @@ export const AGENT_REGISTRY = [
18
18
  mcpConfig: "documented",
19
19
  agentRules: "documented",
20
20
  permissions: "documented",
21
+ agentDefinitions: "documented",
21
22
  },
22
23
  mcpSupport: {
23
24
  status: "supported",
@@ -43,6 +44,14 @@ export const AGENT_REGISTRY = [
43
44
  windows: ["{home}", ".claude", "settings.json"],
44
45
  },
45
46
  },
47
+ agentDefinitionsSupport: {
48
+ status: "supported",
49
+ schemaLabel: "repo-local agent definition Markdown file",
50
+ path: {
51
+ posix: ["{repo}", ".claude", "agents", "{name}.md"],
52
+ windows: ["{repo}", ".claude", "agents", "{name}.md"],
53
+ },
54
+ },
46
55
  },
47
56
  {
48
57
  id: "codex",
@@ -87,6 +96,11 @@ export const AGENT_REGISTRY = [
87
96
  windows: ["{home}", ".codex", "config.toml"],
88
97
  },
89
98
  },
99
+ agentDefinitionsSupport: {
100
+ status: "unsupported",
101
+ schemaLabel: "dedicated agent definition directory",
102
+ reason: "OpenAI Codex does not expose a documented dedicated per-agent definition directory surface separate from AGENTS.md and config.toml — use agentRules to deploy persona instructions instead",
103
+ },
90
104
  },
91
105
  {
92
106
  id: "gemini-cli",
@@ -106,6 +120,7 @@ export const AGENT_REGISTRY = [
106
120
  detectBinary: "documented",
107
121
  mcpConfig: "documented",
108
122
  agentRules: "documented",
123
+ agentDefinitions: "implementation-only",
109
124
  },
110
125
  mcpSupport: {
111
126
  status: "supported",
@@ -128,6 +143,14 @@ export const AGENT_REGISTRY = [
128
143
  schemaLabel: "global permissions surface",
129
144
  reason: "Gemini CLI does not expose a documented global per-user permission or approval config surface",
130
145
  },
146
+ agentDefinitionsSupport: {
147
+ status: "supported",
148
+ schemaLabel: "repo-local agent definition Markdown file",
149
+ path: {
150
+ posix: ["{repo}", ".gemini", "agents", "{name}.md"],
151
+ windows: ["{repo}", ".gemini", "agents", "{name}.md"],
152
+ },
153
+ },
131
154
  },
132
155
  {
133
156
  id: "antigravity",
@@ -145,6 +168,8 @@ export const AGENT_REGISTRY = [
145
168
  skills: "implementation-only",
146
169
  detectPaths: "implementation-only",
147
170
  detectBinary: "provisional",
171
+ agentRules: "documented",
172
+ agentDefinitions: "documented",
148
173
  },
149
174
  mcpSupport: {
150
175
  status: "supported",
@@ -167,6 +192,14 @@ export const AGENT_REGISTRY = [
167
192
  schemaLabel: "global permissions surface",
168
193
  reason: "Antigravity does not expose a documented global per-user permission or approval config surface",
169
194
  },
195
+ agentDefinitionsSupport: {
196
+ status: "supported",
197
+ schemaLabel: "repo-local agent definition Markdown file",
198
+ path: {
199
+ posix: ["{repo}", ".agents", "rules", "{name}.md"],
200
+ windows: ["{repo}", ".agents", "rules", "{name}.md"],
201
+ },
202
+ },
170
203
  },
171
204
  {
172
205
  id: "opencode",
@@ -185,6 +218,7 @@ export const AGENT_REGISTRY = [
185
218
  detectPaths: "documented",
186
219
  detectBinary: "documented",
187
220
  agentRules: "documented",
221
+ agentDefinitions: "documented",
188
222
  },
189
223
  mcpSupport: {
190
224
  status: "supported",
@@ -208,28 +242,37 @@ export const AGENT_REGISTRY = [
208
242
  schemaLabel: "global permissions surface",
209
243
  reason: "OpenCode does not expose a documented global per-user permission or approval config surface",
210
244
  },
245
+ agentDefinitionsSupport: {
246
+ status: "supported",
247
+ schemaLabel: "repo-local agent definition Markdown file",
248
+ path: {
249
+ posix: ["{repo}", ".opencode", "agents", "{name}.md"],
250
+ windows: ["{repo}", ".opencode", "agents", "{name}.md"],
251
+ },
252
+ },
211
253
  },
212
254
  {
213
255
  id: "github-copilot",
214
256
  displayName: "GitHub Copilot",
215
- skills: {
216
- posix: ["{home}", ".copilot", "skills", "{name}"],
217
- windows: ["{home}", ".copilot", "skills", "{name}"],
218
- },
257
+ // No `skills` field: GitHub Copilot natively executes Claude-style skills
258
+ // from `.claude/skills/` (the same path used by claude-code). Deploying
259
+ // via the `claude-code` skills target automatically covers Copilot — no
260
+ // separate `~/.copilot/skills/` path is needed or maintained.
219
261
  detectPaths: {
220
262
  posix: ["{home}", ".copilot"],
221
263
  windows: ["{home}", ".copilot"],
222
264
  },
223
265
  detectBinary: "github-copilot",
224
266
  provenance: {
225
- skills: "documented",
226
267
  detectPaths: "documented",
227
268
  detectBinary: "documented",
269
+ agentDefinitions: "documented",
228
270
  },
229
271
  mcpSupport: {
230
- status: "unsupported",
272
+ status: "planned",
231
273
  schemaLabel: "repo-scoped MCP surfaces",
232
- reason: "GitHub Copilot MCP support depends on repo-scoped files such as devcontainer or agent-frontmatter mappings, which are not translated here",
274
+ plannedSurface: "devcontainer (.devcontainer/devcontainer.json) and agent-frontmatter (.github/agents/*.agent.md)",
275
+ reason: "GitHub Copilot MCP support will be implemented via repo-scoped devcontainer features and agent-frontmatter mappings — surfaces that are genuinely Copilot-specific and not covered by other agent targets",
233
276
  },
234
277
  agentRulesSupport: {
235
278
  status: "unsupported",
@@ -241,7 +284,15 @@ export const AGENT_REGISTRY = [
241
284
  schemaLabel: "global permissions surface",
242
285
  reason: "GitHub Copilot permissions are managed via organization policy, not a deployable per-user config surface",
243
286
  },
244
- policyNote: "Organization policies may override locally deployed skills. Verify with your GitHub org admin if deployed skills are not active.",
287
+ agentDefinitionsSupport: {
288
+ status: "supported",
289
+ schemaLabel: "repo-local agent definition Markdown file",
290
+ path: {
291
+ posix: ["{repo}", ".github", "agents", "{name}.agent.md"],
292
+ windows: ["{repo}", ".github", "agents", "{name}.agent.md"],
293
+ },
294
+ },
295
+ policyNote: "Organization policies may override locally deployed configuration. Verify with your GitHub org admin if deployed skills or rules are not active.",
245
296
  },
246
297
  ];
247
298
  export const AGENT_REGISTRY_BY_ID = Object.fromEntries(AGENT_REGISTRY.map((a) => [a.id, a]));
@@ -42,6 +42,8 @@ function validateManifest(data, filePath) {
42
42
  if (issuePath.length === 1 &&
43
43
  (issuePath[0] === "mcpServers" ||
44
44
  issuePath[0] === "agentRules" ||
45
+ issuePath[0] === "agentDefinitions" ||
46
+ issuePath[0] === "permissions" ||
45
47
  issuePath[0] === "files" ||
46
48
  issuePath[0] === "configs")) {
47
49
  throw new UserError("MANIFEST_INVALID", `${filePath}: "${issuePath[0]}" must be an array`);
@@ -0,0 +1,20 @@
1
+ import type { AgentDefinitionEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, FileWriteDeployAction, FileWriteRevertAction, PlanWarning } from "../../types.ts";
3
+ export interface AgentDefinitionsAdapterResult {
4
+ actions: FileWriteDeployAction[];
5
+ warnings: PlanWarning[];
6
+ }
7
+ /**
8
+ * Compiles deploy actions for agentDefinitions manifest entries.
9
+ *
10
+ * Agent definition files are Markdown files (typically with YAML frontmatter)
11
+ * that define custom agents or subagents for a given platform. Unlike
12
+ * agentRules (which target a single shared global file per agent), each
13
+ * definition entry produces a separate file named after the entry in the
14
+ * agent's dedicated agent-definitions directory (repo-local).
15
+ *
16
+ * Target paths use the `{repo}` placeholder so definitions land in the
17
+ * repository being deployed, not the user's home directory.
18
+ */
19
+ export declare function compileAgentDefinitionActions(entry: AgentDefinitionEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string): Promise<AgentDefinitionsAdapterResult>;
20
+ export declare function compileAgentDefinitionReverts(entry: AgentDefinitionEntry, agentFilter: AgentId[] | null, home: string, repo?: string): FileWriteRevertAction[];
@@ -0,0 +1,90 @@
1
+ import path from "node:path";
2
+ import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
3
+ import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
+ import { validateAgentRuleMarkdownPath, validateSourceFile, validateSourcePath, } from "../validation.js";
5
+ /**
6
+ * Compiles deploy actions for agentDefinitions manifest entries.
7
+ *
8
+ * Agent definition files are Markdown files (typically with YAML frontmatter)
9
+ * that define custom agents or subagents for a given platform. Unlike
10
+ * agentRules (which target a single shared global file per agent), each
11
+ * definition entry produces a separate file named after the entry in the
12
+ * agent's dedicated agent-definitions directory (repo-local).
13
+ *
14
+ * Target paths use the `{repo}` placeholder so definitions land in the
15
+ * repository being deployed, not the user's home directory.
16
+ */
17
+ export async function compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo) {
18
+ const actions = [];
19
+ const warnings = [];
20
+ const platform = getPlatformKey();
21
+ const targetAgents = entry.agents.filter((agentId) => detectedAgents.includes(agentId));
22
+ const supportedTargets = [];
23
+ if (targetAgents.length === 0) {
24
+ return { actions, warnings };
25
+ }
26
+ for (const agentId of targetAgents) {
27
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
28
+ const support = agent?.agentDefinitionsSupport;
29
+ if (!support || support.status === "unsupported") {
30
+ warnings.push({
31
+ kind: "confidence",
32
+ message: `agentDefinitions: agent "${agentId}" uses ${support?.schemaLabel ?? "an unsupported agent-definition schema"} and ${support?.status === "unsupported" ? support.reason : "does not expose a supported agent-definitions adapter"} — skipping "${entry.name}"`,
33
+ });
34
+ continue;
35
+ }
36
+ if (support.status === "planned") {
37
+ warnings.push({
38
+ kind: "confidence",
39
+ message: `agentDefinitions: agent "${agentId}" agent-definitions support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
40
+ });
41
+ continue;
42
+ }
43
+ supportedTargets.push({
44
+ agentId,
45
+ confidence: agent.provenance.agentDefinitions ?? "provisional",
46
+ target: resolvePlaceholders(support.path[platform], entry.name, home, repo),
47
+ });
48
+ }
49
+ if (supportedTargets.length === 0) {
50
+ return { actions, warnings };
51
+ }
52
+ // Validate the shared source file only when at least one target is active.
53
+ const source = path.resolve(sourceDir, entry.path);
54
+ await validateSourcePath(source, entry.path, resolvedSourceDir, realRoot);
55
+ await validateSourceFile(source, entry.path);
56
+ for (const target of supportedTargets) {
57
+ validateAgentRuleMarkdownPath(entry.path, target.agentId);
58
+ actions.push({
59
+ kind: "file-write",
60
+ skill: entry.name,
61
+ agent: target.agentId,
62
+ source,
63
+ target: target.target,
64
+ confidence: target.confidence,
65
+ });
66
+ }
67
+ return { actions, warnings };
68
+ }
69
+ export function compileAgentDefinitionReverts(entry, agentFilter, home, repo) {
70
+ const actions = [];
71
+ const platform = getPlatformKey();
72
+ for (const agentId of entry.agents) {
73
+ if (agentFilter && !agentFilter.includes(agentId))
74
+ continue;
75
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
76
+ const support = agent?.agentDefinitionsSupport;
77
+ if (!support ||
78
+ support.status === "unsupported" ||
79
+ support.status === "planned")
80
+ continue;
81
+ const target = resolvePlaceholders(support.path[platform], entry.name, home, repo);
82
+ actions.push({
83
+ kind: "file-write",
84
+ skill: entry.name,
85
+ agent: agentId,
86
+ target,
87
+ });
88
+ }
89
+ return actions;
90
+ }
@@ -1,12 +1,13 @@
1
- import type { AgentRuleEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
1
+ import type { AgentDefinitionEntry, AgentRuleEntry, McpServerEntry, PermissionsEntry } from "../../schemas/manifest.ts";
2
2
  import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, FrontmatterEmitDeployAction, PlanWarning, TomlPatchDeployAction } from "../../types.ts";
3
+ import { compileAgentDefinitionReverts } from "./agent-definitions.ts";
3
4
  import { compileMcpServerReverts } from "./mcp.ts";
4
5
  import { compilePermissionsReverts } from "./permissions.ts";
5
6
  import { compileAgentRuleReverts } from "./rules.ts";
6
- export { compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
7
+ export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
7
8
  export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction | TomlPatchDeployAction | FrontmatterEmitDeployAction;
8
9
  export interface AdapterResult {
9
10
  actions: AdapterAction[];
10
11
  warnings: PlanWarning[];
11
12
  }
12
- export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], permissions: PermissionsEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string, repo?: string): Promise<AdapterResult>;
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[]): Promise<AdapterResult>;
@@ -1,8 +1,9 @@
1
+ import { compileAgentDefinitionActions, compileAgentDefinitionReverts, } from "./agent-definitions.js";
1
2
  import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
2
3
  import { compilePermissionsActions, compilePermissionsReverts, } from "./permissions.js";
3
4
  import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
4
- export { compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
5
- export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo) {
5
+ export { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, };
6
+ export async function compileAdapterActions(mcpServers, agentRules, permissions, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo, agentDefinitions) {
6
7
  const actions = [];
7
8
  const warnings = [];
8
9
  for (const entry of mcpServers) {
@@ -20,5 +21,10 @@ export async function compileAdapterActions(mcpServers, agentRules, permissions,
20
21
  actions.push(...r.actions);
21
22
  warnings.push(...r.warnings);
22
23
  }
24
+ for (const entry of agentDefinitions ?? []) {
25
+ const r = await compileAgentDefinitionActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, repo);
26
+ actions.push(...r.actions);
27
+ warnings.push(...r.warnings);
28
+ }
23
29
  return { actions, warnings };
24
30
  }
@@ -62,6 +62,13 @@ export function compileMcpServerActions(entry, detectedAgents, home, repo) {
62
62
  });
63
63
  continue;
64
64
  }
65
+ if (support.status === "planned") {
66
+ warnings.push({
67
+ kind: "confidence",
68
+ message: `mcpServers: agent "${agentId}" MCP support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
69
+ });
70
+ continue;
71
+ }
65
72
  validateMcpServerConfigShape(entry.config, entry.name, agentId);
66
73
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo);
67
74
  const resolvedTarget = path.resolve(rawTarget);
@@ -79,7 +86,9 @@ export function compileMcpServerReverts(entry, agentFilter, home, repo) {
79
86
  continue;
80
87
  const agent = AGENT_REGISTRY_BY_ID[agentId];
81
88
  const support = agent?.mcpSupport;
82
- if (!support || support.status === "unsupported")
89
+ if (!support ||
90
+ support.status === "unsupported" ||
91
+ support.status === "planned")
83
92
  continue;
84
93
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home, repo);
85
94
  const target = path.resolve(rawTarget);
@@ -21,6 +21,13 @@ export function compilePermissionsActions(entry, detectedAgents, home) {
21
21
  });
22
22
  continue;
23
23
  }
24
+ if (support.status === "planned") {
25
+ warnings.push({
26
+ kind: "confidence",
27
+ message: `permissions: agent "${agentId}" permissions support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
28
+ });
29
+ continue;
30
+ }
24
31
  validatePermissionsConfigShape(entry.config, entry.name, agentId);
25
32
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
26
33
  const resolvedTarget = path.resolve(rawTarget);
@@ -56,7 +63,9 @@ export function compilePermissionsReverts(entry, agentFilter, home) {
56
63
  continue;
57
64
  const agent = AGENT_REGISTRY_BY_ID[agentId];
58
65
  const support = agent?.permissionsSupport;
59
- if (!support || support.status === "unsupported")
66
+ if (!support ||
67
+ support.status === "unsupported" ||
68
+ support.status === "planned")
60
69
  continue;
61
70
  const rawTarget = resolvePlaceholders(support.path[platform], entry.name, home);
62
71
  const target = path.resolve(rawTarget);
@@ -21,6 +21,13 @@ export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDi
21
21
  });
22
22
  continue;
23
23
  }
24
+ if (support.status === "planned") {
25
+ warnings.push({
26
+ kind: "confidence",
27
+ message: `agentRules: agent "${agentId}" rules support is planned via ${support.plannedSurface} — skipping "${entry.name}" until that surface is implemented`,
28
+ });
29
+ continue;
30
+ }
24
31
  supportedTargets.push({
25
32
  agentId,
26
33
  confidence: agent.provenance.agentRules ?? "provisional",
@@ -56,7 +63,9 @@ export function compileAgentRuleReverts(entry, agentFilter, home, repo) {
56
63
  continue;
57
64
  const agent = AGENT_REGISTRY_BY_ID[agentId];
58
65
  const support = agent?.agentRulesSupport;
59
- if (!support || support.status === "unsupported")
66
+ if (!support ||
67
+ support.status === "unsupported" ||
68
+ support.status === "planned")
60
69
  continue;
61
70
  const target = resolvePlaceholders(support.path[platform], entry.name, home, repo);
62
71
  actions.push({
@@ -91,7 +91,7 @@ function detectAmbiguities(detectedAgents, manifest) {
91
91
  if (bothAgents(entry.agents)) {
92
92
  warnings.push({
93
93
  kind: "ambiguity",
94
- message: `Both "gemini-cli" and "antigravity" are listed in agentRules entry "${entry.name}". They share a GEMINI.md-backed instruction shared surface — verify that deploying to both does not create conflicting behavior.`,
94
+ message: `Both "gemini-cli" and "antigravity" are listed in agentRules entry "${entry.name}". They write to distinct surfaces ("gemini-cli" → ~/.gemini/GEMINI.md, "antigravity" {repo}/.agents/rules/${entry.name}.md) from the same source file — verify that deploying to both produces the intended behavior on each agent.`,
95
95
  });
96
96
  }
97
97
  }
@@ -119,6 +119,8 @@ async function planSkillDirActions(manifest, sourceDir, resolvedSourceDir, realR
119
119
  const agent = AGENT_REGISTRY_BY_ID[agentId];
120
120
  if (!agent)
121
121
  continue;
122
+ if (!agent.skills)
123
+ continue;
122
124
  actions.push({
123
125
  kind: "skill-dir",
124
126
  skill: skill.name,
@@ -126,7 +128,7 @@ async function planSkillDirActions(manifest, sourceDir, resolvedSourceDir, realR
126
128
  source,
127
129
  target: resolveAgentSkillPath(agent, skill.name, home),
128
130
  method,
129
- confidence: agent.provenance.skills,
131
+ confidence: agent.provenance.skills ?? "provisional",
130
132
  });
131
133
  }
132
134
  }
@@ -192,7 +194,7 @@ export async function planDeploy(manifest, sourceDir, detectedAgents, home) {
192
194
  ...(await planFileWriteActions(manifest, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home)),
193
195
  ...planConfigPatchActions(manifest, detectedAgents, home),
194
196
  ];
195
- const adapterResult = await compileAdapterActions(manifest.mcpServers, manifest.agentRules, manifest.permissions ?? [], sourceDir, resolvedSourceDir, realRoot, detectedAgents, home);
197
+ const adapterResult = await compileAdapterActions(manifest.mcpServers, manifest.agentRules, manifest.permissions ?? [], sourceDir, resolvedSourceDir, realRoot, detectedAgents, home, undefined, manifest.agentDefinitions ?? []);
196
198
  actions.push(...adapterResult.actions);
197
199
  const warnings = [
198
200
  ...detectAmbiguities(detectedAgents, manifest),
package/dist/core/init.js CHANGED
@@ -2,7 +2,7 @@ import { access, readFile, readdir, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { AGENT_REGISTRY_BY_ID } from "../config/agents.js";
4
4
  import { dryRunPrefix, logger } from "../logger.js";
5
- import { AGENT_IDS, ConfigEntrySchema, FileEntrySchema, McpServerEntrySchema, } from "../schemas/manifest.js";
5
+ import { AGENT_IDS, AgentDefinitionEntrySchema, ConfigEntrySchema, FileEntrySchema, McpServerEntrySchema, } from "../schemas/manifest.js";
6
6
  const SAFE_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
7
7
  // Ordered list: first match wins. Catch-all is applied at call site.
8
8
  const AGENT_RULES_FILE_PATTERNS = [
@@ -27,6 +27,16 @@ const AGENT_RULES_SUBDIRS = [
27
27
  ".github",
28
28
  ".agents/rules",
29
29
  ];
30
+ // Conventional subdirectories that contain agent definition files.
31
+ // These are the agent-specific directories that each agent scans for
32
+ // subagent/persona definitions at runtime.
33
+ const AGENT_DEFINITION_SUBDIRS = [
34
+ ".claude/agents",
35
+ ".gemini/agents",
36
+ ".agents/rules",
37
+ ".opencode/agents",
38
+ ".github/agents",
39
+ ];
30
40
  async function findSkillDirs(baseDir, dir, found) {
31
41
  let entries;
32
42
  try {
@@ -164,6 +174,117 @@ function buildAgentRules(candidates, activeAgents, skillNamesSeen) {
164
174
  }
165
175
  return rules;
166
176
  }
177
+ /**
178
+ * Derives the name for an agent definition entry from its file name.
179
+ * For GitHub Copilot's `{name}.agent.md` naming convention, strips the
180
+ * `.agent` infix in addition to the `.md` extension.
181
+ */
182
+ function deriveAgentDefinitionName(relPath, fileName) {
183
+ const ext = path.extname(fileName).toLowerCase();
184
+ // Strip the extension to get the base name, then strip any trailing ".agent"
185
+ // suffix (GitHub Copilot convention: foo.agent.md → foo).
186
+ let baseName = path.basename(fileName, ext);
187
+ if (baseName.endsWith(".agent")) {
188
+ baseName = baseName.slice(0, -".agent".length);
189
+ }
190
+ const rawName = baseName.toLowerCase().replace(/[^a-zA-Z0-9._-]/g, "-");
191
+ if (!SAFE_NAME_RE.test(rawName)) {
192
+ logger.warn("init", `Skipping "${relPath}": could not derive a valid agentDefinitions name`);
193
+ return null;
194
+ }
195
+ return rawName;
196
+ }
197
+ /**
198
+ * Maps a known agent-definition subdirectory to the agent IDs that own it.
199
+ * Returns null when the subdir is not agent-specific (fall back to all agents
200
+ * that support agentDefinitions).
201
+ */
202
+ function agentsForDefinitionSubdir(subdir) {
203
+ switch (subdir) {
204
+ case ".claude/agents":
205
+ return ["claude-code"];
206
+ case ".gemini/agents":
207
+ return ["gemini-cli"];
208
+ case ".agents/rules":
209
+ return ["antigravity"];
210
+ case ".opencode/agents":
211
+ return ["opencode"];
212
+ case ".github/agents":
213
+ return ["github-copilot"];
214
+ default:
215
+ return null;
216
+ }
217
+ }
218
+ async function scanDefinitionSubdir(subdir, baseDir, seen, skillDirRelPaths, agentRulesRelPaths, candidates) {
219
+ const suggestedAgents = agentsForDefinitionSubdir(subdir) ?? [];
220
+ const dir = path.join(baseDir, subdir);
221
+ let entries;
222
+ try {
223
+ entries = await readdir(dir, { withFileTypes: true, encoding: "utf-8" });
224
+ }
225
+ catch {
226
+ return;
227
+ }
228
+ for (const entry of entries) {
229
+ if (!entry.isFile())
230
+ continue;
231
+ const ext = path.extname(entry.name).toLowerCase();
232
+ if (ext !== ".md" && ext !== ".markdown")
233
+ continue;
234
+ const absPath = path.join(dir, entry.name);
235
+ const relPath = path.relative(baseDir, absPath).split(path.sep).join("/");
236
+ if (seen.has(relPath) ||
237
+ isInsideSkillDir(relPath, skillDirRelPaths) ||
238
+ agentRulesRelPaths.has(relPath))
239
+ continue;
240
+ const name = deriveAgentDefinitionName(relPath, entry.name);
241
+ if (name === null)
242
+ continue;
243
+ seen.add(relPath);
244
+ candidates.push({ relPath, name, suggestedAgents });
245
+ }
246
+ }
247
+ async function findAgentDefinitionCandidates(baseDir, skillDirRelPaths, agentRulesRelPaths) {
248
+ const candidates = [];
249
+ const seen = new Set();
250
+ for (const subdir of AGENT_DEFINITION_SUBDIRS) {
251
+ await scanDefinitionSubdir(subdir, baseDir, seen, skillDirRelPaths, agentRulesRelPaths, candidates);
252
+ }
253
+ return candidates;
254
+ }
255
+ function buildAgentDefinitions(candidates, activeAgents, namesSeen) {
256
+ const definitions = [];
257
+ const localNamesSeen = new Set(namesSeen);
258
+ const definitionsCapableAgents = activeAgents.filter((id) => AGENT_REGISTRY_BY_ID[id].agentDefinitionsSupport?.status !==
259
+ "unsupported");
260
+ for (const { relPath, name: rawName, suggestedAgents } of candidates) {
261
+ // Use suggested agents (from the dir that was scanned), intersected with
262
+ // active agents that support agentDefinitions. Fall back to all capable
263
+ // agents if the intersection is empty.
264
+ const intersection = suggestedAgents.length > 0
265
+ ? suggestedAgents.filter((a) => definitionsCapableAgents.includes(a))
266
+ : [];
267
+ const agents = intersection.length > 0 ? intersection : definitionsCapableAgents;
268
+ if (agents.length === 0)
269
+ continue;
270
+ // Resolve name collision
271
+ let name = rawName;
272
+ if (localNamesSeen.has(name)) {
273
+ const candidate = `${name}-agent`;
274
+ if (SAFE_NAME_RE.test(candidate)) {
275
+ logger.warn("init", `agentDefinitions name "${name}" collides with an existing name; using "${candidate}"`);
276
+ name = candidate;
277
+ }
278
+ else {
279
+ logger.warn("init", `Skipping "${relPath}": name "${name}" collides and fallback is invalid`);
280
+ continue;
281
+ }
282
+ }
283
+ localNamesSeen.add(name);
284
+ definitions.push({ name, path: relPath, agents });
285
+ }
286
+ return definitions;
287
+ }
167
288
  async function loadMcpServers(baseDir) {
168
289
  const filePath = path.join(baseDir, "mcp-servers.json");
169
290
  let raw;
@@ -263,6 +384,39 @@ async function loadConfigsManifest(baseDir) {
263
384
  }
264
385
  return results;
265
386
  }
387
+ async function loadAgentDefinitionsManifest(baseDir) {
388
+ const filePath = path.join(baseDir, "agent-definitions-manifest.json");
389
+ let raw;
390
+ try {
391
+ raw = await readFile(filePath, "utf-8");
392
+ }
393
+ catch {
394
+ return [];
395
+ }
396
+ let parsed;
397
+ try {
398
+ parsed = JSON.parse(raw);
399
+ }
400
+ catch {
401
+ logger.warn("init", "agent-definitions-manifest.json: invalid JSON, skipping");
402
+ return [];
403
+ }
404
+ if (!Array.isArray(parsed)) {
405
+ logger.warn("init", "agent-definitions-manifest.json: expected a JSON array, skipping");
406
+ return [];
407
+ }
408
+ const results = [];
409
+ for (let i = 0; i < parsed.length; i++) {
410
+ const result = AgentDefinitionEntrySchema.safeParse(parsed[i]);
411
+ if (result.success) {
412
+ results.push(result.data);
413
+ }
414
+ else {
415
+ logger.warn("init", `agent-definitions-manifest.json: entry[${i}] invalid, skipping`);
416
+ }
417
+ }
418
+ return results;
419
+ }
266
420
  async function emitDirectoryHints(baseDir, filesLoaded, configsLoaded) {
267
421
  for (const [dir, section, loaded, sidecar] of [
268
422
  ["files", "files", filesLoaded, "files-manifest.json"],
@@ -288,16 +442,20 @@ async function manifestExists(manifestPath) {
288
442
  return false;
289
443
  }
290
444
  }
291
- function logVerboseManifest(skills, agentRules, mcpServers, files, configs) {
445
+ function logPathAgentEntries(label, entries) {
446
+ if (entries.length === 0)
447
+ return;
448
+ logger.detail(`${label}:`);
449
+ for (const e of entries) {
450
+ logger.detail(` ${e.name} → ${e.path} [${e.agents.join(", ")}]`);
451
+ }
452
+ }
453
+ function logVerboseManifest(skills, agentRules, mcpServers, files, configs, agentDefinitions) {
292
454
  for (const s of skills) {
293
455
  logger.detail(`${s.name} → ${s.path}`);
294
456
  }
295
- if (agentRules.length > 0) {
296
- logger.detail("agentRules:");
297
- for (const r of agentRules) {
298
- logger.detail(` ${r.name} → ${r.path} [${r.agents.join(", ")}]`);
299
- }
300
- }
457
+ logPathAgentEntries("agentRules", agentRules);
458
+ logPathAgentEntries("agentDefinitions", agentDefinitions);
301
459
  if (mcpServers.length > 0) {
302
460
  logger.detail("mcpServers:");
303
461
  for (const m of mcpServers) {
@@ -336,6 +494,16 @@ export async function runInit(options) {
336
494
  const skillDirRelPaths = new Set(found.map((f) => f.relPath));
337
495
  const agentRulesCandidates = await findAgentRulesCandidates(directory, skillDirRelPaths);
338
496
  const agentRules = buildAgentRules(agentRulesCandidates, agentRulesCapableAgents, skillNamesSeen);
497
+ const allNamesSeen = new Set([
498
+ ...skillNamesSeen,
499
+ ...agentRules.map((r) => r.name),
500
+ ]);
501
+ const agentRulesRelPaths = new Set(agentRules.map((r) => r.path));
502
+ const agentDefinitionCandidates = await findAgentDefinitionCandidates(directory, skillDirRelPaths, agentRulesRelPaths);
503
+ const discoveredDefinitions = buildAgentDefinitions(agentDefinitionCandidates, agents, allNamesSeen);
504
+ // Sidecar file overrides take precedence over auto-discovery
505
+ const sidecarDefinitions = await loadAgentDefinitionsManifest(directory);
506
+ const agentDefinitions = sidecarDefinitions.length > 0 ? sidecarDefinitions : discoveredDefinitions;
339
507
  const mcpServers = await loadMcpServers(directory);
340
508
  const files = await loadFilesManifest(directory);
341
509
  const configs = await loadConfigsManifest(directory);
@@ -345,12 +513,14 @@ export async function runInit(options) {
345
513
  configs,
346
514
  mcpServers,
347
515
  agentRules,
516
+ agentDefinitions,
348
517
  };
349
518
  const json = `${JSON.stringify(manifest, null, 2)}\n`;
350
519
  function summarize() {
351
520
  const parts = [
352
521
  `${skills.length} skill(s)`,
353
522
  `${agentRules.length} agentRule(s)`,
523
+ `${agentDefinitions.length} agentDefinition(s)`,
354
524
  `${mcpServers.length} mcpServer(s)`,
355
525
  `${files.length} file(s)`,
356
526
  `${configs.length} config(s)`,
@@ -367,7 +537,7 @@ export async function runInit(options) {
367
537
  await writeFile(manifestPath, json, "utf-8");
368
538
  logger.info(`Generated ${manifestPath} with ${summarize()}.`);
369
539
  if (verbose) {
370
- logVerboseManifest(skills, agentRules, mcpServers, files, configs);
540
+ logVerboseManifest(skills, agentRules, mcpServers, files, configs, agentDefinitions);
371
541
  }
372
542
  await emitDirectoryHints(directory, files.length, configs.length);
373
543
  return 0;
@@ -85,6 +85,10 @@ export function getDeployMethod() {
85
85
  return process.platform === "win32" ? "copy" : "symlink";
86
86
  }
87
87
  export function resolveAgentSkillPathFor(agent, skillName, home, platform) {
88
+ if (!agent.skills) {
89
+ throw new Error(`Agent "${agent.id}" does not have a skills deployment path. ` +
90
+ `Deploy skills via another agent target that covers this agent natively (e.g. claude-code for github-copilot).`);
91
+ }
88
92
  return resolvePlaceholders(agent.skills[platform], skillName, home);
89
93
  }
90
94
  export function resolveAgentDetectPathFor(agent, home, platform) {
@@ -1,7 +1,7 @@
1
1
  import { lstat, readFile, rm, unlink, writeFile } from "node:fs/promises";
2
2
  import { AGENT_REGISTRY_BY_ID } from "../config/agents.js";
3
3
  import { logger } from "../logger.js";
4
- import { compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, } from "./adapters/index.js";
4
+ import { compileAgentDefinitionReverts, compileAgentRuleReverts, compileMcpServerReverts, compilePermissionsReverts, } from "./adapters/index.js";
5
5
  import { revertTomlMcpPatch } from "./adapters/toml.js";
6
6
  import { lookupDeployment, unregisterDeployment, } from "./ownership.js";
7
7
  import { resolveAgentSkillPath } from "./resolve.js";
@@ -15,6 +15,8 @@ function buildSkillDirReverts(manifest, home, agentFilter) {
15
15
  const agent = AGENT_REGISTRY_BY_ID[agentId];
16
16
  if (!agent)
17
17
  continue;
18
+ if (!agent.skills)
19
+ continue;
18
20
  actions.push({
19
21
  kind: "skill-dir",
20
22
  skill: skill.name,
@@ -71,6 +73,7 @@ export function planRevert(manifest, detectedAgents, home, repo) {
71
73
  ...(manifest.mcpServers ?? []).flatMap((e) => compileMcpServerReverts(e, detectedAgents, home, repo)),
72
74
  ...(manifest.agentRules ?? []).flatMap((e) => compileAgentRuleReverts(e, detectedAgents, home, repo)),
73
75
  ...(manifest.permissions ?? []).flatMap((e) => compilePermissionsReverts(e, detectedAgents, home)),
76
+ ...(manifest.agentDefinitions ?? []).flatMap((e) => compileAgentDefinitionReverts(e, detectedAgents, home, repo)),
74
77
  ];
75
78
  }
76
79
  export function planRevertAll(manifest, home, repo) {
@@ -81,6 +84,7 @@ export function planRevertAll(manifest, home, repo) {
81
84
  ...(manifest.mcpServers ?? []).flatMap((e) => compileMcpServerReverts(e, null, home, repo)),
82
85
  ...(manifest.agentRules ?? []).flatMap((e) => compileAgentRuleReverts(e, null, home, repo)),
83
86
  ...(manifest.permissions ?? []).flatMap((e) => compilePermissionsReverts(e, null, home)),
87
+ ...(manifest.agentDefinitions ?? []).flatMap((e) => compileAgentDefinitionReverts(e, null, home, repo)),
84
88
  ];
85
89
  }
86
90
  function recordOutcome(result, action, counts, failed) {
@@ -84,6 +84,18 @@ export declare const PermissionsEntrySchema: z.ZodObject<{
84
84
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
85
85
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
86
86
  }, z.core.$strip>;
87
+ export declare const AgentDefinitionEntrySchema: z.ZodObject<{
88
+ name: z.ZodString;
89
+ agents: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
90
+ "claude-code": "claude-code";
91
+ codex: "codex";
92
+ "gemini-cli": "gemini-cli";
93
+ antigravity: "antigravity";
94
+ opencode: "opencode";
95
+ "github-copilot": "github-copilot";
96
+ }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
97
+ path: z.ZodString;
98
+ }, z.core.$strip>;
87
99
  export declare const ManifestSchema: z.ZodObject<{
88
100
  skills: z.ZodArray<z.ZodObject<{
89
101
  name: z.ZodString;
@@ -159,6 +171,18 @@ export declare const ManifestSchema: z.ZodObject<{
159
171
  }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
160
172
  config: z.ZodRecord<z.ZodString, z.ZodUnknown>;
161
173
  }, z.core.$strip>>>;
174
+ agentDefinitions: z.ZodDefault<z.ZodArray<z.ZodObject<{
175
+ name: z.ZodString;
176
+ agents: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
177
+ "claude-code": "claude-code";
178
+ codex: "codex";
179
+ "gemini-cli": "gemini-cli";
180
+ antigravity: "antigravity";
181
+ opencode: "opencode";
182
+ "github-copilot": "github-copilot";
183
+ }>>>, z.ZodTransform<("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[], ("claude-code" | "codex" | "gemini-cli" | "antigravity" | "opencode" | "github-copilot")[]>>;
184
+ path: z.ZodString;
185
+ }, z.core.$strip>>>;
162
186
  }, z.core.$strip>;
163
187
  export type SkillEntry = z.infer<typeof SkillEntrySchema>;
164
188
  export type FileEntry = z.infer<typeof FileEntrySchema>;
@@ -166,6 +190,7 @@ export type ConfigEntry = z.infer<typeof ConfigEntrySchema>;
166
190
  export type McpServerEntry = z.infer<typeof McpServerEntrySchema>;
167
191
  export type AgentRuleEntry = z.infer<typeof AgentRuleEntrySchema>;
168
192
  export type PermissionsEntry = z.infer<typeof PermissionsEntrySchema>;
193
+ export type AgentDefinitionEntry = z.infer<typeof AgentDefinitionEntrySchema>;
169
194
  export type Manifest = z.infer<typeof ManifestSchema>;
170
195
  export declare const AgentListSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string[], string>>, z.ZodArray<z.ZodPipe<z.ZodString, z.ZodEnum<{
171
196
  "claude-code": "claude-code";
@@ -98,6 +98,14 @@ export const PermissionsEntrySchema = z.object({
98
98
  // For codex: { approval_policy?: "auto" | "manual" | "suggest" | "on-failure" }
99
99
  config: z.record(z.string(), z.unknown()),
100
100
  });
101
+ export const AgentDefinitionEntrySchema = z.object({
102
+ name: nameField,
103
+ agents: agentsField,
104
+ // Relative path to the agent definition Markdown file within the source bundle.
105
+ // Must be a .md or .markdown file containing YAML frontmatter that describes
106
+ // the agent's persona, instructions, and any tool configuration.
107
+ path: sourcePathField,
108
+ });
101
109
  export const ManifestSchema = z.object({
102
110
  skills: z.array(SkillEntrySchema).superRefine((skills, ctx) => {
103
111
  const seen = new Set();
@@ -117,6 +125,7 @@ export const ManifestSchema = z.object({
117
125
  mcpServers: z.array(McpServerEntrySchema).default([]),
118
126
  agentRules: z.array(AgentRuleEntrySchema).default([]),
119
127
  permissions: z.array(PermissionsEntrySchema).default([]),
128
+ agentDefinitions: z.array(AgentDefinitionEntrySchema).default([]),
120
129
  });
121
130
  // Parses the --agents CLI flag: comma-separated agent IDs → AgentId[]
122
131
  export const AgentListSchema = z
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AgentId } from "./schemas/manifest.ts";
2
- export type { AgentId, ConfigEntry, FileEntry, Manifest, SkillEntry, } from "./schemas/manifest.ts";
2
+ export type { AgentDefinitionEntry, AgentId, ConfigEntry, FileEntry, Manifest, SkillEntry, } from "./schemas/manifest.ts";
3
3
  export interface AgentPaths {
4
4
  posix: string[];
5
5
  windows: string[];
@@ -16,25 +16,47 @@ export interface UnsupportedAgentSurface {
16
16
  schemaLabel: string;
17
17
  reason: string;
18
18
  }
19
- export type AgentSurfaceSupport = SupportedAgentSurface | UnsupportedAgentSurface;
19
+ /**
20
+ * A surface that is confirmed as Copilot-specific and genuinely justified for
21
+ * future dedicated implementation, but not yet supported. Distinct from
22
+ * "unsupported" (which means the surface is either covered by another target or
23
+ * will never be added) so adapters can emit a forward-looking "planned" notice
24
+ * rather than a blocking skip warning.
25
+ */
26
+ export interface PlannedAgentSurface {
27
+ status: "planned";
28
+ schemaLabel: string;
29
+ /** Short description of the concrete file / config surface to be implemented. */
30
+ plannedSurface: string;
31
+ reason: string;
32
+ }
33
+ export type AgentSurfaceSupport = SupportedAgentSurface | UnsupportedAgentSurface | PlannedAgentSurface;
20
34
  export interface AgentProvenance {
21
- skills: Confidence;
35
+ /** Omit when the agent has no separate skill deployment path. */
36
+ skills?: Confidence;
22
37
  detectPaths: Confidence;
23
38
  detectBinary: Confidence;
24
39
  mcpConfig?: Confidence;
25
40
  agentRules?: Confidence;
26
41
  permissions?: Confidence;
42
+ agentDefinitions?: Confidence;
27
43
  }
28
44
  export interface AgentConfig {
29
45
  id: AgentId;
30
46
  displayName: string;
31
- skills: AgentPaths;
47
+ /**
48
+ * The on-disk path template for deploying skills to this agent.
49
+ * Omit for agents that consume skills from another agent's path natively
50
+ * (e.g. GitHub Copilot reads `.claude/skills/` directly).
51
+ */
52
+ skills?: AgentPaths;
32
53
  detectPaths: AgentPaths;
33
54
  detectBinary: string | null;
34
55
  provenance: AgentProvenance;
35
56
  mcpSupport?: AgentSurfaceSupport;
36
57
  agentRulesSupport?: AgentSurfaceSupport;
37
58
  permissionsSupport?: AgentSurfaceSupport;
59
+ agentDefinitionsSupport?: AgentSurfaceSupport;
38
60
  policyNote?: string;
39
61
  }
40
62
  export interface PlanWarning {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuznai/inception-engine",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Deploy AI agent skills from a git repo to user home directories",
5
5
  "license": "MIT",
6
6
  "author": "Damian Piątkowski",