agent-skillboard 0.2.15 → 0.2.16

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/docs/routing.md CHANGED
@@ -3,6 +3,12 @@
3
3
  Capability routing helps an AI choose a skill for the user's current request
4
4
  without making the user learn SkillBoard commands.
5
5
 
6
+ SkillBoard is intentionally permissive at this layer: workflow-bound skills can
7
+ remain broadly available, and routing only chooses the skill that should steer
8
+ this request. When several allowed skills match, the response includes
9
+ `overlap_resolution` so the AI can explain that the other skills stayed
10
+ available while the workflow routed to one selected skill.
11
+
6
12
  For the normal AI-mediated flow, prefer `brief --intent`. It returns the
7
13
  availability brief and the routing result together:
8
14
 
@@ -25,6 +31,8 @@ Read `assistant_guidance.route` from the JSON output. It includes:
25
31
  - `recommended_skill`
26
32
  - `fallback_skills`
27
33
  - `route_candidates`
34
+ - `overlap_resolution`
35
+ - `policy_memory`
28
36
  - `post_use_policy_suggestion`
29
37
  - `guard_command`
30
38
  - `usage_disclosure`
@@ -42,6 +50,13 @@ When several skills match, inspect `route_candidates` before acting. Each entry
42
50
  shows the candidate skill, whether it was selected, whether the guard currently
43
51
  allows it, and the guard reason when it is denied. This is the field that tells
44
52
  an AI why a preferred skill was skipped and an allowed fallback was selected.
53
+ Inspect `overlap_resolution` first when it is present: `status: resolved` with
54
+ `mode: permissive-routing` means multiple allowed skills matched, SkillBoard
55
+ kept them available, and the current workflow still has one deterministic route.
56
+ When `policy_memory` is present, remembered or configured workflow policy
57
+ selected the routed skill while other allowed skills were also available. The AI
58
+ should mention that after completion so the user knows a stored policy
59
+ preference shaped the route.
45
60
 
46
61
  When routing is safe but policy learning would reduce future ambiguity,
47
62
  SkillBoard may return `post_use_policy_suggestion`. This includes cases where a
package/docs/user-flow.md CHANGED
@@ -1,19 +1,25 @@
1
1
  # First-Time Skill Control Flow
2
2
 
3
- This flow assumes a user installed SkillBoard because they want to ask their AI
4
- which skills are safe to use and approve changes without learning the control
5
- plane internals.
6
-
7
- When you ask your AI "what skills can you use here?" or "make this reviewed
8
- skill available for this workflow," the AI should read the current brief, show
9
- the relevant choice, ask only before applying one current action id when policy
3
+ This flow assumes a user installed SkillBoard so their AI can keep installed
4
+ skills broadly available while resolving confusing overlap only when it matters.
5
+
6
+ When you ask your AI normal work requests such as "write tests before
7
+ implementation", "review this plan and point out weak assumptions", or "help me
8
+ refine this UX flow," the AI should work normally. SkillBoard becomes relevant
9
+ when skill choice is ambiguous, several skills overlap, workflow priority
10
+ matters, or you explicitly ask for a SkillBoard or skill decision such as "what
11
+ skills can you use here?" or "make this reviewed skill available for this
12
+ workflow." In those cases, the AI should read the current brief, show the
13
+ relevant choice, ask only before applying one current action id when policy
10
14
  would change, and run the final guard automatically before invocation. For an
11
15
  already-allowed skill, the AI should state which skill it is about to use and
12
16
  which skill it used when reporting the result, not ask for another approval.
13
- That disclosure is an audit trace, not a permission prompt. You do not need to
14
- memorize the SkillBoard command loop. The command examples below are
15
- AI/automation/operator details for the agent, scripts, or people maintaining the
16
- setup.
17
+ That disclosure is an audit trace, not a permission prompt. If you explicitly
18
+ ask for a specific already-allowed skill, the AI should honor that request after
19
+ guard use instead of rerouting away solely because another skill also matches.
20
+ You do not need to memorize the SkillBoard command loop. The command examples
21
+ below are AI/automation/operator details for the agent, scripts, or people
22
+ maintaining the setup.
17
23
 
18
24
  If you ask OpenCode to use a skill you previously used in Codex, the target
19
25
  agent should call:
@@ -73,8 +79,9 @@ returned post-apply brief before making the next availability claim.
73
79
  `apply-action` re-resolves the current brief and refuses stale action ids instead
74
80
  of replaying cached action-card shell text.
75
81
 
76
- When the user asks which skill fits a task, the agent can keep the same brief
77
- flow and include the user request as intent:
82
+ When a normal request leaves skill choice ambiguous, several skills overlap,
83
+ workflow priority matters, or the user asks for a SkillBoard or skill decision,
84
+ the agent can keep the same brief flow and include the user request as intent:
78
85
 
79
86
  ```bash
80
87
  skillboard brief --intent "write tests before implementation" --workflow daily-workflow --config skillboard.config.yaml --skills skills --json
@@ -83,20 +90,29 @@ skillboard brief --intent "write tests before implementation" --workflow daily-w
83
90
  The returned `assistant_guidance.route` maps the request to a declared workflow
84
91
  capability or a workflow-bound skill metadata match, returns the recommended
85
92
  skill and fallbacks, and includes `match_source`, `matched_terms`,
86
- `recommendation_reason`, `route_candidates`, `post_use_policy_suggestion`, and the
87
- `skillboard guard use ...` command that still needs to pass immediately before
88
- invocation. `route_candidates` is the per-skill decision trace: it shows which
89
- matching skill was selected, which candidates were denied, and the guard reason
90
- when a preferred skill was skipped for an allowed fallback.
93
+ `recommendation_reason`, `route_candidates`, `overlap_resolution`,
94
+ `policy_memory`,
95
+ `post_use_policy_suggestion`, and the `skillboard guard use ...` command that
96
+ still needs to pass immediately before invocation. `overlap_resolution`
97
+ summarizes permissive routing when several allowed skills match.
98
+ `route_candidates` is the per-skill decision trace: it shows which matching
99
+ skill was selected, which candidates were denied, and the guard reason when a
100
+ preferred skill was skipped for an allowed fallback.
101
+ `policy_memory` appears when remembered or configured workflow policy selected
102
+ the routed skill while other allowed skills were also available; the agent
103
+ should mention that after completion so the user understands the prior choice
104
+ shaped the route.
91
105
  `post_use_policy_suggestion` is the ask-after-use hook: if it is present, the
92
106
  agent should use the allowed routed skill first, then ask after completion
93
107
  whether to remember the suggested preference. Metadata matching can
94
108
  use declared skill id, path, category, and `SKILL.md` frontmatter
95
109
  name/description; it does not semantically rank raw skill bodies. If a
96
110
  recommended skill is already allowed, the agent should disclose it at the start
97
- and completion rather than ask for another approval. If no capability or
98
- workflow-bound skill matches, the agent should ask a clarifying question instead
99
- of guessing from raw `SKILL.md` text. Operators can still call
111
+ and completion rather than ask for another approval. If the user explicitly
112
+ requests a specific already-allowed skill, the agent should honor that request
113
+ after guard use instead of rerouting away solely because another skill also
114
+ matches. If no capability or workflow-bound skill matches, the agent should ask
115
+ a clarifying question instead of guessing from raw `SKILL.md` text. Operators can still call
100
116
  `skillboard route ...` directly when they only need the recommendation payload.
101
117
 
102
118
  Run this again after installing agent packages, plugins, workflow bundles, or
@@ -279,26 +295,39 @@ This removes SkillBoard policy references only and leaves
279
295
 
280
296
  AI/automation/operator details:
281
297
 
298
+ Remove managed user-agent guidance first if global install/setup made agents
299
+ recognize SkillBoard and you want that agent-layer footprint gone:
300
+
301
+ ```bash
302
+ skillboard uninstall --agent-layer --dry-run
303
+ skillboard uninstall --agent-layer
304
+ ```
305
+
306
+ This removes only managed `skillboard/SKILL.md` guidance files containing the
307
+ SkillBoard agent integration marker. It preserves other agent skills and
308
+ user-authored `skillboard` skills.
309
+
282
310
  ```bash
283
311
  skillboard uninstall --dry-run
284
312
  skillboard uninstall
285
313
  ```
286
314
 
287
315
  Uninstall removes generated bridge blocks and unchanged helper files. It
288
- preserves `skillboard.config.yaml`, `skills/`, reports, and user-authored
316
+ also removes `skillboard.config.yaml` and the `.skillboard/` project state by
317
+ default while preserving local `skills/` files and user-authored non-SkillBoard
289
318
  content in bridge files.
290
319
 
291
- For a fresh policy lifecycle during testing, use:
320
+ If you want to keep project SkillBoard policy and bridge guidance, opt into
321
+ settings preservation explicitly:
292
322
 
293
323
  ```bash
294
- skillboard uninstall --purge --dry-run
295
- skillboard uninstall --purge
296
- skillboard init
324
+ skillboard uninstall --keep-settings --dry-run
325
+ skillboard uninstall --keep-settings
297
326
  ```
298
327
 
299
- Use `--purge` when you want SkillBoard's allow/block/preference influence gone
300
- from the project while keeping local skill files. It discards the current
301
- SkillBoard config even if it contains imported skills or workflow edits,
302
- removes generated dashboard and impact reports, and removes the entire
303
- `.skillboard/` project state directory, including hooks, source caches, rollout
304
- logs, variant snapshots, and profiles. Local `skills/` files stay in place.
328
+ `--purge` is still accepted as an explicit spelling for the default clean
329
+ project removal. Default removal and `--purge` both discard the current
330
+ SkillBoard config even if it contains imported skills or workflow edits, remove
331
+ generated dashboard and impact reports, and remove the entire `.skillboard/`
332
+ project state directory, including hooks, source caches, rollout logs, variant
333
+ snapshots, and profiles. Local `skills/` files stay in place.
@@ -17,9 +17,9 @@ surfaces a user or agent would use.
17
17
  The raw list answers inventory questions: which skill declarations are connected
18
18
  to this workflow?
19
19
 
20
- SkillBoard answers operational safety questions: which skills can actually run
21
- now, why are others blocked, which skill fits the user's current request, and
22
- what approved action changes the next state?
20
+ SkillBoard answers routing questions: which skills can actually run now, why
21
+ are others blocked, which skill should steer the user's current request when
22
+ several skills overlap, and what approved action changes the next state?
23
23
 
24
24
  In the tested fixture, the raw list can make the workflow look ready because it
25
25
  shows `matt.tdd active workflow-auto`. SkillBoard refuses that unsafe claim and
@@ -171,6 +171,9 @@ Observed route result:
171
171
  - Confidence: `high`.
172
172
  - Recommended skill: `matt.tdd`.
173
173
  - Fallback skill: `private.tdd-work-continuity`.
174
+ - Overlap resolution is exposed in route payloads when several allowed skills
175
+ match, so agents can explain the deterministic route without hiding the other
176
+ available skills.
174
177
  - Guard command: `skillboard guard use matt.tdd ...`.
175
178
  - Guard result for `matt.tdd`: allowed.
176
179
  - Start disclosure: `I will use matt.tdd for this request.`
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "agent-skillboard",
3
- "version": "0.2.15",
4
- "description": "Let AI agents pick and use allowed skills in each workflow.",
3
+ "version": "0.2.16",
4
+ "description": "Keep agent skills broadly available while routing overlaps consistently.",
5
5
  "keywords": [
6
6
  "ai-agent",
7
7
  "agent-skills",
8
8
  "skills",
9
9
  "skill-routing",
10
+ "overlap-routing",
10
11
  "workflow",
11
12
  "codex",
12
13
  "claude-code",
@@ -3,7 +3,16 @@ import { command } from "./action-core.mjs";
3
3
  const GUARD_WHEN = "before invoking a skill";
4
4
  const GOAL_DOCUMENT = Object.freeze({
5
5
  path: "docs/ai-skill-routing-goal.md",
6
- purpose: "Preserve SkillBoard as a non-blocking AI skill routing control plane: route and work first when safe, explain briefly, ask after use when policy learning helps, and remember usage policy without rewriting skill bodies.",
6
+ purpose: "Preserve SkillBoard as a permissive AI skill routing layer: keep skills broadly available, resolve overlaps deterministically, explain briefly, ask after use when policy learning helps, and remember usage policy without rewriting skill bodies.",
7
+ loop: Object.freeze([
8
+ "observe",
9
+ "route",
10
+ "work",
11
+ "explain briefly",
12
+ "ask after",
13
+ "remember policy"
14
+ ]),
15
+ simplification_rule: "Concepts must justify themselves by supporting SkillBoard's routing identity, overlap resolution, policy memory, or non-blocking user flow; remove, merge, or rename only the concepts that fail that test.",
7
16
  when_to_read: Object.freeze([
8
17
  "before changing routing",
9
18
  "before changing brief output",
@@ -47,6 +56,7 @@ export function buildAssistantGuidance(brief, options = {}) {
47
56
  function goalDocument() {
48
57
  return {
49
58
  ...GOAL_DOCUMENT,
59
+ loop: [...GOAL_DOCUMENT.loop],
50
60
  when_to_read: [...GOAL_DOCUMENT.when_to_read]
51
61
  };
52
62
  }
@@ -125,12 +135,14 @@ function recommendedNextStep(status, brief, choices, route = null) {
125
135
  if (route !== null) {
126
136
  return route.recommended_skill === null
127
137
  ? "Ask a clarifying question; no workflow capability matched this request."
128
- : `Use ${route.recommended_skill} for this request after the guard check passes.`;
138
+ : `Use ${route.recommended_skill} for this request after the guard check passes${postUsePolicyStep(route)}.`;
129
139
  }
130
140
  return "Run the guard check before invoking any selected skill.";
131
141
  case "needs-decision":
132
142
  if (route?.recommended_skill !== null && route?.guard_allowed === true) {
133
- return `Use ${route.recommended_skill} for this request after the guard check passes; handle pending review decisions after the task unless a policy-changing action is needed now.`;
143
+ return route.post_use_policy_suggestion === null
144
+ ? `Use ${route.recommended_skill} for this request after the guard check passes; handle pending review decisions after the task unless a policy-changing action is needed now.`
145
+ : `Use ${route.recommended_skill} for this request after the guard check passes; after completion, ask whether to remember the suggested policy and handle pending review decisions unless a policy-changing action is needed now.`;
134
146
  }
135
147
  return firstChoice === undefined
136
148
  ? "Ask the user which pending review decision to make."
@@ -159,6 +171,12 @@ function recommendedNextStep(status, brief, choices, route = null) {
159
171
  }
160
172
  }
161
173
 
174
+ function postUsePolicyStep(route) {
175
+ return route.post_use_policy_suggestion === null
176
+ ? ""
177
+ : "; after completion, ask whether to remember the suggested policy";
178
+ }
179
+
162
180
  function routeGuidance(route) {
163
181
  return {
164
182
  intent: route.intent,
@@ -180,6 +198,8 @@ function routeGuidance(route) {
180
198
  guard_roles: candidate.guard_roles,
181
199
  capability_roles: candidate.capability_roles
182
200
  })),
201
+ overlap_resolution: route.overlap_resolution ?? null,
202
+ policy_memory: route.policy_memory ?? null,
183
203
  usage_disclosure: route.usage_disclosure ?? null,
184
204
  post_use_policy_suggestion: route.post_use_policy_suggestion ?? null,
185
205
  guard_command: route.guard_command,
@@ -0,0 +1,184 @@
1
+ import { isAbsolute, relative, resolve } from "node:path";
2
+ import { createInterface } from "node:readline";
3
+ import { installAgentIntegration, uninstallAgentIntegration } from "./agent-integration-files.mjs";
4
+ import { resolveSetupHome, setupOwnership } from "./agent-integration-home.mjs";
5
+ import { setupAgentSkillTargets, supportedAgentNames } from "./agent-skill-roots.mjs";
6
+
7
+ export async function runSetupCommand(options, stdout, runtime = defaultRuntime()) {
8
+ if (options.get("dir") !== undefined) {
9
+ throw new Error("skillboard setup is agent-layer setup and does not accept --dir");
10
+ }
11
+ const env = runtime.env ?? process.env;
12
+ const home = await resolveSetupHome(env, runtime);
13
+ const targets = await agentSetupTargets(options, runtime, home);
14
+ if (targets.length === 0) {
15
+ stdout.write("No supported agent user skill roots were detected.\n");
16
+ stdout.write(`Create a supported agent home or pass --agent ${supportedAgentNames().join(",")} to choose targets.\n`);
17
+ return 1;
18
+ }
19
+ if (options.get("yes") !== "true") {
20
+ writeSetupConfirmation(stdout, targets, commandPrefix(runtime));
21
+ if (!canPrompt(runtime)) {
22
+ return 1;
23
+ }
24
+ const confirmed = await promptForSetup(runtime);
25
+ if (!confirmed) {
26
+ stdout.write("Skipped SkillBoard setup.\n");
27
+ return 1;
28
+ }
29
+ }
30
+ const result = await installAgentIntegration(targets, setupOwnership(env, runtime, home));
31
+ stdout.write("SkillBoard agent integration installed.\n");
32
+ writeList(stdout, "Created", result.created);
33
+ writeList(stdout, "Updated", result.updated);
34
+ writeList(stdout, "Unchanged", result.unchanged);
35
+ writeList(stdout, "Preserved", result.preserved);
36
+ stdout.write("Next:\n");
37
+ stdout.write("- Restart or refresh agents that cache user skills.\n");
38
+ stdout.write("- No project was initialized; run skillboard init only inside a workspace that needs local SkillBoard policy.\n");
39
+ stdout.write('- Ask the agent in a workspace: "Review this plan and point out weak assumptions."\n');
40
+ stdout.write("- SkillBoard will step in when skills overlap, routing is ambiguous, or you ask for a skill decision.\n");
41
+ return 0;
42
+ }
43
+
44
+ export async function runAgentLayerUninstallCommand(options, stdout, runtime = defaultRuntime()) {
45
+ if (options.get("dir") !== undefined) {
46
+ throw new Error("skillboard uninstall --agent-layer is agent-layer cleanup and does not accept --dir");
47
+ }
48
+ for (const option of ["remove-config", "reset-config", "purge", "keep-settings", "remove-reports", "remove-hooks"]) {
49
+ if (options.get(option) === "true") {
50
+ throw new Error(`--${option} cannot be combined with --agent-layer`);
51
+ }
52
+ }
53
+ const env = runtime.env ?? process.env;
54
+ const home = await resolveSetupHome(env, runtime);
55
+ const targets = await agentSetupTargets(options, runtime, home);
56
+ if (targets.length === 0) {
57
+ stdout.write("No supported agent user skill roots were detected.\n");
58
+ return 0;
59
+ }
60
+ const dryRun = options.get("dry-run") === "true";
61
+ const result = await uninstallAgentIntegration(targets, dryRun);
62
+ stdout.write(`${dryRun ? "Dry run: " : ""}Uninstalled SkillBoard agent integration.\n`);
63
+ writeList(stdout, "Removed", result.removed);
64
+ writeList(stdout, "Updated", result.updated);
65
+ writeList(stdout, "Preserved", result.preserved);
66
+ writeList(stdout, "Absent", result.absent);
67
+ return 0;
68
+ }
69
+
70
+ function writeList(stdout, label, values) {
71
+ if (values.length > 0) {
72
+ stdout.write(`${label}: ${formatList(values)}\n`);
73
+ }
74
+ }
75
+
76
+ function writeSetupConfirmation(stdout, targets, command) {
77
+ stdout.write("SkillBoard setup installs agent-layer integration, not project files.\n");
78
+ stdout.write("It writes a SkillBoard guidance skill into detected user agent skill roots so agents can resolve skill priority when choices overlap.\n");
79
+ stdout.write("It does not create skillboard.config.yaml or .skillboard/; run skillboard init later only for a project that needs local policy.\n");
80
+ stdout.write("Targets:\n");
81
+ for (const target of targets) {
82
+ stdout.write(`- ${target.agent}: ${target.skillPath}\n`);
83
+ }
84
+ stdout.write("Run with --yes to install agent-layer integration:\n");
85
+ stdout.write(`- ${command} setup --agent ${targets.map((target) => target.agent).join(",")} --yes\n`);
86
+ }
87
+
88
+ function canPrompt(runtime) {
89
+ return runtime.stdin?.isTTY === true && runtime.stdout?.isTTY === true;
90
+ }
91
+
92
+ async function promptForSetup(runtime) {
93
+ const rl = createInterface({
94
+ input: runtime.stdin,
95
+ output: runtime.stdout
96
+ });
97
+ try {
98
+ const answer = await question(rl, "Install SkillBoard agent integration now? [y/N] ");
99
+ return /^(y|yes)$/i.test(answer.trim());
100
+ } finally {
101
+ rl.close();
102
+ }
103
+ }
104
+
105
+ function question(rl, prompt) {
106
+ return new Promise((resolve) => {
107
+ rl.question(prompt, resolve);
108
+ });
109
+ }
110
+
111
+ function formatList(values) {
112
+ return values.length === 0 ? "none" : values.map((value) => `\`${value}\``).join(", ");
113
+ }
114
+
115
+ function readCsv(value) {
116
+ if (value === undefined || value.trim() === "") {
117
+ return [];
118
+ }
119
+ return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
120
+ }
121
+
122
+ function defaultRuntime() {
123
+ return {
124
+ cwd: process.cwd(),
125
+ entrypointPath: process.argv[1],
126
+ packageSpec: process.env.npm_config_package
127
+ };
128
+ }
129
+
130
+ async function agentSetupTargets(options, runtime, setupHome) {
131
+ const env = runtime.env ?? process.env;
132
+ const home = setupHome ?? await resolveSetupHome(env, runtime);
133
+ const requested = readCsv(options.get("agent"));
134
+ const supported = new Set(supportedAgentNames());
135
+ const names = requested.length === 0 ? supportedAgentNames() : requested;
136
+ const targets = [];
137
+ for (const name of names) {
138
+ if (!supported.has(name)) {
139
+ throw new Error(`Unsupported setup agent: ${name}`);
140
+ }
141
+ targets.push(...await setupAgentSkillTargets(name, home, env, { includeFallback: requested.length > 0 }));
142
+ }
143
+ return targets;
144
+ }
145
+
146
+ function commandPrefix(runtime) {
147
+ const entrypoint = runtime.entrypointPath ?? "";
148
+ const normalized = entrypoint.replace(/\\/g, "/");
149
+ if (normalized.includes("/_npx/")) {
150
+ const packageSpec = runtime.packageSpec ?? "agent-skillboard";
151
+ return `npx --yes --package ${shellQuote(packageSpec)} skillboard`;
152
+ }
153
+ if (isSourceTreeEntrypoint(entrypoint)) {
154
+ return `node ${sourceTreeEntrypoint(entrypoint, runtime.cwd ?? process.cwd())}`;
155
+ }
156
+ return "skillboard";
157
+ }
158
+
159
+ function isSourceTreeEntrypoint(entrypoint) {
160
+ if (entrypoint === "") {
161
+ return false;
162
+ }
163
+ const normalized = entrypoint.replace(/\\/g, "/");
164
+ return (normalized === "bin/skillboard.mjs" || normalized.endsWith("/bin/skillboard.mjs"))
165
+ && !normalized.includes("/node_modules/")
166
+ && !normalized.includes("/_npx/")
167
+ && !normalized.includes("/.npm/");
168
+ }
169
+
170
+ function sourceTreeEntrypoint(entrypoint, cwd) {
171
+ const absoluteEntrypoint = isAbsolute(entrypoint) ? entrypoint : resolve(cwd, entrypoint);
172
+ const relativeEntrypoint = relative(cwd, absoluteEntrypoint).replace(/\\/g, "/");
173
+ if (!relativeEntrypoint.startsWith("../") && relativeEntrypoint !== ".." && !isAbsolute(relativeEntrypoint)) {
174
+ return shellQuote(relativeEntrypoint);
175
+ }
176
+ return shellQuote(absoluteEntrypoint);
177
+ }
178
+
179
+ function shellQuote(value) {
180
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) {
181
+ return value;
182
+ }
183
+ return `'${value.replace(/'/g, "'\\''")}'`;
184
+ }
@@ -0,0 +1,48 @@
1
+ export const AGENT_INTEGRATION_START = "<!-- BEGIN SKILLBOARD AGENT INTEGRATION -->";
2
+ export const AGENT_INTEGRATION_END = "<!-- END SKILLBOARD AGENT INTEGRATION -->";
3
+
4
+ export function agentIntegrationSkill() {
5
+ return `---
6
+ name: skillboard
7
+ description: Use SkillBoard when several installed skills could apply, a skill choice is ambiguous, workflow priority matters, or the user explicitly asks which skill should be used, imported, preferred, avoided, reviewed, or prioritized.
8
+ ---
9
+ ${AGENT_INTEGRATION_START}
10
+ # SkillBoard Agent Integration
11
+
12
+ Use this skill to let SkillBoard guide skill selection above individual projects.
13
+
14
+ ## Layering
15
+
16
+ - SkillBoard is the user-level control plane for skill priority, overlap resolution, and workflow-aware routing.
17
+ - Project management belongs to the agent or workspace layer. Do not initialize, attach, rewrite, or manage a project just because SkillBoard is installed.
18
+ - Package install and \`skillboard setup\` install user-agent guidance only.
19
+ - \`skillboard init\` is a separate project command. Use it only when the user wants project-local policy files such as \`skillboard.config.yaml\`, \`.skillboard/\`, \`AGENTS.md\`, or \`CLAUDE.md\`.
20
+
21
+ ## Default Behavior
22
+
23
+ - Installed user skills are usable by default unless the runtime, user, or local instructions disable them.
24
+ - For ordinary user requests, work normally; invoke SkillBoard only when skill choice is ambiguous, skills overlap, workflow priority matters, or the user asks for a SkillBoard or skill decision.
25
+ - If the user explicitly asks for a specific installed skill, honor that request when the guard allows it instead of rerouting away solely because other skills also match.
26
+ - Do not ask for permission merely because you selected a skill.
27
+ - When you use a skill, disclose it briefly at the start and completion. If SkillBoard says remembered or configured policy selected this skill while other allowed skills were available, mention that at completion.
28
+
29
+ ## Cross-Agent Skill Reuse
30
+
31
+ - When the user wants to use a skill from another agent, run \`skillboard import-skill --from <source-agent> --to <this-agent> --skill <skill> --json\`.
32
+ - If SkillBoard reports the skill is compatible, install it with \`--yes\` and use the copied target-agent skill.
33
+ - If SkillBoard reports \`needs-adaptation\`, explain the compatibility reasons and ask before changing the skill body for this agent.
34
+ - If the user approves, inspect the source skill, write an adapted \`SKILL.md\` for this agent, then install it with \`skillboard import-skill --from <source-agent> --to <this-agent> --skill <skill> --adapted-file <adapted-skill.md> --yes --json\`.
35
+ - This is still user-agent setup. Do not create or mutate project policy files for cross-agent skill reuse.
36
+
37
+ ## Ambiguity Resolution
38
+
39
+ 1. Start from the user's task, not from a pre-task inventory prompt.
40
+ 2. Identify candidate skills only when multiple installed skills plausibly match, a manual skill-control request is present, or workflow priority could change the route.
41
+ 3. Prefer the skill whose explicit request, description, workflow guidance, and local instructions most directly match the user's task.
42
+ 4. If a project or agent has explicit SkillBoard policy, use \`skillboard brief --intent <request> --json\` or \`skillboard route <intent> --workflow <name> --json\` to break ties.
43
+ 5. If the best choice is still ambiguous or the choice would change persistent policy, ask the user which priority to remember.
44
+ 6. Continue with the selected skill; do not stop only because other candidate skills exist.
45
+
46
+ ${AGENT_INTEGRATION_END}
47
+ `;
48
+ }