agent-skillboard 0.1.2 → 0.2.2
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/CHANGELOG.md +39 -0
- package/README.md +159 -630
- package/docs/adapters.md +96 -96
- package/docs/ai-skill-routing-goal.md +112 -0
- package/docs/capabilities.md +6 -0
- package/docs/install.md +172 -114
- package/docs/policy-model.md +266 -214
- package/docs/positioning.md +94 -94
- package/docs/reference.md +349 -0
- package/docs/routing.md +85 -0
- package/docs/user-flow.md +79 -17
- package/docs/value-proof.md +194 -0
- package/docs/variant-lifecycle.md +86 -0
- package/docs/versioning.md +154 -138
- package/examples/multi-source-skills/anthropic/docx/SKILL.md +8 -8
- package/examples/multi-source-skills/anthropic/skill-creator/SKILL.md +8 -8
- package/examples/multi-source-skills/matt/grill-me/SKILL.md +8 -8
- package/examples/multi-source-skills/matt/tdd/SKILL.md +8 -8
- package/examples/multi-source-skills/omo/review-work/SKILL.md +8 -8
- package/examples/multi-source-skills/omo/ulw-plan/SKILL.md +8 -8
- package/examples/multi-source-skills/private/tdd-work-continuity/SKILL.md +8 -8
- package/examples/multi-source-skills/private/workflow-router/SKILL.md +8 -8
- package/examples/multi-source-skills/wshobson/python-testing/SKILL.md +8 -8
- package/examples/multi-source-skills/wshobson/security-review/SKILL.md +8 -8
- package/examples/skillboard.config.yaml +8 -3
- package/examples/skills/grill-me/SKILL.md +9 -9
- package/examples/skills/grill-with-docs/SKILL.md +9 -9
- package/examples/skills/requirement-intake/SKILL.md +9 -9
- package/examples/skills/tdd/SKILL.md +8 -8
- package/package.json +6 -3
- package/src/advisor/actions.mjs +25 -3
- package/src/advisor/guidance.mjs +232 -0
- package/src/advisor/schema.mjs +2 -0
- package/src/advisor/skills.mjs +2 -0
- package/src/advisor/trust-policy.mjs +5 -3
- package/src/advisor.mjs +36 -7
- package/src/brief-cli.mjs +6 -5
- package/src/brief-renderer.mjs +225 -8
- package/src/cli.mjs +574 -27
- package/src/config-helpers.mjs +34 -18
- package/src/conflicts.mjs +70 -0
- package/src/control/can-use-guard.mjs +8 -3
- package/src/control/skill-crud.mjs +142 -0
- package/src/control/skill-variants.mjs +221 -0
- package/src/control/source-trust.mjs +1 -0
- package/src/control/variant-files.mjs +265 -0
- package/src/control/variant-lifecycle-config.mjs +156 -0
- package/src/control/variant-reset.mjs +171 -0
- package/src/control/variant-status.mjs +75 -0
- package/src/control.mjs +13 -1
- package/src/domain/rules/skills.mjs +60 -0
- package/src/domain/rules/workflows.mjs +13 -0
- package/src/hook-plan.mjs +6 -6
- package/src/impact.mjs +21 -12
- package/src/index.mjs +13 -1
- package/src/lifecycle-cli.mjs +19 -8
- package/src/lifecycle-content.mjs +34 -24
- package/src/route.mjs +537 -0
- package/src/source-verification.mjs +7 -3
- package/src/workspace.mjs +141 -43
- package/tsconfig.lsp.json +1 -1
- package/docs/plans/20260625-080025-skillboard-mvp-review.md +0 -189
- package/docs/plans/README.md +0 -20
package/src/control.mjs
CHANGED
|
@@ -14,11 +14,18 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
activateSkill,
|
|
16
16
|
addSkill,
|
|
17
|
+
addSkillVariant,
|
|
17
18
|
blockSkill,
|
|
18
19
|
preferSkill,
|
|
19
20
|
quarantineSkill,
|
|
20
21
|
removeSkill
|
|
21
22
|
} from "./control/skill-crud.mjs";
|
|
23
|
+
import {
|
|
24
|
+
approveSkillVariant,
|
|
25
|
+
forkSkillVariant
|
|
26
|
+
} from "./control/skill-variants.mjs";
|
|
27
|
+
import { resetSkillVariant } from "./control/variant-reset.mjs";
|
|
28
|
+
import { variantLifecycleStatus } from "./control/variant-status.mjs";
|
|
22
29
|
import { addHarness, addWorkflow } from "./control/workflow-crud.mjs";
|
|
23
30
|
import {
|
|
24
31
|
GUARD_HOOK_MODE,
|
|
@@ -116,15 +123,20 @@ export {
|
|
|
116
123
|
activateSkill,
|
|
117
124
|
addHarness,
|
|
118
125
|
addSkill,
|
|
126
|
+
addSkillVariant,
|
|
119
127
|
addWorkflow,
|
|
128
|
+
approveSkillVariant,
|
|
120
129
|
auditSources,
|
|
121
130
|
blockSkill,
|
|
122
131
|
canUseSkill,
|
|
123
132
|
classifySkillSource,
|
|
124
133
|
classifySkillTrust,
|
|
134
|
+
forkSkillVariant,
|
|
125
135
|
preferSkill,
|
|
126
136
|
quarantineSkill,
|
|
127
|
-
removeSkill
|
|
137
|
+
removeSkill,
|
|
138
|
+
resetSkillVariant,
|
|
139
|
+
variantLifecycleStatus
|
|
128
140
|
};
|
|
129
141
|
|
|
130
142
|
export async function installGuardHook(options) {
|
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
validateSkillState
|
|
5
5
|
} from "../skill-state-matrix.mjs";
|
|
6
6
|
|
|
7
|
+
const VARIANT_STATUS_VALUES = new Set(["draft", "approved"]);
|
|
8
|
+
const VARIANT_DIGEST_PATTERN = /^sha256:[0-9a-fA-F]{64}$/;
|
|
9
|
+
const VARIANT_SNAPSHOT_PREFIX = ".skillboard/variant-snapshots/";
|
|
10
|
+
|
|
7
11
|
export const skillRules = [
|
|
8
12
|
{
|
|
9
13
|
id: "SKILL-STATUS-001",
|
|
@@ -71,6 +75,19 @@ export const skillRules = [
|
|
|
71
75
|
return diagnostics;
|
|
72
76
|
}
|
|
73
77
|
},
|
|
78
|
+
{
|
|
79
|
+
id: "SKILL-VARIANT-001",
|
|
80
|
+
check(ctx) {
|
|
81
|
+
const diagnostics = [];
|
|
82
|
+
for (const skill of ctx.skills) {
|
|
83
|
+
if (skill.variant === null || skill.variant === undefined) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
diagnostics.push(...validateVariantMetadata(ctx, skill));
|
|
87
|
+
}
|
|
88
|
+
return diagnostics;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
74
91
|
{
|
|
75
92
|
id: "SKILL-OWNER-001",
|
|
76
93
|
check(ctx) {
|
|
@@ -103,3 +120,46 @@ function validateStatusInvocation(skill) {
|
|
|
103
120
|
}
|
|
104
121
|
return diagnostics;
|
|
105
122
|
}
|
|
123
|
+
|
|
124
|
+
function validateVariantMetadata(ctx, skill) {
|
|
125
|
+
const diagnostics = [];
|
|
126
|
+
const { variant } = skill;
|
|
127
|
+
if (!ctx.skillsById.has(variant.of)) {
|
|
128
|
+
diagnostics.push(`Skill ${skill.id} variant.of references undeclared skill: ${variant.of}`);
|
|
129
|
+
}
|
|
130
|
+
if (!ctx.capabilitiesByName.has(variant.capability)) {
|
|
131
|
+
diagnostics.push(`Skill ${skill.id} variant.capability references undeclared capability: ${variant.capability}`);
|
|
132
|
+
}
|
|
133
|
+
if (!ctx.workflowsByName.has(variant.workflow)) {
|
|
134
|
+
diagnostics.push(`Skill ${skill.id} variant.workflow references undeclared workflow: ${variant.workflow}`);
|
|
135
|
+
}
|
|
136
|
+
if (!VARIANT_STATUS_VALUES.has(variant.status)) {
|
|
137
|
+
diagnostics.push(`Skill ${skill.id} variant.status must be one of: draft, approved; got ${variant.status}.`);
|
|
138
|
+
}
|
|
139
|
+
diagnostics.push(...validateVariantCheckpoint(skill, "base", variant.base));
|
|
140
|
+
if (variant.approved !== undefined) {
|
|
141
|
+
diagnostics.push(...validateVariantCheckpoint(skill, "approved", variant.approved));
|
|
142
|
+
}
|
|
143
|
+
return diagnostics;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function validateVariantCheckpoint(skill, key, checkpoint) {
|
|
147
|
+
const diagnostics = [];
|
|
148
|
+
if (!VARIANT_DIGEST_PATTERN.test(checkpoint.contentDigest)) {
|
|
149
|
+
diagnostics.push(`Skill ${skill.id} variant.${key}.content_digest must match sha256:<64 hex chars>.`);
|
|
150
|
+
}
|
|
151
|
+
if (!isVariantSnapshotPath(checkpoint.snapshot)) {
|
|
152
|
+
diagnostics.push(`Skill ${skill.id} variant.${key}.snapshot must be a relative path under ${VARIANT_SNAPSHOT_PREFIX}.`);
|
|
153
|
+
}
|
|
154
|
+
return diagnostics;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isVariantSnapshotPath(value) {
|
|
158
|
+
if (value.startsWith("/") || /^[A-Za-z]:/.test(value) || value.includes("\\")) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (!value.startsWith(VARIANT_SNAPSHOT_PREFIX) || value.length <= VARIANT_SNAPSHOT_PREFIX.length) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
165
|
+
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
NON_CALLABLE_WORKFLOW_INVOCATIONS,
|
|
4
4
|
NON_CALLABLE_WORKFLOW_STATUSES
|
|
5
5
|
} from "../constants.mjs";
|
|
6
|
+
import { workflowConflictEntries } from "../../conflicts.mjs";
|
|
6
7
|
|
|
7
8
|
export const workflowRules = [
|
|
8
9
|
{
|
|
@@ -90,6 +91,18 @@ export const workflowRules = [
|
|
|
90
91
|
}
|
|
91
92
|
return diagnostics;
|
|
92
93
|
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "WF-CONFLICT-001",
|
|
97
|
+
check(ctx) {
|
|
98
|
+
const diagnostics = [];
|
|
99
|
+
for (const workflow of ctx.workflows) {
|
|
100
|
+
for (const conflict of workflowConflictEntries(ctx.workspace, workflow)) {
|
|
101
|
+
diagnostics.push(`Workflow ${workflow.name} has active skill conflict: ${conflict.skill} conflicts_with ${conflict.conflictingSkill}.`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return diagnostics;
|
|
105
|
+
}
|
|
93
106
|
}
|
|
94
107
|
];
|
|
95
108
|
|
package/src/hook-plan.mjs
CHANGED
|
@@ -58,10 +58,10 @@ function renderGuardHookScript(options) {
|
|
|
58
58
|
return `#!/usr/bin/env sh
|
|
59
59
|
set -eu
|
|
60
60
|
|
|
61
|
-
SKILLBOARD_BIN
|
|
62
|
-
SKILLBOARD_CONFIG
|
|
63
|
-
SKILLBOARD_SKILLS
|
|
64
|
-
SKILLBOARD_WORKFLOW
|
|
61
|
+
SKILLBOARD_BIN=${shellQuote(options.command)}
|
|
62
|
+
SKILLBOARD_CONFIG=${shellQuote(options.configPath)}
|
|
63
|
+
SKILLBOARD_SKILLS=${shellQuote(options.skillsRoot)}
|
|
64
|
+
SKILLBOARD_WORKFLOW=${shellQuote(options.workflow)}
|
|
65
65
|
|
|
66
66
|
if [ "\${SKILLBOARD_SKILL_ID:-}" != "" ]; then
|
|
67
67
|
skill_id="$SKILLBOARD_SKILL_ID"
|
|
@@ -72,8 +72,8 @@ else
|
|
|
72
72
|
exit 64
|
|
73
73
|
fi
|
|
74
74
|
|
|
75
|
-
# Split
|
|
76
|
-
#
|
|
75
|
+
# Split the install-time command so hooks can use commands like:
|
|
76
|
+
# --skillboard-bin "node bin/skillboard.mjs"
|
|
77
77
|
# Paths containing spaces should be provided through an environment wrapper.
|
|
78
78
|
set -- $SKILLBOARD_BIN
|
|
79
79
|
exec "$@" guard use "$skill_id" --workflow "$SKILLBOARD_WORKFLOW" --config "$SKILLBOARD_CONFIG" --skills "$SKILLBOARD_SKILLS"
|
package/src/impact.mjs
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
|
+
activeConflictEntriesForSkill,
|
|
3
|
+
conflictingSkillIds
|
|
4
|
+
} from "./conflicts.mjs";
|
|
5
|
+
|
|
6
|
+
export function impactDisable(workspace, skillId) {
|
|
2
7
|
const affectedWorkflowEntries = workspace.workflows
|
|
3
8
|
.filter((workflow) => workflow.activeSkills.includes(skillId) || workflow.requiredCapabilities.some((capability) => {
|
|
4
9
|
return capability.preferred === skillId || capability.fallback.includes(skillId);
|
|
5
10
|
}));
|
|
6
11
|
const affectedWorkflows = affectedWorkflowEntries.map((workflow) => workflow.name);
|
|
7
12
|
const affectedOutputs = [...new Set(affectedWorkflowEntries.flatMap((workflow) => workflow.requiredOutputs))];
|
|
8
|
-
const skill = workspace.skills.find((candidate) => candidate.id === skillId);
|
|
9
|
-
const alternatives = alternativesForSkill(workspace, skillId, skill);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
const skill = workspace.skills.find((candidate) => candidate.id === skillId);
|
|
14
|
+
const alternatives = alternativesForSkill(workspace, skillId, skill);
|
|
15
|
+
const conflictingSkills = conflictingSkillIds(workspace, skillId);
|
|
16
|
+
const activeConflicts = activeConflictEntriesForSkill(workspace, skillId);
|
|
17
|
+
return {
|
|
18
|
+
skillId,
|
|
19
|
+
exists: skill !== undefined,
|
|
20
|
+
affectedWorkflows,
|
|
21
|
+
affectedOutputs,
|
|
22
|
+
alternatives,
|
|
23
|
+
conflictingSkills,
|
|
24
|
+
activeConflicts,
|
|
25
|
+
risk: riskFor(skill, affectedWorkflows, alternatives)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
19
28
|
|
|
20
29
|
function alternativesForSkill(workspace, skillId, skill) {
|
|
21
30
|
if (skill?.replacedBy !== undefined) {
|
package/src/index.mjs
CHANGED
|
@@ -15,15 +15,19 @@ import { detectInstallOutput } from "./install-output-detector.mjs";
|
|
|
15
15
|
import { rolloutApply, rolloutAudit, rolloutPlan, rolloutReport, rolloutRollback } from "./rollout.mjs";
|
|
16
16
|
import { reviewInstallUnit } from "./review.mjs";
|
|
17
17
|
import { buildSkillBrief } from "./advisor.mjs";
|
|
18
|
+
import { routeSkill } from "./route.mjs";
|
|
18
19
|
import {
|
|
19
20
|
activateSkill,
|
|
20
21
|
addHarness,
|
|
21
22
|
addSkill,
|
|
23
|
+
addSkillVariant,
|
|
22
24
|
addWorkflow,
|
|
25
|
+
approveSkillVariant,
|
|
23
26
|
auditSources,
|
|
24
27
|
blockSkill,
|
|
25
28
|
canUseSkill,
|
|
26
29
|
explainSkill,
|
|
30
|
+
forkSkillVariant,
|
|
27
31
|
installGuardHook,
|
|
28
32
|
listHarnesses,
|
|
29
33
|
listInstallUnits,
|
|
@@ -31,14 +35,18 @@ import {
|
|
|
31
35
|
listWorkflows,
|
|
32
36
|
preferSkill,
|
|
33
37
|
quarantineSkill,
|
|
34
|
-
removeSkill
|
|
38
|
+
removeSkill,
|
|
39
|
+
resetSkillVariant,
|
|
40
|
+
variantLifecycleStatus
|
|
35
41
|
} from "./control.mjs";
|
|
36
42
|
|
|
37
43
|
export {
|
|
38
44
|
activateSkill,
|
|
39
45
|
addHarness,
|
|
40
46
|
addSkill,
|
|
47
|
+
addSkillVariant,
|
|
41
48
|
addWorkflow,
|
|
49
|
+
approveSkillVariant,
|
|
42
50
|
agentInventoryDetectors,
|
|
43
51
|
auditSources,
|
|
44
52
|
blockSkill,
|
|
@@ -49,6 +57,7 @@ export {
|
|
|
49
57
|
detectInstallOutput,
|
|
50
58
|
doctorProject,
|
|
51
59
|
explainSkill,
|
|
60
|
+
forkSkillVariant,
|
|
52
61
|
impactDisable,
|
|
53
62
|
importSource,
|
|
54
63
|
initProject,
|
|
@@ -64,6 +73,7 @@ export {
|
|
|
64
73
|
preferSkill,
|
|
65
74
|
quarantineSkill,
|
|
66
75
|
removeSkill,
|
|
76
|
+
resetSkillVariant,
|
|
67
77
|
reconcileWorkspace,
|
|
68
78
|
refreshAgentInventory,
|
|
69
79
|
refreshSourcePins,
|
|
@@ -74,9 +84,11 @@ export {
|
|
|
74
84
|
rolloutPlan,
|
|
75
85
|
rolloutReport,
|
|
76
86
|
rolloutRollback,
|
|
87
|
+
routeSkill,
|
|
77
88
|
renderImportFragment,
|
|
78
89
|
renderReconcilePlan,
|
|
79
90
|
uninstallProject,
|
|
80
91
|
verifySources,
|
|
92
|
+
variantLifecycleStatus,
|
|
81
93
|
writeLockfile
|
|
82
94
|
};
|
package/src/lifecycle-cli.mjs
CHANGED
|
@@ -30,7 +30,8 @@ export async function runInitCommand(options, stdout, runtime = defaultRuntime()
|
|
|
30
30
|
writeSafetyDefault(stdout, result.safety);
|
|
31
31
|
writeNextCommands(stdout, {
|
|
32
32
|
command: commandPrefix(runtime),
|
|
33
|
-
dir: options.get("dir")
|
|
33
|
+
dir: options.get("dir"),
|
|
34
|
+
workflows: result.scan.addedWorkflows ?? []
|
|
34
35
|
});
|
|
35
36
|
return 0;
|
|
36
37
|
}
|
|
@@ -85,7 +86,7 @@ function writeSafetyDefault(stdout, safety) {
|
|
|
85
86
|
stdout.write(`- ${safety.automatic} automatic skills enabled by existing policy.\n`);
|
|
86
87
|
}
|
|
87
88
|
stdout.write("- Imported local skills are manual-only.\n");
|
|
88
|
-
stdout.write("- Runtime/plugin/system skills
|
|
89
|
+
stdout.write("- Runtime/plugin/system skills require source review before manual activation.\n");
|
|
89
90
|
stdout.write(`- ${safety.automatic} automatic skills enabled\n`);
|
|
90
91
|
stdout.write(`- ${safety.manualOnly} manual-only skills available\n`);
|
|
91
92
|
stdout.write(`- ${safety.routerOnly} router-only skills available\n`);
|
|
@@ -94,10 +95,22 @@ function writeSafetyDefault(stdout, safety) {
|
|
|
94
95
|
|
|
95
96
|
function writeNextCommands(stdout, next) {
|
|
96
97
|
const dir = next.dir === undefined ? "" : ` --dir ${shellQuote(next.dir)}`;
|
|
98
|
+
const workflows = sorted(next.workflows ?? []);
|
|
97
99
|
stdout.write("Next:\n");
|
|
100
|
+
stdout.write('- Ask your AI: "What skills can you use in this project?"\n');
|
|
98
101
|
stdout.write(`- ${next.command} doctor${dir} --summary\n`);
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
if (workflows.length === 0) {
|
|
103
|
+
stdout.write(`- ${next.command} brief${dir}\n`);
|
|
104
|
+
stdout.write(`- ${next.command} brief${dir} --verbose\n`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const workflow = workflows[0];
|
|
108
|
+
stdout.write(`Choose a workflow: ${formatList(workflows)}\n`);
|
|
109
|
+
stdout.write(`Example workflow brief: ${formatList([workflow])}\n`);
|
|
110
|
+
stdout.write(`- ${next.command} brief --workflow ${shellQuote(workflow)}${dir}\n`);
|
|
111
|
+
stdout.write('Example task routing: "write tests before implementation"\n');
|
|
112
|
+
stdout.write(`- ${next.command} brief --workflow ${shellQuote(workflow)} --intent ${shellQuote("write tests before implementation")}${dir}\n`);
|
|
113
|
+
stdout.write(`- ${next.command} brief --workflow ${shellQuote(workflow)}${dir} --verbose\n`);
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
function formatList(values) {
|
|
@@ -127,10 +140,8 @@ function commandPrefix(runtime) {
|
|
|
127
140
|
const entrypoint = runtime.entrypointPath ?? "";
|
|
128
141
|
const normalized = entrypoint.replaceAll("\\", "/");
|
|
129
142
|
if (normalized.includes("/_npx/")) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return "npx agent-skillboard";
|
|
143
|
+
const packageSpec = runtime.packageSpec ?? "agent-skillboard";
|
|
144
|
+
return `npx --yes --package ${shellQuote(packageSpec)} skillboard`;
|
|
134
145
|
}
|
|
135
146
|
if (isSourceTreeEntrypoint(entrypoint)) {
|
|
136
147
|
return `node ${sourceTreeEntrypoint(entrypoint, runtime.cwd ?? process.cwd())}`;
|
|
@@ -20,31 +20,38 @@ export function bridgeBlock() {
|
|
|
20
20
|
return `${BRIDGE_START}
|
|
21
21
|
# SkillBoard Control Plane
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Your responsibility is to answer skill availability questions from SkillBoard, translate user intent into current action ids, ask for one confirmation only before policy-changing actions, apply one current action, reread the post-apply brief, and run the guard automatically before invocation.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
25
|
+
## Product Goal
|
|
26
|
+
|
|
27
|
+
- SkillBoard is a non-blocking AI skill routing control plane, not a pre-task settings checklist.
|
|
28
|
+
- Read \`docs/ai-skill-routing-goal.md\` before changing routing, brief, bridge, policy, or workflow UX.
|
|
29
|
+
- Preserve the loop: observe → route → work → explain briefly → ask after → remember policy.
|
|
30
|
+
- SkillBoard does not rewrite \`SKILL.md\` bodies to personalize behavior; record usage policy for when to use, prefer, reference, avoid, or block skills.
|
|
31
|
+
|
|
32
|
+
## Availability
|
|
33
|
+
|
|
34
|
+
- Use SkillBoard as the source of truth; installed \`SKILL.md\` files are not automatically callable.
|
|
35
|
+
- Read the current brief before answering: \`skillboard brief --json --config skillboard.config.yaml --skills skills\`. If the workflow is known, include \`--workflow <name>\`; add \`--include-actions\` when the user wants you to mediate a change.
|
|
36
|
+
- When the user asks which skill fits a task, read \`skillboard brief --intent <request> --json --config skillboard.config.yaml --skills skills\`. Include \`--workflow <name>\` when known. Read \`assistant_guidance.route\`; use \`recommended_skill\`, \`fallback_skills\`, \`route_candidates\`, \`post_use_policy_suggestion\`, and \`guard_command\` instead of guessing from raw skill text. Inspect \`route_candidates\` when several skills match so denied candidates and selected fallbacks are clear. If \`post_use_policy_suggestion\` is present, work first with the allowed routed skill, then ask after completion whether to remember the suggested policy. If no skill matches, ask a clarifying question before choosing a skill.
|
|
28
37
|
- Treat the brief sections headed "What your AI can use now", "Needs your decision", and "Blocked for safety" as the availability summary; do not infer availability from \`SKILL.md\` bodies.
|
|
29
38
|
- Treat "Needs your decision" as a one-time decision queue, not a persistent blocked state. "Blocked for safety" means the skill/source/workflow is hard-blocked until policy or provenance changes.
|
|
30
39
|
- Use \`skillboard can-use <skill-id> --workflow <name> --config skillboard.config.yaml --skills skills --json\` for machine-readable agent decisions.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
- Run \`skillboard inventory refresh --dry-run --config skillboard.config.yaml\` after installing a new local agent skill pack, plugin, workflow bundle, or harness.
|
|
47
|
-
- Run \`skillboard import --profile <id-or-path> --source-root <repo> --out .skillboard/reports/import-fragment.yaml\` after installing a new skill repository, then review the fragment before merging it into \`skillboard.config.yaml\`.
|
|
40
|
+
|
|
41
|
+
## Intent to Action
|
|
42
|
+
|
|
43
|
+
- Translate user intent into current action ids from the current brief, not saved output.
|
|
44
|
+
- For action cards, read \`skillboard brief --json --config skillboard.config.yaml --skills skills --include-actions\`, pick one current action id, ask the user for one confirmation, then run \`skillboard apply-action <action-id> --config skillboard.config.yaml --skills skills --yes --json\`. Include \`--workflow <name>\` when a workflow is selected.
|
|
45
|
+
- After \`skillboard apply-action <action-id> ... --yes --json\`, reread the returned post-apply brief before answering the next availability question or applying another action. \`apply-action\` re-resolves current actions; do not apply cached or stale action ids, do not apply multiple actions, and do not run raw action-card shell text as the primary apply path.
|
|
46
|
+
- For an already-allowed skill, do not ask for another approval. Run \`skillboard guard use <skill-id> --workflow <name> --config skillboard.config.yaml --skills skills\` automatically. Say at the start: "I will use <skill-id> for this request." Say at completion: "I used <skill-id> for this request." Treat this disclosure as an audit trace, not a permission prompt. Ask the user only if the guard denies use or a policy-changing action is needed.
|
|
47
|
+
|
|
48
|
+
## Operations
|
|
49
|
+
|
|
50
|
+
- Source trust: run \`skillboard audit sources --config skillboard.config.yaml --skills skills\` before trusting newly imported external skill sources; after review, use \`skillboard review install-unit <unit-id> --trust-level reviewed --config skillboard.config.yaml --skills skills\`. Unreviewed runtime sources are a one-time review decision, not a default block recommendation; after review, activate only the needed quarantined skills as manual-only workflow skills and use ask-after policy suggestions for future preferences.
|
|
51
|
+
- Health: run \`skillboard doctor --config skillboard.config.yaml --skills skills\` or \`skillboard status --config skillboard.config.yaml --skills skills --json\`; add \`--strict\` when review-needed safe mode should fail automation.
|
|
52
|
+
- Hook action cards: prefer \`skillboard apply-action <action-id> --yes --json\`. The underlying manual preview is \`skillboard hook install --workflow <name> --config skillboard.config.yaml --skills skills --out .skillboard/hooks/<name>-guard.sh --dry-run --json\`; inspect \`planned.preview.shell\` before materializing an executable guard hook outside the action-card control loop. Generated hooks pin the install-time SkillBoard command, config, skills root, and workflow; set those values with hook install options such as \`--skillboard-bin\`, not runtime environment overrides.
|
|
53
|
+
- Inventory/import growth: run \`skillboard inventory refresh --dry-run --config skillboard.config.yaml\` after installing local skill packs, plugins, workflow bundles, or harnesses; run \`skillboard import --profile <id-or-path> --source-root <repo> --out .skillboard/reports/import-fragment.yaml\` after installing a new skill repository, then review the fragment before merging it into \`skillboard.config.yaml\`.
|
|
54
|
+
- Prefer workflow-scoped skills over global skill invocation. Only \`global-meta\` skills may be treated as globally available.
|
|
48
55
|
|
|
49
56
|
${BRIDGE_END}`;
|
|
50
57
|
}
|
|
@@ -77,11 +84,14 @@ skillboard hook install --workflow <name> --config skillboard.config.yaml --skil
|
|
|
77
84
|
skillboard hook install --workflow <name> --config skillboard.config.yaml --skills skills --out .skillboard/hooks/<name>-guard.sh
|
|
78
85
|
\`\`\`
|
|
79
86
|
|
|
80
|
-
For hook action cards, prefer the bridge
|
|
87
|
+
For hook action cards, prefer the bridge control loop with
|
|
81
88
|
\`skillboard apply-action <action-id> --yes --json\`. These raw hook commands
|
|
82
89
|
are the underlying manual detail: preview the JSON plan first and inspect
|
|
83
90
|
\`planned.preview.shell\` before materializing an executable guard hook.
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
Generated hooks pin the install-time SkillBoard command, config, skills root,
|
|
92
|
+
and workflow; set those values with hook install options such as
|
|
93
|
+
\`--skillboard-bin\`, not runtime environment overrides. The generated script
|
|
94
|
+
delegates to \`skillboard guard use\` and can be wired into the hook mechanism of
|
|
95
|
+
the active harness.
|
|
86
96
|
`;
|
|
87
97
|
}
|