cyber-agentkit 0.0.0-stage → 1.0.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/package.json CHANGED
@@ -1,6 +1,92 @@
1
1
  {
2
2
  "name": "cyber-agentkit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "description": "An agent-harness-agnostic toolkit: the fundamental features agent tools need, working the same on every harness. Detect the running harness, check plugin dependencies, resolve layered reference documents, and lease git worktrees.",
5
+ "keywords": [
6
+ "agent-harness",
7
+ "claude-code",
8
+ "cursor",
9
+ "codex",
10
+ "copilot-cli",
11
+ "opencode",
12
+ "kilo-code",
13
+ "gemini-cli",
14
+ "qwen-code",
15
+ "vscode",
16
+ "cline",
17
+ "crush",
18
+ "openhands",
19
+ "auggie"
20
+ ],
21
+ "homepage": "https://cyber-uni.github.io/cyber-agentkit/",
22
+ "bugs": {
23
+ "url": "https://github.com/cyber-uni/cyber-agentkit/issues"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/cyber-uni/cyber-agentkit.git",
28
+ "directory": "packages/cyber-agentkit"
29
+ },
30
+ "license": "MIT",
31
+ "author": "unional <homawong@gmail.com>",
32
+ "type": "module",
33
+ "sideEffects": [
34
+ "./bin/*.mjs",
35
+ "./dist/cli.js",
36
+ "./skills/*/scripts/*.mjs"
37
+ ],
38
+ "exports": {
39
+ ".": "./dist/index.js",
40
+ "./commands": "./dist/commands.js",
41
+ "./worktrees": "./dist/worktrees.js",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "bin": {
45
+ "cyber-agentkit": "bin/cyber-agentkit.mjs"
46
+ },
47
+ "files": [
48
+ "LICENSE",
49
+ "bin",
50
+ "dist",
51
+ "skills",
52
+ "references",
53
+ "plugin.json",
54
+ ".claude-plugin",
55
+ ".cursor-plugin",
56
+ ".codex-plugin"
57
+ ],
58
+ "peerDependencies": {
59
+ "clibuilder": "^12.0.0"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "clibuilder": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^24.10.1",
68
+ "clibuilder": "^12.0.0",
69
+ "tsdown": "^0.23.0",
70
+ "tsx": "^4.22.3",
71
+ "typescript": "^7.0.0",
72
+ "vitest": "^5.0.0",
73
+ "yaml": "^2.9.0"
74
+ },
75
+ "engines": {
76
+ "node": ">=22"
77
+ },
78
+ "publishConfig": {
79
+ "access": "public",
80
+ "provenance": true
81
+ },
82
+ "scripts": {
83
+ "build": "tsdown",
84
+ "generate:references": "tsx scripts/generate-references.ts",
85
+ "dev": "tsx src/index.ts",
86
+ "lint": "biome check .",
87
+ "test": "pnpm build && vitest run src",
88
+ "test:watch": "vitest",
89
+ "typecheck": "tsc --noEmit",
90
+ "verify": "pnpm typecheck && pnpm lint && pnpm test"
91
+ }
6
92
  }
package/plugin.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "cyber-agentkit",
4
+ "version": "1.0.0",
5
+ "description": "An agent-harness-agnostic toolkit: the fundamental features agent tools need, working the same on every harness. Detect the running harness, check plugin dependencies, resolve layered reference documents, and lease git worktrees.",
6
+ "author": {
7
+ "name": "unional"
8
+ },
9
+ "homepage": "https://github.com/cyber-uni/cyber-agentkit",
10
+ "repository": "https://github.com/cyber-uni/cyber-agentkit",
11
+ "license": "MIT",
12
+ "keywords": ["agent-harness", "claude-code", "cursor", "codex", "copilot-cli"],
13
+ "extensions": {
14
+ "org.cyberuni.universal-plugin": {
15
+ "skills": "./skills/",
16
+ "harnesses": {
17
+ "claude-code": {},
18
+ "cursor": {},
19
+ "codex": {},
20
+ "copilot-cli": {}
21
+ },
22
+ "scripts": {
23
+ "skills/reference/scripts/reference.mjs": "src/references/reference.skill-script.ts"
24
+ }
25
+ }
26
+ }
27
+ }
package/readme.md ADDED
@@ -0,0 +1,423 @@
1
+ # cyber-agentkit
2
+
3
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/cyber-uni/cyber-agentkit/blob/main/LICENSE)
4
+
5
+ An agent-harness-agnostic toolkit. It provides the fundamental features agent tools need and makes
6
+ each one work the same way across harnesses:
7
+
8
+ - **Harness knowledge.** Detect which harness is running, and query what it holds: managed-policy
9
+ locations, plugin storage, installed and enabled plugins, skill naming and directories, and how to
10
+ run it headless.
11
+ - **Plugin dependencies.** Check which plugins another plugin needs against what the harness has.
12
+ - **Reference documents.** Resolve the named Markdown documents an agent reads on demand.
13
+ - **Worktrees.** Lease git worktrees to concurrent agent sessions.
14
+
15
+ It depends on no other agent tool, so any of them can build on it.
16
+
17
+ **Status: pre-release.** Every fact this library encodes rests on
18
+ [`.research/harness-detection`](https://github.com/cyber-uni/cyber-agentkit/tree/main/.research/harness-detection).
19
+
20
+ ## Detect the harness
21
+
22
+ It detects Claude Code, Cursor, Codex, GitHub Copilot CLI, OpenCode, Kilo Code, Gemini CLI, Qwen
23
+ Code, GitHub Copilot in VS Code, Cline, Crush, OpenHands, and the Auggie CLI.
24
+
25
+ ```ts
26
+ import { detectHarness } from 'cyber-agentkit'
27
+
28
+ const result = detectHarness()
29
+ // {
30
+ // harness: 'claude-code',
31
+ // candidates: ['claude-code'],
32
+ // evidence: [
33
+ // { harness: 'claude-code', signal: 'CLAUDECODE', research: 'E-CC-D1', description: '…' },
34
+ // { harness: 'claude-code', signal: 'CLAUDE_CODE_CHILD_SESSION', research: 'E-CC-D3', description: '…' },
35
+ // ],
36
+ // }
37
+ ```
38
+
39
+ Detection reads environment variables that each harness sets on the processes it spawns:
40
+
41
+ | Harness | Detected from |
42
+ | --- | --- |
43
+ | Claude Code | `CLAUDECODE=1` with `CLAUDE_CODE_CHILD_SESSION=1` or `CLAUDE_CODE_SESSION_ID` |
44
+ | Cursor | `CURSOR_AGENT=1`, or `CURSOR_VERSION` with `CURSOR_PROJECT_DIR` in hooks |
45
+ | Codex | `CODEX_THREAD_ID` |
46
+ | GitHub Copilot CLI | `COPILOT_CLI=1`, `COPILOT_AGENT_SESSION_ID`, or `COPILOT_PLUGIN_ROOT` in hooks |
47
+ | OpenCode | `OPENCODE=1` with `OPENCODE_PID` |
48
+ | Kilo Code | `KILO=1` with `KILO_PID` |
49
+ | Gemini CLI | `GEMINI_CLI=1` |
50
+ | Qwen Code | `QWEN_CODE=1` |
51
+ | GitHub Copilot in VS Code | `COPILOT_AGENT=1` |
52
+ | Cline | `CLINE_ACTIVE=true`, set by the VS Code extension only |
53
+ | Crush | `CRUSH=1` |
54
+ | OpenHands | `AI_AGENT=openhands`, or `OPENHANDS_EVENT_TYPE` with `OPENHANDS_PROJECT_DIR` in hooks |
55
+ | Auggie CLI | `AUGMENT_HOOK_EVENT` with `AUGMENT_PROJECT_DIR`, in hooks only |
56
+
57
+ It reports `unknown` instead of guessing:
58
+
59
+ - when no harness matches, including `CLAUDECODE=1` on its own, which IDE extensions also set;
60
+ - when more than one harness matches, as when one harness runs inside another's shell. The matches
61
+ are listed in `candidates`;
62
+ - for `AGENT` and `AI_AGENT`, which several vendors set (only the exact value `AI_AGENT=openhands`
63
+ counts), and for `OPENCODE=1` alone, which Kilo Code, an OpenCode fork, also sets;
64
+ - in contexts where a harness sets nothing of its own: Codex, Gemini CLI, and Qwen Code hooks, Qwen
65
+ Code, Crush, OpenHands, and Auggie MCP servers, Auggie shell commands, OpenHands CLI 1.16.0 shell
66
+ commands (its SDK predates `AI_AGENT=openhands`), and the Cline CLI;
67
+ - for harnesses with no verified signal, such as Goose, Antigravity, Rovo Dev, Kiro, Amp, Factory
68
+ Droid, Devin Desktop, and Warp. The research records why for each one.
69
+
70
+ Pass `{ env }` to inspect an environment other than `process.env`.
71
+
72
+ ## Managed policy
73
+
74
+ ```ts
75
+ import { managedPolicyLocations } from 'cyber-agentkit'
76
+
77
+ managedPolicyLocations('claude-code', { platform: 'linux' })
78
+ // [
79
+ // { kind: 'server', location: 'claude.ai admin console or a self-hosted Claude apps gateway', … },
80
+ // { kind: 'file', location: '/etc/claude-code/managed-settings.json', … },
81
+ // { kind: 'directory', location: '/etc/claude-code/managed-settings.d', … },
82
+ // { kind: 'file', location: '/etc/claude-code/managed-mcp.json', … },
83
+ // ]
84
+ ```
85
+
86
+ `kind` is `file` or `directory` for what a caller can read from disk, `macos-managed-preferences`
87
+ or `windows-registry` for MDM delivery, and `server` for policy held by the vendor or the
88
+ organization. A `server` entry means the local files are not the whole policy.
89
+
90
+ ## Plugin storage
91
+
92
+ ```ts
93
+ import { pluginStorage } from 'cyber-agentkit'
94
+
95
+ pluginStorage('codex')
96
+ // {
97
+ // harness: 'codex',
98
+ // configDir: '/home/me/.codex',
99
+ // locations: [
100
+ // { kind: 'plugin-cache', path: '/home/me/.codex/plugins/cache', … },
101
+ // { kind: 'enabled-record', path: '/home/me/.codex/config.toml', … },
102
+ // ],
103
+ // }
104
+ ```
105
+
106
+ Paths are computed, not checked, so a location may not exist until the first plugin is installed.
107
+ Cursor has no `enabled-record`: no file records which of its plugins are enabled.
108
+
109
+ ## Enabled plugins
110
+
111
+ ```ts
112
+ import { enabledPlugins } from 'cyber-agentkit'
113
+
114
+ const result = await enabledPlugins('claude-code')
115
+ // {
116
+ // harness: 'claude-code',
117
+ // supported: true,
118
+ // plugins: [{ id: 'my-plugin@my-marketplace', enabled: true, scope: 'project', source: '/repo/.claude/settings.json' }],
119
+ // sources: [{ scope: 'managed', path: '/etc/claude-code/managed-settings.json', found: false }, …],
120
+ // unread: ['server-managed settings (claude.ai admin console or a self-hosted Claude apps gateway)', …],
121
+ // research: ['E-CC-P3', …],
122
+ // }
123
+ ```
124
+
125
+ | Harness | Files read, highest precedence first |
126
+ | --- | --- |
127
+ | Claude Code | managed `managed-settings.json`, `.claude/settings.local.json`, `.claude/settings.json`, `<config dir>/settings.json` |
128
+ | Codex | `<config dir>/config.toml` |
129
+ | GitHub Copilot CLI | managed `managed-settings.json`, `.github/copilot/settings.local.json`, `.github/copilot/settings.json`, `<config dir>/settings.json` |
130
+ | Cursor, OpenCode, Kilo Code, Gemini CLI, Qwen Code, Copilot in VS Code, Cline, Crush, OpenHands, Auggie CLI | none: `supported` is `false` |
131
+
132
+ Only plugins with an explicit entry are reported. A plugin with no entry falls back to a default
133
+ this package does not know. When `unread` is not empty, MDM or server-managed policy can still
134
+ override the answer.
135
+
136
+ ## Installed plugins
137
+
138
+ ```ts
139
+ import { enabledPlugins, installedPlugins } from 'cyber-agentkit'
140
+
141
+ const installed = await installedPlugins('claude-code')
142
+ // {
143
+ // harness: 'claude-code',
144
+ // supported: true,
145
+ // plugins: [{ id: 'my-plugin@my-marketplace', path: '/home/me/.claude/plugins/cache/my-marketplace/my-plugin/1.0.0', version: '1.0.0', scope: 'user', research: ['E-CC-P2'] }],
146
+ // unresolved: [],
147
+ // sources: [{ path: '/home/me/.claude/plugins/installed_plugins.json', found: true }],
148
+ // unread: [],
149
+ // research: ['E-CC-P2'],
150
+ // }
151
+
152
+ // The folder of each enabled plugin:
153
+ const enabled = new Set((await enabledPlugins('claude-code')).plugins.filter((p) => p.enabled).map((p) => p.id))
154
+ const folders = installed.plugins.filter((p) => enabled.has(p.id)).map((p) => p.path)
155
+ ```
156
+
157
+ | Harness | Read from | Folder |
158
+ | --- | --- | --- |
159
+ | Claude Code | `<config dir>/plugins/installed_plugins.json` | `installPath`; one entry per scope a plugin is installed at |
160
+ | Codex | `<config dir>/plugins/cache/<marketplace>/<plugin>/` | `local` if present, else the highest version, as Codex picks it |
161
+ | GitHub Copilot CLI | `<config dir>/config.json` `installedPlugins` | `cache_path`; a direct install's `id` is its bare name |
162
+ | Cursor, OpenCode, Kilo Code, Gemini CLI, Qwen Code, Copilot in VS Code, Cline, Crush, OpenHands, Auggie CLI | none: `supported` is `false` | — |
163
+
164
+ `unresolved` lists Codex plugins whose cache mixes semver and non-semver version folders, where the
165
+ folder Codex picks depends on its sort. Copilot CLI loads plugins from a marketplace added by local
166
+ path in place, without an install record, so they appear in `unread` instead.
167
+
168
+ ## Skill naming
169
+
170
+ ```ts
171
+ import { skillInvocation } from 'cyber-agentkit'
172
+
173
+ skillInvocation('claude-code', { plugin: 'my-plugin', skill: 'review' })?.text // '/my-plugin:review'
174
+ skillInvocation('copilot-cli', { plugin: 'my-plugin', skill: 'review' })?.text // '/review'
175
+ skillInvocation('codex', { plugin: 'my-plugin', skill: 'review' })?.text // '$my-plugin:review'
176
+ skillInvocation('gemini-cli', { plugin: 'my-plugin', skill: 'review' }) // undefined: the model loads skills itself
177
+ ```
178
+
179
+ ## Plugin dependencies
180
+
181
+ Only Claude Code's manifest declares dependencies, and only Claude Code installs the missing ones.
182
+ Every other harness ignores the field, so the plugin installs and fails later with nothing to say
183
+ why. This reads what a plugin declares, checks it against what the running harness has installed and
184
+ enabled, and returns the steps that settle the rest. It installs nothing and compares no versions.
185
+
186
+ ```ts
187
+ import { checkPluginDependencies, supportsPluginDependencies } from 'cyber-agentkit'
188
+
189
+ supportsPluginDependencies('claude-code') // true; false for the others
190
+
191
+ const check = await checkPluginDependencies('codex', { pluginRoot })
192
+ // {
193
+ // harness: 'codex',
194
+ // supported: false,
195
+ // autoResolved: false,
196
+ // dependencies: [{ name: 'my-dep', marketplace: 'my-marketplace', state: 'missing' }],
197
+ // steps: ['…'],
198
+ // research: ['E-DEP-2', …],
199
+ // }
200
+ ```
201
+
202
+ `state` is `enabled`, `installed` (no explicit setting), `disabled`, `missing`, or `unknown` (the
203
+ harness keeps no readable install record). A dependency with no marketplace resolves only in the
204
+ declaring plugin's own marketplace, as Claude Code does, and is `unknown` when that marketplace
205
+ cannot be found.
206
+
207
+ `readPluginDependencies(pluginRoot)` reads the list from `extensions["io.github.cyber-uni.plugin-manager"]`
208
+ (or the older `extensions["org.cyberuni.universal-plugin"]`) in the root `plugin.json`, then from
209
+ `.claude-plugin/plugin.json`. `declaredPluginDependencies(manifest)` parses a manifest you already
210
+ hold. The how-to for a person or agent, `plugin-dependencies`, ships as a
211
+ [reference](#reference-documents).
212
+
213
+ ## Skill directories
214
+
215
+ ```ts
216
+ import { skillsDirectories } from 'cyber-agentkit'
217
+
218
+ skillsDirectories('claude-code') // { project: ['.claude/skills'], user: ['.claude/skills'], research: ['E-CC-L1'] }
219
+ skillsDirectories('codex')?.project.includes('.agents/skills') // true
220
+ skillsDirectories('qwen-code') // undefined: not confirmed
221
+ ```
222
+
223
+ Project directories are relative to the project root, user directories to the home directory. Only
224
+ directories read by default are listed; admin, bundled, and plugin skills are left out.
225
+
226
+ ## Headless runs
227
+
228
+ How to run a harness on one prompt with no user present: the command, the model and permission
229
+ flags, the output formats and where token usage and cost appear in them, the transcript location,
230
+ and the documented exit codes. The library only describes the run; starting the process is up to
231
+ you.
232
+
233
+ ```ts
234
+ import { headlessCommand, headlessInvocation } from 'cyber-agentkit'
235
+
236
+ headlessCommand('claude-code', {
237
+ prompt: 'Fix the failing test',
238
+ model: 'sonnet',
239
+ permission: 'unattended',
240
+ outputFormat: 'stream-json',
241
+ })
242
+ // { executable: 'claude', args: ['-p', '--model', 'sonnet', '--permission-mode', 'bypassPermissions',
243
+ // '--output-format', 'stream-json', '--verbose', 'Fix the failing test'] }
244
+
245
+ const codex = headlessInvocation('codex')
246
+ // codex.outputFormats[1]: { name: 'jsonl', args: ['--json'],
247
+ // usage: { event: 'turn.completed', tokens: 'usage', accumulate: 'sum' } } (no dollar cost)
248
+
249
+ headlessInvocation('vscode-copilot').supported // false: no headless mode
250
+ headlessInvocation('opencode').supported // 'unknown': a one-shot mode exists, but its flags are not verified
251
+ ```
252
+
253
+ Claude Code, Codex, Copilot CLI, Cursor, Gemini CLI, and Qwen Code are covered. `permission:
254
+ 'unattended'` lets the run edit files and run commands without asking, so use it only in a
255
+ throwaway checkout. Exit codes are a weak signal: Claude Code documents only zero and non-zero, and
256
+ a run stopped by a turn or budget cap is told apart by the `result` message's `subtype`.
257
+
258
+ ## Reference documents
259
+
260
+ A reference is a named Markdown document an agent reads on demand, such as a checklist or a set of
261
+ weights a skill applies. A plugin ships a contribution, a skill ships its default at
262
+ `<skill>/references/<name>.default.md`, and anyone can add their own without editing the plugin: a
263
+ project in `.agents/references/<name>.md`, a person in `~/.agents/references/<name>.md`.
264
+
265
+ ```ts
266
+ import { loadReference } from 'cyber-agentkit'
267
+
268
+ const resolved = await loadReference('agent-readiness-weights', {
269
+ root: process.cwd(),
270
+ // The plugin calling the resolver: its own `references/` is the first plugin layer.
271
+ plugin: { name: 'my-plugin', root: pluginRoot },
272
+ // The skill loading the name: its `references/<name>.default.md` joins as the default tier.
273
+ defaultSkill: skillFolder,
274
+ })
275
+ if (resolved.status === 'found') console.log(resolved.content)
276
+ ```
277
+
278
+ `status` is `found`, `missing`, `ambiguous` (nothing orders the plugins holding the name; pick one
279
+ of `resolved.options`, such as `my-plugin/agent-readiness-weights`, or settle it with
280
+ `reference select`), or `invalid` (not a reference name). A name not found also has a `code`, such
281
+ as `reference-missing`. A library function never throws for a bad name. `warnings` holds each fault
282
+ as `{ code, message }`, and `trace` says how the document was built.
283
+
284
+ The tiers, highest first:
285
+
286
+ | Tier | Folders |
287
+ | --- | --- |
288
+ | managed | a `references/` beside each detected harness's managed-policy files |
289
+ | project | `.agents/references/` in the root and each folder above it, up to the repository root |
290
+ | user | `~/.agents/references/` |
291
+ | plugin | the calling plugin's `references/`, each plugin the harness has enabled, then each declared dependency that has a plugin manifest, named by that manifest |
292
+ | default | `<skill folder>/references/<name>.default.md` of the skill loading the name |
293
+
294
+ In each folder, only `<name>.md` and `<name>/README.md` answer a name, in that order.
295
+
296
+ Contributions apply bottom first: the plugins and the default, in the order `extends` gives them,
297
+ then user, project, and managed. Each applies over what is below it with its frontmatter `merge`:
298
+
299
+ - `patch` (the default): its sections replace the text they match by heading path, and the rest is
300
+ kept.
301
+ - `combine`: its sections' text is added after the text they match, lower first; where combined text
302
+ conflicts, the later text wins.
303
+ - `replace`: it replaces everything below.
304
+ - `remove`: it drops everything below.
305
+
306
+ A `<!-- merge: <operation> -->` marker under a heading applies an operation to that section alone.
307
+ Frontmatter `extends` lists what a contribution builds on, bottom first: plugins by their manifest
308
+ name, and `default`. The highest `extends` written in the managed, project, or user tier builds the
309
+ stack; without one, the plugins' own `extends` order them. `resolved.metadata` holds the composed
310
+ frontmatter, the higher contribution winning each key, without `merge` and `extends`. Frontmatter
311
+ that is not a YAML mapping is ignored with a warning.
312
+
313
+ | Function | Does |
314
+ | --- | --- |
315
+ | `loadReference(name, options)` | Resolves one name for a root, with every tier read |
316
+ | `referenceLayers(options)` | Builds the ordered layers, and finds the skills holding a default, to resolve several names against |
317
+ | `resolveReference(name, layers)` | Resolves a name against layers |
318
+ | `listReferences(layers)`, `referenceNames(layers)` | Every name the layers hold, one row each, and a row per layer holding it |
319
+ | `listReferences(layers, { pattern })` | Every reference by exact name pattern |
320
+ | `searchReferences(query, layers)` | Names matching a query by name, description, heading, or body |
321
+ | `whereReference(name, layers, options)` | The project and user files a customization is written to, and the heading paths below each |
322
+ | `projectReferencesDir()`, `userReferencesDir()`, `defaultLayer()` | Single folders and layers |
323
+ | `declaredDependencies()`, `packageDir()`, `pluginManifestName()` | A manifest's declared packages, where each is installed, and a plugin's manifest name |
324
+ | `harnessSkillFolders()`, `pluginSkillFolders()`, `skillsIn()` | The skill folders a harness reads, and the skills in them, known by their `SKILL.md` name |
325
+ | `referenceImplementations(id, layers)` | The implementations of an interface a consumer can load, and those left out with why |
326
+ | `checkReferences(layers, options)` | Checks interface documents and their implementations, each as `show` composes it |
327
+
328
+ ### The reference command
329
+
330
+ The package ships a `reference` command with `show`, `list`, `search`, `where`, `implementations`,
331
+ `check`, `create`, `select`, and `delete` subcommands:
332
+
333
+ ```sh
334
+ npx -y cyber-agentkit reference show <name>... --root <repository root> --default <skill folder>
335
+ npx -y cyber-agentkit reference list
336
+ npx -y cyber-agentkit reference list 'project-tracker.capabilities.*'
337
+ npx -y cyber-agentkit reference implementations <interface id> --accept 1,2
338
+ npx -y cyber-agentkit reference check
339
+ npx -y cyber-agentkit reference create <name> --merge combine
340
+ npx -y cyber-agentkit reference select <name> <plugin> --scope user
341
+ npx -y cyber-agentkit reference delete <name> --scope project --dry-run
342
+ ```
343
+
344
+ `implementations` lists what a consumer can load for an interface (a `<id>.interface` document) with
345
+ each one's pin, description, and unsupported sections. `check` verifies interface documents and
346
+ their implementations, and exits 1 on any failure.
347
+
348
+ `create`, `select`, and `delete` act on `.agents/references/` (the project, the default) or
349
+ `~/.agents/references/` (`--scope user`). `create` and `delete` also take `--plugin <plugin folder>`
350
+ or `--default <skill folder>` for a plugin's or a skill's source in the repository. `delete` reports
351
+ what answers the name afterwards, and never deletes a managed contribution or an installed copy.
352
+ `select` writes the `extends` that picks what a name builds on, and `--clear` removes it.
353
+
354
+ Output is [TOON](https://github.com/toon-format/toon) by default, for an agent to parse; pass
355
+ `--format json` or `--format text` (`show`, `create`, `select`, and `delete` default to `text`).
356
+ Each command prints only the fields that answer it; on `show`, `--metadata` adds the status and the
357
+ composed frontmatter, and `--trace` adds how the document was built. Every warning carries a stable
358
+ `code`. The formats
359
+ follow [`clibuilder`](https://www.npmjs.com/package/clibuilder) 12, and any other value is a
360
+ usage error (exit code 2). A CLI built on clibuilder 12
361
+ can host the same command under its own plugin name, imported from the `./commands` subpath. `--format`
362
+ is the host's global option, so the host's `cli({ format })` sets the default for every subcommand;
363
+ the `text` default of `show`, `create`, `select`, and `delete` belongs to the `cyber-agentkit` CLI:
364
+
365
+ ```ts
366
+ import { createReferenceCommand } from 'cyber-agentkit/commands'
367
+
368
+ app.command(createReferenceCommand({ plugin: { name: 'my-plugin', root: pluginRoot } }))
369
+ ```
370
+
371
+ ### The `reference` skill
372
+
373
+ The package is also an agent plugin, `cyber-agentkit`, that ships a `reference` skill. Type
374
+ `/reference` (`/cyber-agentkit:reference` in Claude Code) to load, create, update, delete, find, or
375
+ inspect a reference, or to wire a skill to load one. The skill writes or deletes a file only after
376
+ you approve it. It runs the command from its bundled `scripts/reference.mjs`, which needs no
377
+ `node_modules`.
378
+
379
+ ```text
380
+ /plugin marketplace add cyber-uni/marketplace
381
+ /plugin install cyber-agentkit@cyber-uni
382
+ ```
383
+
384
+ A skill that needs a reference names it in one line, as the skill's
385
+ [`README.md`](https://github.com/cyber-uni/cyber-agentkit/blob/main/packages/cyber-agentkit/skills/reference/README.md)
386
+ shows:
387
+
388
+ ```text
389
+ Load `skill-design` with the `reference` skill of `cyber-agentkit`.
390
+ ```
391
+
392
+ ## Worktrees
393
+
394
+ The `./worktrees` subpath leases git worktrees to concurrent agent sessions, so two agents never
395
+ share a checkout. It does not fetch and never kills a process.
396
+
397
+ ```ts
398
+ import { acquire, pruneWorktrees, release } from 'cyber-agentkit/worktrees'
399
+ ```
400
+
401
+ | Function | Does |
402
+ | --- | --- |
403
+ | `acquire(options)` | Leases a worktree: recycles an idle one of its own, else creates one at the next free slot under `max` |
404
+ | `explain(options)` | Every worktree of the repository with the reason it cannot be reused, or none |
405
+ | `release()`, `claimLease()`, `holdsLease()` | The lease a holder takes on a worktree |
406
+ | `pruneWorktrees(options)` | Removes unleased, idle, clean, landed worktrees it owns. A dry run unless `apply` is set |
407
+ | `removeWorktree(options)` | Removes the one worktree you name, under the same safety checks |
408
+ | `seedWorktree(options)` | Copies the gitignored files a `.worktreeinclude` names into a new or recycled worktree |
409
+ | `listWorktrees()`, `occupants()`, `classifyOwner()` | The worktrees of a repository, the sessions working in each, and who owns each |
410
+
411
+ A worktree is skipped, with the reason in its verdict, when it is the primary checkout, owned by
412
+ another tool or person, leased, prunable, busy, dirty, or not yet landed on the default branch. The
413
+ checks fail closed: when git or the process probe cannot say, the worktree is left alone.
414
+
415
+ ## Why this exists
416
+
417
+ `universal-plugin`, `buddy-agent-harness`, `repobuddy`, and `cyberlegion/cyber-mux` each need to know
418
+ which agent harness they are running under, and each was re-implementing that detection separately.
419
+ This package exists so they share one implementation instead.
420
+
421
+ ## License
422
+
423
+ [MIT](https://github.com/cyber-uni/cyber-agentkit/blob/main/LICENSE)
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: How to install the plugins another plugin depends on, for Claude Code and for every harness that has no dependency field.
3
+ tags: [plugin, dependencies, install]
4
+ ---
5
+
6
+ ## What a plugin declares
7
+
8
+ Only Claude Code's manifest declares dependencies: a `dependencies` array in `.claude-plugin/plugin.json` whose entries are `"name"`, `"name@marketplace"`, or `{ "name", "marketplace", "version" }` (E-DEP-1). A bare name resolves in the declaring plugin's own marketplace. A plugin can author the same list once in its root `plugin.json`, at `extensions["io.github.cyber-uni.plugin-manager"].dependencies` or, in plugins built before that key, `extensions["org.cyberuni.universal-plugin"].dependencies` (E-DEP-6 to E-DEP-8). Read it from there first, then from `.claude-plugin/plugin.json`, whichever harness you run on.
9
+
10
+ ## Check what is missing
11
+
12
+ Run the library's `checkPluginDependencies(harness, { pluginRoot })`. It reports each dependency as `enabled`, `installed` (no explicit setting), `disabled`, `missing`, or `unknown` (the harness keeps no readable install record), and returns the steps below that apply. It installs nothing.
13
+
14
+ ## Claude Code
15
+
16
+ Claude Code resolves dependencies itself. `claude plugin install`, `/reload-plugins`, auto-update, and `marketplace add` install the missing ones, and a plugin whose dependency is missing or disabled does not load (E-DEP-2).
17
+
18
+ 1. For a missing dependency, run `claude plugin install <name>@<marketplace>`.
19
+ 2. For a disabled dependency, set its `<name>@<marketplace>` key to `true` in `enabledPlugins`.
20
+ 3. Run `/reload-plugins`.
21
+
22
+ A dependency in another marketplace is not installed unless the root marketplace lists it in `allowCrossMarketplaceDependenciesOn`, or you already have it enabled. Without that, the install completes and the plugin then fails to load (E-DEP-3).
23
+
24
+ ## Every other harness
25
+
26
+ `cursor`, `codex`, `copilot-cli`, `opencode`, `kilo`, `gemini-cli`, `qwen-code`, `vscode-copilot`, `cline`, `crush`, `openhands`, `augment` have no dependency field (E-DEP-4, E-DEP-5, E-CC-X1). Nothing is resolved for you, and no install command is given because none has been verified.
27
+
28
+ 1. Read the dependencies as above.
29
+ 2. Tell the user which marketplace each one needs. You cannot tell whether the harness has that marketplace added, so ask the user to check, and to add it if it is not.
30
+ 3. Install each one through the harness's own plugin install flow, from its marketplace when one is named.
31
+ 4. Enable each one.
@@ -0,0 +1,63 @@
1
+ # Reference
2
+
3
+ Loads, creates, updates, selects, deletes, and finds [references](https://cyber-uni.github.io/cyber-agentkit/concepts/reference-documents/): Markdown documents an agent reads on demand by name. It routes each request to the `reference` command, run from a launcher bundled in `scripts/`, and writes or deletes a reference only after the user approves it. Type `/reference` to run it yourself. Installed as a Claude Code plugin, it is `/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`). Installed with pnpm, it is `pnpm-cyber-agentkit-reference`.
4
+
5
+ | Mode | When |
6
+ | --- | --- |
7
+ | Load | a skill's instructions name references, or an interface whose implementations, to load with this skill |
8
+ | Create | writing a new reference for a project, a user, a plugin (`<plugin name>.<reference>.md`), or a skill's default (`<name>.default.md`); an implementation of an interface is `<id>.<key>.md` |
9
+ | Update | changing a reference: the user's own in place, a plugin's by a customization that patches it |
10
+ | Select | choosing which plugins, or the skill's default, a name builds on, which settles an ambiguous name |
11
+ | Delete | removing a project or user contribution, saying first what answers the name afterwards |
12
+ | Find | `search` for a topic, `list` every reference, or `implementations` of an interface |
13
+ | Inspect | `show`; `show --trace` for how a name composed; `where` for the project and user files a customization goes to; `check` against an interface |
14
+ | Wire a skill | giving a skill the line below |
15
+
16
+ It ships in the `cyber-agentkit` plugin:
17
+
18
+ ```text
19
+ /plugin marketplace add cyber-uni/marketplace
20
+ /plugin install cyber-agentkit@cyber-uni
21
+ ```
22
+
23
+ ## Loading a reference from a skill
24
+
25
+ A calling skill names the references it needs in one line:
26
+
27
+ ```text
28
+ Load `skill-design` and `agent-tool-output` with the `reference` skill of `cyber-agentkit`.
29
+ ```
30
+
31
+ Name the package as well as the skill: an agent that does not have the skill can then tell the user what to install. Write the skill's name in words, as above. Every harness reads the words, but each types the skill differently, and where the typed form does not name the plugin, two plugins' skills of the same name collide.
32
+
33
+ A skill written for one harness only may add that harness's typed form after the skill's name, for example "with the `reference` skill (`/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`)) of `cyber-agentkit`" in Claude Code. Each harness names it this way:
34
+
35
+ <!-- generated: harness invocations -->
36
+ | Harness | Typed form | Names the plugin |
37
+ | --- | --- | --- |
38
+ | `claude-code` | `/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`) | yes |
39
+ | `cursor` | `/reference` | no |
40
+ | `codex` | `$cyber-agentkit:reference` | yes |
41
+ | `copilot-cli` | `/reference` | no |
42
+ | `opencode` | `/reference` | no |
43
+ | `kilo` | `/reference` | no |
44
+ | `gemini-cli` | no typed form recorded | — |
45
+ | `qwen-code` | no typed form recorded | — |
46
+ | `vscode-copilot` | `/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`) | yes |
47
+ | `cline` | `/reference` | no |
48
+ | `crush` | no typed form recorded | — |
49
+ | `openhands` | no typed form recorded | — |
50
+ | `augment` | no typed form recorded | — |
51
+ <!-- /generated -->
52
+
53
+ A skill that consumes an [interface](https://cyber-uni.github.io/cyber-agentkit/concepts/reference-interfaces/) names the interface instead:
54
+
55
+ ```text
56
+ Load the implementations of the `scaffold.recipe` interface with the `reference` skill of `cyber-agentkit`.
57
+ ```
58
+
59
+ The skill runs `implementations <id>` and hands back each implementation's pin, which the calling skill loads by name.
60
+
61
+ A calling skill may ship its own default of a reference at `references/<name>.default.md`. Loading passes the calling skill's folder as `--default`, so the default sits below every plugin, user, project, and managed contribution, and anyone can customize it. The skill reads the default by itself only when the command cannot run. A copy at `references/<name>.md`, the old layout, is not read as a default.
62
+
63
+ `scripts/reference.mjs` is the package's `reference` command bundled into this folder. It ships through the npm package and runs with no `node_modules`. Loading never falls back to `npx` or the network; the other modes fall back to `pnpm exec cyber-agentkit`, or to `npx` pinned to this release's exact version, when the launcher is missing.