@kuznai/inception-engine 0.10.1 → 0.11.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
@@ -1,11 +1,15 @@
1
1
  # inception-engine
2
2
 
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.
3
+ Plant skills directly into the minds of your installed AI coding agents — Claude Code, Codex, Gemini CLI, Antigravity, and OpenCode. One command. They'll think they thought of it themselves.
4
4
 
5
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
6
 
7
+ GitHub Copilot is no longer treated as a separate instruction or skill target in the product direction when it can consume Claude-native artifacts directly. If Copilot uses `CLAUDE.md` or Claude-style skill layouts without translation, inception-engine should rely on the Claude deployment path instead of maintaining duplicate Copilot-specific surfaces. Dedicated Copilot customization remains justified only where Copilot exposes a materially different interface, such as MCP-related configuration.
8
+
7
9
  The broader portability layer is the roadmap direction, but this README focuses on what is working now.
8
10
 
11
+ `init` is available as a bootstrap command, but what works today is intentionally narrow: it scans for directories containing `SKILL.md` and generates starter `skills` entries plus empty `mcpServers` and `agentRules` arrays. It does not infer `files`, `configs`, MCP server definitions, or rules files from the repository yet.
12
+
9
13
  ## Quick Start
10
14
 
11
15
  ```bash
@@ -32,7 +36,6 @@ Managed skills overwrite their previous version. If a target exists but was not
32
36
  | Gemini CLI | `gemini-cli` | `~/.gemini/skills/` | Yes | Yes | Yes |
33
37
  | Antigravity | `antigravity` | `~/.gemini/antigravity/skills/` | Yes* | Yes* | Yes* |
34
38
  | OpenCode | `opencode` | `~/.config/opencode/skills/` | Yes | Yes | Yes* |
35
- | GitHub Copilot | `github-copilot` | `~/.copilot/skills/` | Yes | Yes | Yes |
36
39
 
37
40
  \* Antigravity support is currently based on the implementation's registry path assumptions and local validation, not a strong official doc set equivalent to the other agents.
38
41
 
@@ -46,10 +49,13 @@ Managed skills overwrite their previous version. If a target exists but was not
46
49
  | File write | All agents via manifest and CLI | All agents |
47
50
  | Config patch (JSON merge) | All agents via manifest and CLI | All agents |
48
51
  | 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 |
52
+ | Global Rules Files | claude-code, codex, gemini-cli, opencode; github-copilot reads CLAUDE.md natively (deploy via claude-code); other agents are warned and skipped | claude-code, codex, gemini-cli, opencode |
53
+ | `init` manifest generation | Scans `SKILL.md` directories and writes starter `skills` entries | N/A |
50
54
 
51
55
  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.
52
56
 
57
+ For GitHub Copilot specifically, the portability rule is Claude-first: if Copilot accepts the same Claude-native instruction or skill artifact, inception-engine should not add a separate Copilot deployment feature for it.
58
+
53
59
  ## Manifest Format
54
60
 
55
61
  Create an `inception.json` file at the root of your skills directory:
@@ -60,7 +66,7 @@ Create an `inception.json` file at the root of your skills directory:
60
66
  {
61
67
  "name": "my-skill",
62
68
  "path": "skills/my-skill",
63
- "agents": ["claude-code", "codex", "gemini-cli", "antigravity", "opencode", "github-copilot"]
69
+ "agents": ["claude-code", "codex", "gemini-cli", "antigravity", "opencode"]
64
70
  }
65
71
  ],
66
72
  "files": [
@@ -132,7 +138,7 @@ Each **agentRules** entry deploys a Markdown instruction file to an agent's supp
132
138
  - **path** - Relative path to the source Markdown file within the repo
133
139
  - **agents** - Array of agent IDs to deploy this file to
134
140
 
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.
141
+ 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`). For `github-copilot`, no separate deployment is needed because Copilot reads `CLAUDE.md` natively — target it via the `claude-code` agentRules entry and it reaches Copilot automatically. Other agents emit a warning and are skipped because their instruction surfaces are different, repo-scoped, or not yet implemented. Revert removes the deployed rules file.
136
142
 
137
143
  ## Creating Skills
138
144
 
@@ -151,11 +157,30 @@ Instructions for the AI agent...
151
157
 
152
158
  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.
153
159
 
160
+ ## `init` Command
161
+
162
+ `init` is meant to bootstrap a repository that already has skill folders. It recursively scans the target directory, treats any directory containing `SKILL.md` as a skill, and writes a starter `inception.json`.
163
+
164
+ Current `init` behavior:
165
+
166
+ - Generates `skills` entries using the discovered relative paths
167
+ - Uses the directory name as the manifest skill name
168
+ - Applies either the `--agents` list or all currently known agent IDs
169
+ - Refuses to overwrite an existing `inception.json` unless `--force` is provided
170
+ - Supports `--dry-run` so you can inspect the generated manifest before writing it
171
+
172
+ Current `init` limitations:
173
+
174
+ - It does not read or validate YAML frontmatter inside `SKILL.md`
175
+ - It does not infer `files`, `configs`, `mcpServers`, or `agentRules`
176
+ - It does not reconcile generated output with the longer-term Claude-first portability direction
177
+
154
178
  ## CLI Reference
155
179
 
156
180
  ```
157
181
  inception-engine <directory> [options]
158
182
  inception-engine revert <directory> [options]
183
+ inception-engine init <directory> [options]
159
184
  ```
160
185
 
161
186
  ### Commands
@@ -164,6 +189,7 @@ inception-engine revert <directory> [options]
164
189
  |---|---|
165
190
  | `<directory>` | Deploy skills from the manifest in the given directory |
166
191
  | `revert <directory>` | Remove previously deployed skills declared in the manifest |
192
+ | `init <directory>` | Scan a directory for skill folders and generate `inception.json` |
167
193
 
168
194
  ### Options
169
195
 
@@ -171,6 +197,7 @@ inception-engine revert <directory> [options]
171
197
  |---|---|
172
198
  | `--dry-run` | Show what would be done without making changes |
173
199
  | `--agents <list>` | Comma-separated list of agent IDs to target (overrides deploy detection; restricts revert) |
200
+ | `--force` | `init` only; overwrite an existing `inception.json` |
174
201
  | `--verbose` | Show detailed output including file paths |
175
202
  | `--debug` | Show full error stack traces |
176
203
  | `--help` | Show help message |
@@ -192,6 +219,12 @@ npx @kuznai/inception-engine revert ./my-skills-repo
192
219
 
193
220
  # Preview what would be removed
194
221
  npx @kuznai/inception-engine revert ./my-skills-repo --dry-run
222
+
223
+ # Generate a starter manifest from discovered skill folders
224
+ npx @kuznai/inception-engine init ./my-skills-repo
225
+
226
+ # Preview the generated manifest without writing it
227
+ npx @kuznai/inception-engine init ./my-skills-repo --dry-run
195
228
  ```
196
229
 
197
230
  ## Sample Skills
@@ -201,6 +234,7 @@ The `limbo/` directory contains exceptional sample skills for testing purposes o
201
234
  Try them out:
202
235
 
203
236
  ```bash
237
+ npx @kuznai/inception-engine init limbo --dry-run
204
238
  npx @kuznai/inception-engine limbo --dry-run
205
239
  ```
206
240
 
@@ -139,7 +139,10 @@ export const AGENT_REGISTRY = [
139
139
  detectPaths: "documented",
140
140
  detectBinary: "documented",
141
141
  },
142
- // mcpConfigPath and agentRulesPath omitted: rules live in repo, not home dir; MCP config unclear
142
+ // agentRulesPath omitted: Copilot reads CLAUDE.md natively (Claude-first portability rule).
143
+ // Deploy via the "claude-code" agentRules entry — it reaches Copilot automatically.
144
+ // mcpConfigPath omitted: Copilot MCP config surface is not implemented here yet.
145
+ claudeNativeInstruction: true,
143
146
  policyNote: "Organization policies may override locally deployed skills. Verify with your GitHub org admin if deployed skills are not active.",
144
147
  },
145
148
  ];
@@ -16,6 +16,13 @@ export async function compileAgentRuleActions(entry, sourceDir, resolvedSourceDi
16
16
  await validateSourceFile(source, entry.path);
17
17
  for (const agentId of targetAgents) {
18
18
  const agent = AGENT_REGISTRY_BY_ID[agentId];
19
+ if (agent?.claudeNativeInstruction) {
20
+ warnings.push({
21
+ kind: "confidence",
22
+ message: `agentRules: agent "${agentId}" reads CLAUDE.md natively — deploy via "claude-code" target to reach Copilot automatically; no separate deployment needed`,
23
+ });
24
+ continue;
25
+ }
19
26
  if (!agent?.agentRulesPath) {
20
27
  warnings.push({
21
28
  kind: "confidence",
@@ -0,0 +1,9 @@
1
+ import type { AgentId } from "../schemas/manifest.ts";
2
+ export interface InitOptions {
3
+ directory: string;
4
+ agents: AgentId[] | null;
5
+ dryRun: boolean;
6
+ force: boolean;
7
+ verbose: boolean;
8
+ }
9
+ export declare function runInit(options: InitOptions): Promise<number>;
@@ -0,0 +1,99 @@
1
+ import { access, readdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { dryRunPrefix, logger } from "../logger.js";
4
+ import { AGENT_IDS } from "../schemas/manifest.js";
5
+ const SAFE_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
6
+ async function findSkillDirs(baseDir, dir, found) {
7
+ let entries;
8
+ try {
9
+ entries = await readdir(dir, { withFileTypes: true, encoding: "utf-8" });
10
+ }
11
+ catch {
12
+ return;
13
+ }
14
+ const hasSkillMd = entries.some((e) => e.isFile() && e.name === "SKILL.md");
15
+ if (hasSkillMd) {
16
+ const relPath = path.relative(baseDir, dir).split(path.sep).join("/");
17
+ const name = path.basename(dir);
18
+ if (SAFE_NAME_RE.test(name)) {
19
+ found.push({ relPath, name });
20
+ }
21
+ else {
22
+ logger.warn("init", `Skipping "${relPath}": directory name "${name}" is not a valid skill name`);
23
+ }
24
+ // Don't recurse into a skill directory
25
+ return;
26
+ }
27
+ for (const entry of entries) {
28
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
29
+ await findSkillDirs(baseDir, path.join(dir, entry.name), found);
30
+ }
31
+ }
32
+ }
33
+ function resolveSkillName(relPath, name, namesSeen) {
34
+ if (!namesSeen.has(name))
35
+ return name;
36
+ // Collision: derive unique name from path by replacing separators with hyphens
37
+ const derived = relPath.replace(/\//g, "-");
38
+ if (SAFE_NAME_RE.test(derived))
39
+ return derived;
40
+ logger.warn("init", `Skipping "${relPath}": could not generate a unique valid name (collision with "${name}")`);
41
+ return null;
42
+ }
43
+ function buildSkills(found, agents) {
44
+ const namesSeen = new Set();
45
+ const skills = [];
46
+ for (const { relPath, name } of found) {
47
+ const skillName = resolveSkillName(relPath, name, namesSeen);
48
+ if (skillName === null)
49
+ continue;
50
+ namesSeen.add(skillName);
51
+ skills.push({ name: skillName, path: relPath, agents });
52
+ }
53
+ return skills;
54
+ }
55
+ async function manifestExists(manifestPath) {
56
+ try {
57
+ await access(manifestPath);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ export async function runInit(options) {
65
+ const { directory, dryRun, force, verbose } = options;
66
+ const agents = options.agents ?? [...AGENT_IDS];
67
+ const manifestPath = path.join(directory, "inception.json");
68
+ if (!dryRun && (await manifestExists(manifestPath)) && !force) {
69
+ logger.error(`Error: ${manifestPath} already exists. Use --force to overwrite.`);
70
+ return 2;
71
+ }
72
+ const found = [];
73
+ await findSkillDirs(directory, directory, found);
74
+ if (found.length === 0) {
75
+ logger.info("No skill directories found (looking for directories containing SKILL.md).");
76
+ return 0;
77
+ }
78
+ const skills = buildSkills(found, agents);
79
+ if (skills.length === 0) {
80
+ logger.info("No skills could be added to the manifest.");
81
+ return 0;
82
+ }
83
+ const manifest = { skills, mcpServers: [], agentRules: [] };
84
+ const json = `${JSON.stringify(manifest, null, 2)}\n`;
85
+ if (dryRun) {
86
+ logger.info(`${dryRunPrefix(true)}Would write ${manifestPath} with ${skills.length} skill(s):`);
87
+ logger.info("");
88
+ logger.info(json);
89
+ return 0;
90
+ }
91
+ await writeFile(manifestPath, json, "utf-8");
92
+ logger.info(`Generated ${manifestPath} with ${skills.length} skill(s).`);
93
+ if (verbose) {
94
+ for (const s of skills) {
95
+ logger.detail(`${s.name} → ${s.path}`);
96
+ }
97
+ }
98
+ return 0;
99
+ }
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { AGENT_REGISTRY } from "./config/agents.js";
5
5
  import { loadManifest } from "./config/manifest.js";
6
6
  import { executeDeploy, planDeploy } from "./core/deploy.js";
7
7
  import { detectInstalledAgents } from "./core/detect.js";
8
+ import { runInit } from "./core/init.js";
8
9
  import { runPreflight } from "./core/preflight.js";
9
10
  import { resolveHome } from "./core/resolve.js";
10
11
  import { executeRevert, planRevert, planRevertAll } from "./core/revert.js";
@@ -17,10 +18,17 @@ inception-engine - Deploy AI agent skills
17
18
  Usage:
18
19
  inception-engine <directory> [options]
19
20
  inception-engine revert <directory> [options]
21
+ inception-engine init <directory> [options]
22
+
23
+ Commands:
24
+ <directory> Deploy skills from the manifest in the given directory
25
+ revert <directory> Remove previously deployed skills
26
+ init <directory> Scan a directory for skill folders and generate inception.json
20
27
 
21
28
  Options:
22
29
  --dry-run Show what would be done without doing it
23
30
  --agents <list> Comma-separated list of agent IDs to target
31
+ --force (init only) Overwrite an existing inception.json
24
32
  --verbose Show detailed output
25
33
  --debug Show full error stack traces
26
34
  --help Show this help message
@@ -38,6 +46,7 @@ function parseCLI(argv) {
38
46
  agents: null,
39
47
  verbose: false,
40
48
  debug: false,
49
+ force: false,
41
50
  };
42
51
  }
43
52
  let parsed;
@@ -50,6 +59,7 @@ function parseCLI(argv) {
50
59
  verbose: { type: "boolean", default: false },
51
60
  debug: { type: "boolean", default: false },
52
61
  help: { type: "boolean", default: false },
62
+ force: { type: "boolean", default: false },
53
63
  agents: { type: "string" },
54
64
  },
55
65
  });
@@ -66,6 +76,7 @@ function parseCLI(argv) {
66
76
  agents: null,
67
77
  verbose: false,
68
78
  debug: false,
79
+ force: false,
69
80
  };
70
81
  }
71
82
  let command = "deploy";
@@ -74,6 +85,10 @@ function parseCLI(argv) {
74
85
  command = "revert";
75
86
  pos = pos.slice(1);
76
87
  }
88
+ else if (pos[0] === "init") {
89
+ command = "init";
90
+ pos = pos.slice(1);
91
+ }
77
92
  if (pos.length > 1) {
78
93
  throw new UserError("INVALID_ARGS", `Unexpected argument: ${pos[1]}`);
79
94
  }
@@ -96,6 +111,7 @@ function parseCLI(argv) {
96
111
  agents,
97
112
  verbose: values.verbose,
98
113
  debug: values.debug,
114
+ force: values.force,
99
115
  };
100
116
  }
101
117
  async function main() {
@@ -104,6 +120,15 @@ async function main() {
104
120
  console.log(USAGE);
105
121
  return 0;
106
122
  }
123
+ if (options.command === "init") {
124
+ return runInit({
125
+ directory: options.directory,
126
+ agents: options.agents,
127
+ dryRun: options.dryRun,
128
+ force: options.force,
129
+ verbose: options.verbose,
130
+ });
131
+ }
107
132
  const manifest = await loadManifest(options.directory);
108
133
  const home = resolveHome();
109
134
  if (options.command === "deploy") {
package/dist/types.d.ts CHANGED
@@ -21,6 +21,7 @@ export interface AgentConfig {
21
21
  provenance: AgentProvenance;
22
22
  mcpConfigPath?: AgentPaths;
23
23
  agentRulesPath?: AgentPaths;
24
+ claudeNativeInstruction?: true;
24
25
  policyNote?: string;
25
26
  }
26
27
  export interface PlanWarning {
@@ -85,10 +86,11 @@ export interface PlannedChange {
85
86
  confidence?: Confidence;
86
87
  }
87
88
  export interface CliOptions {
88
- command: "deploy" | "revert" | "help";
89
+ command: "deploy" | "revert" | "init" | "help";
89
90
  directory: string;
90
91
  dryRun: boolean;
91
92
  agents: AgentId[] | null;
92
93
  verbose: boolean;
93
94
  debug: boolean;
95
+ force: boolean;
94
96
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuznai/inception-engine",
3
- "version": "0.10.1",
3
+ "version": "0.11.1",
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",