@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 +39 -5
- package/dist/config/agents.js +4 -1
- package/dist/core/adapters/rules.js +7 -0
- package/dist/core/init.d.ts +9 -0
- package/dist/core/init.js +99 -0
- package/dist/index.js +25 -0
- package/dist/types.d.ts +3 -1
- package/package.json +1 -1
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,
|
|
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"
|
|
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
|
|
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
|
|
package/dist/config/agents.js
CHANGED
|
@@ -139,7 +139,10 @@ export const AGENT_REGISTRY = [
|
|
|
139
139
|
detectPaths: "documented",
|
|
140
140
|
detectBinary: "documented",
|
|
141
141
|
},
|
|
142
|
-
//
|
|
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
|
}
|