@kuznai/inception-engine 0.8.0 → 0.10.1

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
@@ -2,7 +2,9 @@
2
2
 
3
3
  Plant skills directly into the minds of your installed AI coding agents — Claude Code, Codex, Gemini CLI, Antigravity, OpenCode, and GitHub Copilot. One command. They'll think they thought of it themselves.
4
4
 
5
- Today, inception-engine deploys skills, single files, and JSON config patches to AI coding agents. MCP configuration and agent rules remain unimplemented at the manifest level.
5
+ Today, inception-engine works as a cross-agent deployer for skills on all listed agents, plus single-file writes and JSON config patches. It also supports MCP server registration and global rules-file deployment for the subset of agents whose config surfaces are implemented and validated today.
6
+
7
+ The broader portability layer is the roadmap direction, but this README focuses on what is working now.
6
8
 
7
9
  ## Quick Start
8
10
 
@@ -38,13 +40,15 @@ Managed skills overwrite their previous version. If a target exists but was not
38
40
 
39
41
  ### Feature Support
40
42
 
41
- | Feature | Status |
42
- |---|---|
43
- | Skills (SKILL.md) | Supported via manifest and CLI |
44
- | File write | Supported via manifest and CLI |
45
- | Config patch (JSON merge) | Supported via manifest and CLI |
46
- | MCP Servers | Accepted in manifest for forward compatibility, not implemented |
47
- | Agent Rules | Accepted in manifest for forward compatibility, not implemented |
43
+ | Feature | Deploy | Revert |
44
+ |---|---|---|
45
+ | Skills (SKILL.md) | All agents via manifest and CLI | All agents |
46
+ | File write | All agents via manifest and CLI | All agents |
47
+ | Config patch (JSON merge) | All agents via manifest and CLI | All agents |
48
+ | MCP Servers | claude-code, gemini-cli; other agents are warned and skipped | claude-code, gemini-cli |
49
+ | Global Rules Files | claude-code, codex, gemini-cli, opencode; other agents are warned and skipped | claude-code, codex, gemini-cli, opencode |
50
+
51
+ 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.
48
52
 
49
53
  ## Manifest Format
50
54
 
@@ -75,8 +79,20 @@ Create an `inception.json` file at the root of your skills directory:
75
79
  "agents": ["claude-code"]
76
80
  }
77
81
  ],
78
- "mcpServers": [],
79
- "agentRules": []
82
+ "mcpServers": [
83
+ {
84
+ "name": "my-server",
85
+ "agents": ["claude-code", "gemini-cli"],
86
+ "config": { "command": "npx", "args": ["-y", "my-mcp-server"] }
87
+ }
88
+ ],
89
+ "agentRules": [
90
+ {
91
+ "name": "my-rules",
92
+ "path": "rules/CLAUDE.md",
93
+ "agents": ["claude-code"]
94
+ }
95
+ ]
80
96
  }
81
97
  ```
82
98
 
@@ -97,12 +113,26 @@ Each **config** entry applies a [JSON merge patch (RFC 7386)](https://datatracke
97
113
 
98
114
  - **name** - Unique identifier (same format as skill names)
99
115
  - **target** - Config file to patch, using the same placeholder prefix as file entries
100
- - **patch** - JSON object of keys to set. A `null` value removes the key from the target file. Non-null values are set directly (deep merge is not applied).
116
+ - **patch** - JSON object of keys to set. A `null` value removes the key from the target file. Nested object values are merged recursively; non-object values replace the existing value directly.
101
117
  - **agents** - Array of agent IDs to apply this patch to
102
118
 
103
119
  The engine records an undo-patch for each config-patch deployment so that `revert` can restore the original values.
104
120
 
105
- `mcpServers` and `agentRules` are currently parsed for forward compatibility, but the deployment engine ignores them today.
121
+ Each **mcpServer** entry registers an MCP server into the agent's config file by applying a JSON merge patch under the `mcpServers` key:
122
+
123
+ - **name** - Unique identifier (same format as skill names); used as the server's key in the config
124
+ - **agents** - Array of agent IDs to register this server with
125
+ - **config** - Raw server descriptor object (e.g. `{ "command": "...", "args": [...] }` for stdio transport). The exact shape is passed through verbatim; agent adapters handle agent-specific requirements.
126
+
127
+ MCP server registration is currently supported for `claude-code` (`~/.claude.json`) and `gemini-cli` (`~/.gemini/settings.json`). Other agents emit a warning and are skipped. Revert removes the registered server entry from the config file.
128
+
129
+ Each **agentRules** entry deploys a Markdown instruction file to an agent's supported global rules file location:
130
+
131
+ - **name** - Unique identifier (same format as skill names)
132
+ - **path** - Relative path to the source Markdown file within the repo
133
+ - **agents** - Array of agent IDs to deploy this file to
134
+
135
+ Global rules-file deployment is currently supported for `claude-code` (`~/.claude/CLAUDE.md`), `codex` (`~/.codex/AGENTS.md`), `gemini-cli` (`~/.gemini/GEMINI.md`), and `opencode` (`~/.config/opencode/AGENTS.md`). Other agents emit a warning and are skipped because their instruction surfaces are different, repo-scoped, or not implemented here yet. Revert removes the deployed rules file.
106
136
 
107
137
  ## Creating Skills
108
138
 
@@ -119,7 +149,7 @@ description: What this skill does and when to use it
119
149
  Instructions for the AI agent...
120
150
  ```
121
151
 
122
- The `name` and `description` fields in the frontmatter are required by most agents. The description determines when the agent activates the skill.
152
+ The `name` and `description` fields in the frontmatter are used by most agents. The description determines when the agent activates the skill. inception-engine does not currently validate the frontmatter — missing or malformed fields may cause the skill to be ignored or misbehave at the agent level.
123
153
 
124
154
  ## CLI Reference
125
155
 
@@ -149,19 +179,19 @@ inception-engine revert <directory> [options]
149
179
 
150
180
  ```bash
151
181
  # Deploy all skills to all detected agents
152
- npx inception-engine ./my-skills-repo
182
+ npx @kuznai/inception-engine ./my-skills-repo
153
183
 
154
184
  # Preview what would be deployed
155
- npx inception-engine ./my-skills-repo --dry-run
185
+ npx @kuznai/inception-engine ./my-skills-repo --dry-run
156
186
 
157
187
  # Deploy only to Claude Code and Codex
158
- npx inception-engine ./my-skills-repo --agents claude-code,codex
188
+ npx @kuznai/inception-engine ./my-skills-repo --agents claude-code,codex
159
189
 
160
190
  # Remove deployed skills
161
- npx inception-engine revert ./my-skills-repo
191
+ npx @kuznai/inception-engine revert ./my-skills-repo
162
192
 
163
193
  # Preview what would be removed
164
- npx inception-engine revert ./my-skills-repo --dry-run
194
+ npx @kuznai/inception-engine revert ./my-skills-repo --dry-run
165
195
  ```
166
196
 
167
197
  ## Sample Skills
@@ -171,7 +201,7 @@ The `limbo/` directory contains exceptional sample skills for testing purposes o
171
201
  Try them out:
172
202
 
173
203
  ```bash
174
- npx inception-engine limbo --dry-run
204
+ npx @kuznai/inception-engine limbo --dry-run
175
205
  ```
176
206
 
177
207
  ## Agent Detection
@@ -195,13 +225,13 @@ Revert targets all agents listed in the manifest by default (regardless of detec
195
225
 
196
226
  ### Ownership Tracking and Safe Revert
197
227
 
198
- inception-engine maintains a centralized deployment registry at `~/.inception-engine/registry.json`. Each deploy records the target path, source path, skill name, agent ID, deploy method, and timestamp. No files are written to the source repository.
228
+ inception-engine maintains a centralized deployment registry at `~/.inception-engine/registry.json`. Each deploy records the target path, skill name, agent ID, action-specific provenance (`source`/`method` for skill-dir, `source` for file-write, `patch`/`undoPatch` for config-patch), and timestamp. No files are written to the source repository.
199
229
 
200
230
  - **Registry-based ownership**: On revert, the registry is checked before removing any target. Only targets with a valid registry entry are removed. On redeploy, unmanaged targets are never replaced.
201
231
 
202
- - **Strong binding**: Each registry entry binds a specific target path to its skill, agent, and action kind, with action-specific provenance fields (`source` and `method` for skill-dir and file-write; `patch` and `undoPatch` for config-patch). A target is only considered managed if all relevant fields match a stray entry or a different deployment cannot satisfy the check.
232
+ - **Strong binding**: Each registry entry binds a specific target path to its skill, agent, and action kind. For `skill-dir` and `file-write`, ownership checks also require the recorded `source` to match before an existing target is treated as managed. For `config-patch`, overwrite protection is keyed by target path, kind, skill, and agent; the stored `patch` and `undoPatch` are used for revert bookkeeping rather than deploy-time identity checks.
203
233
 
204
- - **Atomic redeploy**: When overwriting an existing managed target, the engine renames the old target to a backup, creates the new deployment, and only removes the backup on success. If the new deployment fails, the backup is restored.
234
+ - **Atomic redeploy**: When overwriting an existing managed `skill-dir` target, the engine renames the old target to a backup, creates the new deployment, and only removes the backup on success. If the new deployment fails, the backup is restored. `file-write` and `config-patch` deployments write directly to the target without this backup/rollback model.
205
235
 
206
236
  - **Cross-platform**: The registry uses the same resolved home directory as the rest of the tool, including sudo scenarios on POSIX and elevated PowerShell on Windows.
207
237
 
@@ -15,6 +15,16 @@ export const AGENT_REGISTRY = [
15
15
  skills: "documented",
16
16
  detectPaths: "documented",
17
17
  detectBinary: "documented",
18
+ mcpConfig: "documented",
19
+ agentRules: "documented",
20
+ },
21
+ mcpConfigPath: {
22
+ posix: ["{home}", ".claude.json"],
23
+ windows: ["{home}", ".claude.json"],
24
+ },
25
+ agentRulesPath: {
26
+ posix: ["{home}", ".claude", "CLAUDE.md"],
27
+ windows: ["{home}", ".claude", "CLAUDE.md"],
18
28
  },
19
29
  },
20
30
  {
@@ -33,6 +43,12 @@ export const AGENT_REGISTRY = [
33
43
  skills: "documented",
34
44
  detectPaths: "documented",
35
45
  detectBinary: "documented",
46
+ agentRules: "documented",
47
+ },
48
+ // mcpConfigPath omitted: Codex uses TOML config, not JSON — not supported by config-patch
49
+ agentRulesPath: {
50
+ posix: ["{home}", ".codex", "AGENTS.md"],
51
+ windows: ["{home}", ".codex", "AGENTS.md"],
36
52
  },
37
53
  },
38
54
  {
@@ -51,6 +67,16 @@ export const AGENT_REGISTRY = [
51
67
  skills: "documented",
52
68
  detectPaths: "documented",
53
69
  detectBinary: "documented",
70
+ mcpConfig: "documented",
71
+ agentRules: "documented",
72
+ },
73
+ mcpConfigPath: {
74
+ posix: ["{home}", ".gemini", "settings.json"],
75
+ windows: ["{home}", ".gemini", "settings.json"],
76
+ },
77
+ agentRulesPath: {
78
+ posix: ["{home}", ".gemini", "GEMINI.md"],
79
+ windows: ["{home}", ".gemini", "GEMINI.md"],
54
80
  },
55
81
  },
56
82
  {
@@ -70,6 +96,7 @@ export const AGENT_REGISTRY = [
70
96
  detectPaths: "implementation-only",
71
97
  detectBinary: "provisional",
72
98
  },
99
+ // mcpConfigPath and agentRulesPath omitted: paths not documented strongly enough for this release
73
100
  },
74
101
  {
75
102
  id: "opencode",
@@ -87,6 +114,12 @@ export const AGENT_REGISTRY = [
87
114
  skills: "documented",
88
115
  detectPaths: "documented",
89
116
  detectBinary: "documented",
117
+ agentRules: "documented",
118
+ },
119
+ // mcpConfigPath omitted: OpenCode uses opencode.json (TOML-adjacent format), not plain JSON
120
+ agentRulesPath: {
121
+ posix: ["{xdg_config}", "opencode", "AGENTS.md"],
122
+ windows: ["{appdata}", "opencode", "AGENTS.md"],
90
123
  },
91
124
  },
92
125
  {
@@ -106,6 +139,7 @@ export const AGENT_REGISTRY = [
106
139
  detectPaths: "documented",
107
140
  detectBinary: "documented",
108
141
  },
142
+ // mcpConfigPath and agentRulesPath omitted: rules live in repo, not home dir; MCP config unclear
109
143
  policyNote: "Organization policies may override locally deployed skills. Verify with your GitHub org admin if deployed skills are not active.",
110
144
  },
111
145
  ];
@@ -0,0 +1,11 @@
1
+ import type { AgentRuleEntry, McpServerEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, ConfigPatchDeployAction, FileWriteDeployAction, PlanWarning } from "../../types.ts";
3
+ import { compileMcpServerReverts } from "./mcp.ts";
4
+ import { compileAgentRuleReverts } from "./rules.ts";
5
+ export { compileAgentRuleReverts, compileMcpServerReverts };
6
+ export type AdapterAction = ConfigPatchDeployAction | FileWriteDeployAction;
7
+ export interface AdapterResult {
8
+ actions: AdapterAction[];
9
+ warnings: PlanWarning[];
10
+ }
11
+ export declare function compileAdapterActions(mcpServers: McpServerEntry[], agentRules: AgentRuleEntry[], sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string): Promise<AdapterResult>;
@@ -0,0 +1,18 @@
1
+ import { compileMcpServerActions, compileMcpServerReverts } from "./mcp.js";
2
+ import { compileAgentRuleActions, compileAgentRuleReverts } from "./rules.js";
3
+ export { compileAgentRuleReverts, compileMcpServerReverts };
4
+ export async function compileAdapterActions(mcpServers, agentRules, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home) {
5
+ const actions = [];
6
+ const warnings = [];
7
+ for (const entry of mcpServers) {
8
+ const r = compileMcpServerActions(entry, detectedAgents, home);
9
+ actions.push(...r.actions);
10
+ warnings.push(...r.warnings);
11
+ }
12
+ for (const entry of agentRules) {
13
+ const r = await compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home);
14
+ actions.push(...r.actions);
15
+ warnings.push(...r.warnings);
16
+ }
17
+ return { actions, warnings };
18
+ }
@@ -0,0 +1,8 @@
1
+ import type { McpServerEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, ConfigPatchDeployAction, ConfigPatchRevertAction, PlanWarning } from "../../types.ts";
3
+ export interface McpAdapterResult {
4
+ actions: ConfigPatchDeployAction[];
5
+ warnings: PlanWarning[];
6
+ }
7
+ export declare function compileMcpServerActions(entry: McpServerEntry, detectedAgents: AgentId[], home: string): McpAdapterResult;
8
+ export declare function compileMcpServerReverts(entry: McpServerEntry, agentFilter: AgentId[] | null, home: string): ConfigPatchRevertAction[];
@@ -0,0 +1,51 @@
1
+ import path from "node:path";
2
+ import { AGENT_REGISTRY_BY_ID } from "../../config/agents.js";
3
+ import { getPlatformKey, resolvePlaceholders } from "../resolve.js";
4
+ export function compileMcpServerActions(entry, detectedAgents, home) {
5
+ const actions = [];
6
+ const warnings = [];
7
+ const platform = getPlatformKey();
8
+ for (const agentId of entry.agents) {
9
+ if (!detectedAgents.includes(agentId))
10
+ continue;
11
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
12
+ if (!agent?.mcpConfigPath) {
13
+ warnings.push({
14
+ kind: "confidence",
15
+ message: `mcpServers: agent "${agentId}" does not have a documented MCP config path — skipping "${entry.name}"`,
16
+ });
17
+ continue;
18
+ }
19
+ const target = resolvePlaceholders(agent.mcpConfigPath[platform], "", home);
20
+ // Ensure no stray empty segments collapse the path unexpectedly
21
+ const resolvedTarget = path.resolve(target);
22
+ actions.push({
23
+ kind: "config-patch",
24
+ skill: entry.name,
25
+ agent: agentId,
26
+ target: resolvedTarget,
27
+ patch: { mcpServers: { [entry.name]: entry.config } },
28
+ confidence: agent.provenance.mcpConfig ?? "provisional",
29
+ });
30
+ }
31
+ return { actions, warnings };
32
+ }
33
+ export function compileMcpServerReverts(entry, agentFilter, home) {
34
+ const actions = [];
35
+ const platform = getPlatformKey();
36
+ for (const agentId of entry.agents) {
37
+ if (agentFilter && !agentFilter.includes(agentId))
38
+ continue;
39
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
40
+ if (!agent?.mcpConfigPath)
41
+ continue;
42
+ const target = path.resolve(resolvePlaceholders(agent.mcpConfigPath[platform], "", home));
43
+ actions.push({
44
+ kind: "config-patch",
45
+ skill: entry.name,
46
+ agent: agentId,
47
+ target,
48
+ });
49
+ }
50
+ return actions;
51
+ }
@@ -0,0 +1,8 @@
1
+ import type { AgentRuleEntry } from "../../schemas/manifest.ts";
2
+ import type { AgentId, FileWriteDeployAction, FileWriteRevertAction, PlanWarning } from "../../types.ts";
3
+ export interface RulesAdapterResult {
4
+ actions: FileWriteDeployAction[];
5
+ warnings: PlanWarning[];
6
+ }
7
+ export declare function compileAgentRuleActions(entry: AgentRuleEntry, sourceDir: string, resolvedSourceDir: string, realRoot: string, detectedAgents: AgentId[], home: string): Promise<RulesAdapterResult>;
8
+ export declare function compileAgentRuleReverts(entry: AgentRuleEntry, agentFilter: AgentId[] | null, home: string): FileWriteRevertAction[];
@@ -0,0 +1,56 @@
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 { validateSourceFile, validateSourcePath } from "../validation.js";
5
+ export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDir, realRoot, detectedAgents, home) {
6
+ const actions = [];
7
+ const warnings = [];
8
+ const platform = getPlatformKey();
9
+ const targetAgents = entry.agents.filter((agentId) => detectedAgents.includes(agentId));
10
+ if (targetAgents.length === 0) {
11
+ return { actions, warnings };
12
+ }
13
+ // Validate the source file once (before iterating agents) since it is shared.
14
+ const source = path.resolve(sourceDir, entry.path);
15
+ await validateSourcePath(source, entry.path, resolvedSourceDir, realRoot);
16
+ await validateSourceFile(source, entry.path);
17
+ for (const agentId of targetAgents) {
18
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
19
+ if (!agent?.agentRulesPath) {
20
+ warnings.push({
21
+ kind: "confidence",
22
+ message: `agentRules: agent "${agentId}" does not have a documented rules file path — skipping "${entry.name}"`,
23
+ });
24
+ continue;
25
+ }
26
+ const target = resolvePlaceholders(agent.agentRulesPath[platform], "", home);
27
+ actions.push({
28
+ kind: "file-write",
29
+ skill: entry.name,
30
+ agent: agentId,
31
+ source,
32
+ target,
33
+ confidence: agent.provenance.agentRules ?? "provisional",
34
+ });
35
+ }
36
+ return { actions, warnings };
37
+ }
38
+ export function compileAgentRuleReverts(entry, agentFilter, home) {
39
+ const actions = [];
40
+ const platform = getPlatformKey();
41
+ for (const agentId of entry.agents) {
42
+ if (agentFilter && !agentFilter.includes(agentId))
43
+ continue;
44
+ const agent = AGENT_REGISTRY_BY_ID[agentId];
45
+ if (!agent?.agentRulesPath)
46
+ continue;
47
+ const target = resolvePlaceholders(agent.agentRulesPath[platform], "", home);
48
+ actions.push({
49
+ kind: "file-write",
50
+ skill: entry.name,
51
+ agent: agentId,
52
+ target,
53
+ });
54
+ }
55
+ return actions;
56
+ }
@@ -1,9 +1,10 @@
1
- import type { AgentId, DeployAction, Manifest, PlannedChange, PlanWarning } from "../types.ts";
1
+ import type { AgentId, DeployAction, Manifest, PlannedChange, PlanWarning, SkillDirDeployAction } from "../types.ts";
2
+ import { type RegistryPersistence } from "./ownership.ts";
2
3
  export declare function planDeploy(manifest: Manifest, sourceDir: string, detectedAgents: AgentId[], home: string): Promise<{
3
4
  actions: DeployAction[];
4
5
  warnings: PlanWarning[];
5
6
  }>;
6
- export declare function executeDeploy(actions: DeployAction[], dryRun: boolean, verbose: boolean, home: string): Promise<{
7
+ export declare function executeDeploy(actions: DeployAction[], dryRun: boolean, verbose: boolean, home: string, deps?: DeployDependencies): Promise<{
7
8
  succeeded: number;
8
9
  failed: Array<{
9
10
  action: DeployAction;
@@ -11,3 +12,22 @@ export declare function executeDeploy(actions: DeployAction[], dryRun: boolean,
11
12
  }>;
12
13
  planned: PlannedChange[];
13
14
  }>;
15
+ interface SkillDirOps {
16
+ createTarget(action: SkillDirDeployAction): Promise<void>;
17
+ removeTarget(targetPath: string): Promise<void>;
18
+ }
19
+ interface DeployFileOps {
20
+ copyFile(source: string, target: string): Promise<void>;
21
+ rename(source: string, target: string): Promise<void>;
22
+ rm(targetPath: string, options?: {
23
+ recursive?: boolean;
24
+ force?: boolean;
25
+ }): Promise<void>;
26
+ writeFile(filePath: string, content: string, encoding: BufferEncoding): Promise<void>;
27
+ }
28
+ interface DeployDependencies {
29
+ registry?: RegistryPersistence;
30
+ skillDirOps?: SkillDirOps;
31
+ fileOps?: DeployFileOps;
32
+ }
33
+ export {};