@dot-skill/protocol 0.4.2 → 0.5.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.
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Multi-skill identification → scaffold extraction for agents.
3
+ *
4
+ * Segmentation is an agent/adapter responsibility. This module does not invent
5
+ * skills from free prose: the caller must supply candidate topics. It emits
6
+ * incomplete SkillContract / SkillSource scaffolds plus completeness reports
7
+ * so create flows stay coherent with SkillContract 0.5 and refuse incomplete
8
+ * release compiles.
9
+ */
10
+ import { createHash } from "node:crypto";
11
+ import { assessSkillContract, scaffoldSkillContract } from "./authoring.js";
12
+ import { PROTOCOL_VERSION } from "./types.js";
13
+ function slugify(title) {
14
+ const slug = title
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, "-")
17
+ .replace(/^-+|-+$/g, "")
18
+ .slice(0, 64);
19
+ return slug || "skill-candidate";
20
+ }
21
+ function candidateId(title, index) {
22
+ const digest = createHash("sha256")
23
+ .update(`${index}:${title}`)
24
+ .digest("hex")
25
+ .slice(0, 12);
26
+ return `cand_${digest}`;
27
+ }
28
+ function normalizeCandidates(input) {
29
+ const fromCandidates = input.candidates ?? [];
30
+ const fromTopics = (input.topics ?? []).map((topic) => typeof topic === "string" ? { title: topic } : topic);
31
+ const merged = [...fromCandidates, ...fromTopics];
32
+ const seen = new Set();
33
+ const out = [];
34
+ for (const item of merged) {
35
+ const title = typeof item.title === "string" ? item.title.trim() : "";
36
+ if (!title)
37
+ continue;
38
+ const key = title.toLowerCase();
39
+ if (seen.has(key))
40
+ continue;
41
+ seen.add(key);
42
+ out.push({ ...item, title });
43
+ }
44
+ return out;
45
+ }
46
+ function parseJourney(raw) {
47
+ if (!raw || typeof raw !== "object") {
48
+ throw new Error('extract expects JSON object { summary, candidates|topics: [...] }. Run: skill agent-guide');
49
+ }
50
+ const obj = raw;
51
+ const summary = typeof obj.summary === "string"
52
+ ? obj.summary
53
+ : typeof obj.journey_summary === "string"
54
+ ? obj.journey_summary
55
+ : "";
56
+ if (!summary.trim()) {
57
+ throw new Error("extract requires a redacted journey summary string (summary or journey_summary).");
58
+ }
59
+ return {
60
+ kind: "redacted_journey",
61
+ summary: summary.trim(),
62
+ redacted: obj.redacted !== false,
63
+ sensitivity: obj.sensitivity === "private" ||
64
+ obj.sensitivity === "shareable_redacted" ||
65
+ obj.sensitivity === "public"
66
+ ? obj.sensitivity
67
+ : "shareable_redacted",
68
+ candidates: Array.isArray(obj.candidates)
69
+ ? obj.candidates
70
+ : undefined,
71
+ topics: Array.isArray(obj.topics)
72
+ ? obj.topics
73
+ : undefined,
74
+ };
75
+ }
76
+ function seedContract(title, intent, skillKind, sensitivity) {
77
+ const scaffold = scaffoldSkillContract();
78
+ scaffold.title = title;
79
+ scaffold.intent =
80
+ intent?.trim() ||
81
+ `__required__: state the transferable intent for “${title}” (what an agent must do).`;
82
+ if (skillKind)
83
+ scaffold.skill_kind = skillKind;
84
+ scaffold.sensitivity = sensitivity;
85
+ return scaffold;
86
+ }
87
+ function sourceScaffold(args) {
88
+ return {
89
+ kind: "skill_source",
90
+ id: args.id,
91
+ hash: `sha256:${"0".repeat(64)}`,
92
+ title: args.title,
93
+ summary: args.summary,
94
+ intent: args.contract.intent,
95
+ contract: args.contract,
96
+ candidates: undefined,
97
+ sections: [],
98
+ steering: [],
99
+ prompts: [],
100
+ code_refs: [],
101
+ parents: [],
102
+ agent: {
103
+ host: args.host,
104
+ deployment: "unknown",
105
+ },
106
+ journey: {
107
+ summary: args.summary,
108
+ redacted: true,
109
+ sensitivity: args.sensitivity,
110
+ },
111
+ inputs_declared: "inferred",
112
+ sensitivity: args.sensitivity,
113
+ created_at: new Date(0).toISOString(),
114
+ actor: { id: "agent" },
115
+ source_protocol_version: PROTOCOL_VERSION,
116
+ source_refs: args.evidenceRefs.map((ref, i) => ({
117
+ product: "extract",
118
+ kind: "evidence",
119
+ id: `ev_${i + 1}`,
120
+ hash: ref,
121
+ })),
122
+ };
123
+ }
124
+ const PROTOCOL_RULES = [
125
+ "Identify distinct transferable skills from the redacted journey; do not collapse unrelated topics into one skill.",
126
+ "One skill workspace per candidate (skill init in its own directory).",
127
+ "Fill a SkillContract 0.5 for each skill; section prose alone cannot satisfy release completeness.",
128
+ "Run skill status / skill contract-check; refuse release compile when incomplete.",
129
+ "Never invent filler declarations to force a mint; use continuity checkpoint for partial handoff.",
130
+ "Secrets stay as {{refs}} / env refs; journey text must stay redacted.",
131
+ ];
132
+ const CREATE_PATH = [
133
+ "skill agent-guide",
134
+ "Identify N candidate skills → write redacted_journey.json with summary + candidates|topics",
135
+ "skill extract redacted_journey.json -o ./extraction",
136
+ "For each selected candidate: mkdir workspace && cd workspace && skill init --title \"…\"",
137
+ "Copy/adapt contract scaffold → complete every declaration (or explicit none/not_applicable)",
138
+ "skill journey --summary \"…\" && skill propose … (evidence sections)",
139
+ "skill contract-check .skill/… or contract.json --profile release",
140
+ "skill status → skill compile -m \"…\" --approve --mint (or checkpoint if incomplete)",
141
+ ];
142
+ /**
143
+ * Emit incomplete SkillContract/SkillSource scaffolds for agent-identified candidates.
144
+ * Does not invent topics from free prose when candidates/topics are absent.
145
+ */
146
+ export function extractSkillCandidates(raw, options = {}) {
147
+ const journey = parseJourney(raw);
148
+ const profile = options.profile ?? "release";
149
+ const host = options.host ?? "__set_SKILL_HOST__";
150
+ const candidates = normalizeCandidates(journey);
151
+ if (candidates.length === 0) {
152
+ throw new Error("No skill candidates supplied. Identify distinct skills from the journey, then pass candidates:[{title,evidence_refs?}] or topics:[\"…\"]. See: skill agent-guide");
153
+ }
154
+ const scaffolds = candidates.map((item, index) => {
155
+ const id = item.id?.trim() || candidateId(item.title, index);
156
+ const evidence = item.evidence_refs?.filter((r) => typeof r === "string" && r.trim()) ??
157
+ [];
158
+ if (evidence.length === 0) {
159
+ evidence.push(`journey:${slugify(item.title)}`);
160
+ }
161
+ const contract = seedContract(item.title, item.intent, item.skill_kind, journey.sensitivity ?? "shareable_redacted");
162
+ const assessment = assessSkillContract(contract, profile);
163
+ const candidate = {
164
+ id,
165
+ title: item.title,
166
+ evidence_refs: evidence,
167
+ assessment,
168
+ // Incomplete scaffold is intentional; do not claim a complete contract.
169
+ contract: undefined,
170
+ };
171
+ const workspace_slug = slugify(item.title);
172
+ const missing = assessment.issues.map(({ field, message, fix }) => ({
173
+ field,
174
+ message,
175
+ fix,
176
+ }));
177
+ const source = sourceScaffold({
178
+ id: `src_${id.replace(/^cand_/, "")}`,
179
+ title: item.title,
180
+ summary: journey.summary,
181
+ contract,
182
+ evidenceRefs: evidence,
183
+ sensitivity: journey.sensitivity ?? "shareable_redacted",
184
+ host,
185
+ });
186
+ return {
187
+ candidate,
188
+ contract_scaffold: contract,
189
+ source_scaffold: source,
190
+ workspace_slug,
191
+ missing,
192
+ next_steps: [
193
+ `mkdir -p ${workspace_slug} && cd ${workspace_slug} && export SKILL_HOST=${host === "__set_SKILL_HOST__" ? "cursor" : host} && skill init --title ${JSON.stringify(item.title)}`,
194
+ "Complete contract_scaffold into a real SkillContract 0.5 (every declaration explicit).",
195
+ `skill contract-check contract.json --profile ${profile}`,
196
+ 'skill journey --summary "…" && skill propose --json \'[…]\'',
197
+ "skill status — refuse release compile until complete; use skill checkpoint for handoff.",
198
+ ],
199
+ };
200
+ });
201
+ return {
202
+ kind: "skill_extraction",
203
+ protocol_version: PROTOCOL_VERSION,
204
+ profile,
205
+ journey_summary: journey.summary,
206
+ redacted: journey.redacted !== false,
207
+ candidate_count: scaffolds.length,
208
+ scaffolds,
209
+ protocol: {
210
+ one_workspace_per_skill: true,
211
+ refuse_release_if_incomplete: true,
212
+ rules: PROTOCOL_RULES,
213
+ create_path: CREATE_PATH,
214
+ },
215
+ };
216
+ }
217
+ /** Alias for adapters that prefer "segment" vocabulary. */
218
+ export const segmentJourney = extractSkillCandidates;
219
+ /** Structured agent-facing create / multi-skill protocol (also printed by CLI). */
220
+ export function agentCreateGuide() {
221
+ return {
222
+ kind: "skill_agent_guide",
223
+ protocol_version: PROTOCOL_VERSION,
224
+ purpose: "Create portable .skill packages with SkillContract 0.5. Identify multiple skills from a conversation when warranted; enforce completeness; never fake a release.",
225
+ rules: PROTOCOL_RULES,
226
+ identify_multiple_skills: [
227
+ "Read the redacted journey / work summary. List distinct transferable skills (separate intents, triggers, or runtimes).",
228
+ "Do not invent a multi-skill auto-pipeline beyond this protocol. You identify; the CLI scaffolds.",
229
+ "Write JSON: { \"kind\":\"redacted_journey\", \"summary\":\"…\", \"redacted\":true, \"candidates\":[{ \"title\":\"…\", \"evidence_refs\":[\"…\"], \"intent\":\"…\", \"skill_kind\":\"procedure|knowledge|integration\" }] }",
230
+ "Run: skill extract journey.json -o ./extraction",
231
+ "Present candidates + missing[] reports to the human. Only proceed on selected skills.",
232
+ "One directory / one skill init per selected candidate. Never merge unrelated candidates into one workspace.",
233
+ ],
234
+ create_one_skill: [
235
+ "export SKILL_HOST=<your-host-id>",
236
+ "skill init --title \"…\"",
237
+ "skill journey --summary \"Redacted human+AI journey…\"",
238
+ "Complete SkillContract 0.5 (skill contract-template → edit → skill contract-check).",
239
+ "skill propose --json '[{\"title\":\"…\",\"body\":\"…\",\"type\":\"decision|integration|…\"}]' for evidence sections",
240
+ "skill status — inspect completeness / missing",
241
+ "Partial handoff: skill checkpoint -m \"WIP\"",
242
+ "Release only when complete: skill compile -m \"…\" --approve --mint",
243
+ "On compile_refused: list missing fields/fixes; do not pack a fake release.",
244
+ ],
245
+ ingest: [
246
+ "skill inspect ./file.skill",
247
+ "skill validate ./file.skill",
248
+ "skill verify-trust ./file.skill",
249
+ "skill load ./file.skill # continuity resume",
250
+ "skill run ./file.skill # dry-run by default",
251
+ ],
252
+ cli: [
253
+ "skill agent-guide [--json]",
254
+ "skill extract <journey.json> [-o dir] [--profile release|continuity]",
255
+ "skill segment … # alias of extract",
256
+ "skill contract-template",
257
+ "skill contract-check <contract-or-source.json> [--profile release|continuity]",
258
+ "skill status",
259
+ ],
260
+ refuse: [
261
+ "Refuse release compile/mint when contract assessment is incomplete.",
262
+ "Refuse to invent filler skills or filler contract fields to satisfy gates.",
263
+ "Refuse to create multiple skills in one workspace.",
264
+ "Refuse to proceed without SKILL_HOST on create/mint paths.",
265
+ ],
266
+ };
267
+ }
268
+ /** Human-readable text form of agentCreateGuide (for terminals / AGENT.md parity). */
269
+ export function formatAgentGuide(guide = agentCreateGuide()) {
270
+ const lines = [
271
+ `skill agent-guide — Open .skill Protocol v${guide.protocol_version}`,
272
+ "",
273
+ guide.purpose,
274
+ "",
275
+ "Rules:",
276
+ ...guide.rules.map((r) => ` - ${r}`),
277
+ "",
278
+ "Identify → propose multiple skills:",
279
+ ...guide.identify_multiple_skills.map((r, i) => ` ${i + 1}. ${r}`),
280
+ "",
281
+ "Create one skill (complete or refuse):",
282
+ ...guide.create_one_skill.map((r) => ` $ ${r}`),
283
+ "",
284
+ "Ingest / load / run:",
285
+ ...guide.ingest.map((r) => ` $ ${r}`),
286
+ "",
287
+ "CLI:",
288
+ ...guide.cli.map((r) => ` $ ${r}`),
289
+ "",
290
+ "Refuse when:",
291
+ ...guide.refuse.map((r) => ` - ${r}`),
292
+ "",
293
+ ];
294
+ return lines.join("\n");
295
+ }
296
+ /** Type guard helper for partial SkillContract assessments on scaffolds. */
297
+ export function assessExtractionScaffold(scaffold, profile = "release") {
298
+ return assessSkillContract(scaffold.contract_scaffold, profile);
299
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
- /** Open .skill Protocol v0.4 — types, constants, and schemas. */
1
+ /** Open .skill Protocol v0.5 — types, constants, authoring APIs, and schemas. */
2
2
  export { PROTOCOL_VERSION, CONTAINER_VERSION, WORKFLOW_DIALECT_VERSION, MEDIA_TYPE, MANIFEST_MEDIA_TYPE, DEFAULT_SKILL_POLICY, } from "./types.js";
3
- export type { SkillCompileProfile, PackageSensitivity, ProvenanceMode, MintStatus, PermanenceAnchorKind, TrustProfile, InputSource, SensitivityLevel, AskWhen, SideEffectClass, CapabilityFallback, KnowledgeItemType, SteeringEffect, WorkflowStepKind, SkillRunStatus, RuntimeMode, CompletenessPart, GenerationUsage, JourneyProvenance, CompletenessReport, JsonSchema, ContentDigest, ProvenanceRef, InputSlot, OutputContract, CapabilityAdapterHint, CapabilityRequirement, SkillPermission, SkillPolicy, SkillDependency, MintRecord, CreationAttestation, PermanenceAnchor, SkillManifest, KnowledgeItem, SteeringConstraint, WorkflowStepBase, InstructStep, PromptStep, ToolStep, TransformStep, BranchStep, IterateStep, DelegateStep, CheckpointStep, HumanDecisionStep, VerifyStep, EmitStep, SubskillStep, WorkflowStep, Workflow, CompilationIssue, CompilationMapping, CompilationReport, SkillPackageFiles, SkillStepRecord, SkillRun, } from "./types.js";
4
- export { FORBIDDEN_AGENT_HOSTS, isValidAgentHost, } from "./source.js";
3
+ export type { SkillCompileProfile, PackageSensitivity, ProvenanceMode, MintStatus, PermanenceAnchorKind, TrustProfile, TrustState, HostClaimBinding, IssuerClass, InputSource, SensitivityLevel, AskWhen, SideEffectClass, CapabilityFallback, KnowledgeItemType, SteeringEffect, WorkflowStepKind, SkillRunStatus, RuntimeMode, CompletenessPart, GenerationUsage, JourneyProvenance, CompletenessReport, JsonSchema, ContentDigest, ProvenanceRef, InputSlot, OutputContract, CapabilityAdapterHint, CapabilityRequirement, SkillPermission, SkillPolicy, SkillDependency, MintRecord, SealedManifestClaims, CreationAttestation, TrustView, PermanenceAnchor, SkillManifest, KnowledgeItem, SteeringConstraint, WorkflowStepBase, InstructStep, PromptStep, ToolStep, TransformStep, BranchStep, IterateStep, DelegateStep, CheckpointStep, HumanDecisionStep, VerifyStep, EmitStep, SubskillStep, WorkflowStep, Workflow, CompilationIssue, CompilationMapping, CompilationReport, SkillPackageFiles, SkillStepRecord, SkillRun, } from "./types.js";
4
+ export { FORBIDDEN_AGENT_HOSTS, AGENT_RUNTIME_MARKER_ENVS, isValidAgentHost, detectAgentRuntimeMarkers, hasAgentRuntimeEvidence, } from "./source.js";
5
+ export { assessSkillContract, scaffoldSkillContract, explainContractAssessment, } from "./authoring.js";
6
+ export { extractSkillCandidates, segmentJourney, agentCreateGuide, formatAgentGuide, assessExtractionScaffold, } from "./extract.js";
7
+ export type { JourneyCandidateInput, RedactedJourneyInput, ExtractionScaffold, ExtractionReport, AgentGuide, } from "./extract.js";
8
+ export type { SkillKind, DeclarationStatus, ExplicitDeclaration, ContractTrigger, InputApproval, ContractInput, ContractPrecondition, ContractStepKind, ContractStep, ContractBranch, ContractHumanDecision, ContractCapability, ContractPermission, ForbiddenAction, ContractOutput, RecoveryEdge, VerificationAssertion, ContractCorrection, ContractEvidence, ContractProvenance, SkillContract, ContractField, ContractIssue, ContractAssessment, SkillCandidate, } from "./contract.js";
5
9
  export type { SectionType, SectionAuthor, CodeRef, Attachment, PersonRef, SkillSection, SteeringEvent, PromptVersion, AgentContext, SkillSource, SteeringVerb, CaptureFidelity, } from "./source.js";
6
10
  export { recipeToSkillSource } from "./recipe.js";
7
11
  export type { IngredientType, VisibilityIntent, RecipeIngredient, Recipe, Skill, } from "./recipe.js";
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
- /** Open .skill Protocol v0.4 — types, constants, and schemas. */
1
+ /** Open .skill Protocol v0.5 — types, constants, authoring APIs, and schemas. */
2
2
  export { PROTOCOL_VERSION, CONTAINER_VERSION, WORKFLOW_DIALECT_VERSION, MEDIA_TYPE, MANIFEST_MEDIA_TYPE, DEFAULT_SKILL_POLICY, } from "./types.js";
3
- export { FORBIDDEN_AGENT_HOSTS, isValidAgentHost, } from "./source.js";
3
+ export { FORBIDDEN_AGENT_HOSTS, AGENT_RUNTIME_MARKER_ENVS, isValidAgentHost, detectAgentRuntimeMarkers, hasAgentRuntimeEvidence, } from "./source.js";
4
+ export { assessSkillContract, scaffoldSkillContract, explainContractAssessment, } from "./authoring.js";
5
+ export { extractSkillCandidates, segmentJourney, agentCreateGuide, formatAgentGuide, assessExtractionScaffold, } from "./extract.js";
4
6
  export { recipeToSkillSource } from "./recipe.js";
package/dist/recipe.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * Skillerr (and similar products) map recipe/ingredient/bake → SkillSource/compile.
6
6
  */
7
7
  import type { GenerationUsage, JourneyProvenance } from "./types.js";
8
+ import type { SkillContract } from "./contract.js";
8
9
  import type { AgentContext, Attachment, CodeRef, PersonRef, PromptVersion, SectionType, SkillSource, SteeringEvent } from "./source.js";
9
10
  /** @deprecated Prefer SectionType from source.ts — kept for Skillerr adapters. */
10
11
  export type IngredientType = SectionType;
@@ -48,6 +49,8 @@ export interface Recipe {
48
49
  source_protocol_version: string;
49
50
  generation_usage?: GenerationUsage;
50
51
  journey_summary?: string;
52
+ /** Optional 0.5 protocol-native semantics carried through this lossy product adapter. */
53
+ contract?: SkillContract;
51
54
  }
52
55
  /** @deprecated Legacy flat markdown skill export. Prefer SkillManifest / `.skill`. */
53
56
  export interface Skill {
package/dist/recipe.js CHANGED
@@ -45,6 +45,7 @@ export function recipeToSkillSource(recipe, overrides = {}) {
45
45
  title: recipe.title,
46
46
  summary: recipe.summary,
47
47
  intent: recipe.summary ?? recipe.title,
48
+ contract: recipe.contract ? structuredClone(recipe.contract) : undefined,
48
49
  sections,
49
50
  steering: recipe.steering,
50
51
  prompts: recipe.prompts,
package/dist/source.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * Products (Skillerr, etc.) may use their own words (ingredient, recipe, bake).
5
5
  * Adapters map those into SkillSource / SkillSection before compile.
6
6
  */
7
+ import type { SkillContract, SkillCandidate } from "./contract.js";
7
8
  import type { GenerationUsage, JourneyProvenance, PackageSensitivity } from "./types.js";
8
9
  export type SectionType = "prompt" | "decision" | "architecture" | "diagram" | "integration" | "resource" | "reference" | "lesson" | "requirement" | "tradeoff" | "risk" | "question" | "implementation_note" | "config" | "correction_note" | "doc" | "message" | "handoff" | "code" | "intent" | "workflow_note";
9
10
  export type SectionAuthor = "agent" | "human_via_agent";
@@ -89,6 +90,13 @@ export interface SkillSource {
89
90
  title: string;
90
91
  summary?: string;
91
92
  intent?: string;
93
+ /**
94
+ * 0.5 source of truth for transferable semantics. A missing contract marks
95
+ * a 0.4-compatible text source and is release-lossy.
96
+ */
97
+ contract?: SkillContract;
98
+ /** Optional extraction candidates. Segmentation belongs to an adapter/AI, not the compiler. */
99
+ candidates?: SkillCandidate[];
92
100
  sections: SkillSection[];
93
101
  steering: SteeringEvent[];
94
102
  prompts: PromptVersion[];
@@ -111,6 +119,20 @@ export interface SkillSource {
111
119
  hash?: string;
112
120
  }>;
113
121
  }
114
- /** Hosts that are not valid AI agent runtimes for skill creation. */
122
+ /**
123
+ * Hosts that are not valid AI agent runtimes for skill creation / mint.
124
+ * Humans exporting SKILL_HOST=cli|shell|manual must never mint as an agent.
125
+ */
115
126
  export declare const FORBIDDEN_AGENT_HOSTS: Set<string>;
116
127
  export declare function isValidAgentHost(host: string | undefined | null): boolean;
128
+ /**
129
+ * Process / mint markers that indicate an agent runtime path (not a bare human shell).
130
+ * These are still spoofable by a determined local process — residual risk remains —
131
+ * but a human who only exports SKILL_HOST=cursor without any agent context fails this check.
132
+ */
133
+ export declare const AGENT_RUNTIME_MARKER_ENVS: readonly ["CURSOR_AGENT", "CURSOR_TRACE_ID", "COMPOSER_SESSION_ID", "SKILL_AGENT_INVOCATION", "SKILL_SESSION_ID", "CLAUDE_CODE_ENTRYPOINT", "AIDER_ACTIVE"];
134
+ export declare function detectAgentRuntimeMarkers(env?: Record<string, string | undefined>): string[];
135
+ export declare function hasAgentRuntimeEvidence(evidence?: {
136
+ markers?: string[];
137
+ session_id?: string;
138
+ } | null, env?: Record<string, string | undefined>): boolean;
package/dist/source.js CHANGED
@@ -4,7 +4,10 @@
4
4
  * Products (Skillerr, etc.) may use their own words (ingredient, recipe, bake).
5
5
  * Adapters map those into SkillSource / SkillSection before compile.
6
6
  */
7
- /** Hosts that are not valid AI agent runtimes for skill creation. */
7
+ /**
8
+ * Hosts that are not valid AI agent runtimes for skill creation / mint.
9
+ * Humans exporting SKILL_HOST=cli|shell|manual must never mint as an agent.
10
+ */
8
11
  export const FORBIDDEN_AGENT_HOSTS = new Set([
9
12
  "",
10
13
  "human",
@@ -12,9 +15,55 @@ export const FORBIDDEN_AGENT_HOSTS = new Set([
12
15
  "none",
13
16
  "cli",
14
17
  "user",
18
+ "shell",
19
+ "bash",
20
+ "zsh",
21
+ "sh",
22
+ "fish",
23
+ "powershell",
24
+ "pwsh",
25
+ "cmd",
26
+ "terminal",
27
+ "console",
28
+ "tty",
29
+ "stdin",
30
+ "keyboard",
31
+ "local-shell",
32
+ "human-cli",
33
+ "operator",
15
34
  ]);
16
35
  export function isValidAgentHost(host) {
17
36
  if (!host)
18
37
  return false;
19
38
  return !FORBIDDEN_AGENT_HOSTS.has(host.trim().toLowerCase());
20
39
  }
40
+ /**
41
+ * Process / mint markers that indicate an agent runtime path (not a bare human shell).
42
+ * These are still spoofable by a determined local process — residual risk remains —
43
+ * but a human who only exports SKILL_HOST=cursor without any agent context fails this check.
44
+ */
45
+ export const AGENT_RUNTIME_MARKER_ENVS = [
46
+ "CURSOR_AGENT",
47
+ "CURSOR_TRACE_ID",
48
+ "COMPOSER_SESSION_ID",
49
+ "SKILL_AGENT_INVOCATION",
50
+ "SKILL_SESSION_ID",
51
+ "CLAUDE_CODE_ENTRYPOINT",
52
+ "AIDER_ACTIVE",
53
+ ];
54
+ export function detectAgentRuntimeMarkers(env = process.env) {
55
+ const found = [];
56
+ for (const key of AGENT_RUNTIME_MARKER_ENVS) {
57
+ const v = env[key];
58
+ if (v !== undefined && String(v).trim() !== "")
59
+ found.push(key);
60
+ }
61
+ return found;
62
+ }
63
+ export function hasAgentRuntimeEvidence(evidence, env = process.env) {
64
+ if (evidence?.session_id && evidence.session_id.trim())
65
+ return true;
66
+ if (evidence?.markers?.some((m) => m.trim()))
67
+ return true;
68
+ return detectAgentRuntimeMarkers(env).length > 0;
69
+ }
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- /** Open .skill Protocol v0.4 — semantic types for portable `.skill` packages. */
2
- export declare const PROTOCOL_VERSION = "0.4.0";
1
+ /** Open .skill Protocol v0.5 — semantic types for portable `.skill` packages. */
2
+ import type { ContractBranch, ContractHumanDecision, InputApproval, ContractPrecondition, ContractTrigger, ExplicitDeclaration, RecoveryEdge, SkillContract, VerificationAssertion } from "./contract.js";
3
+ export declare const PROTOCOL_VERSION = "0.5.0";
3
4
  export declare const CONTAINER_VERSION = "1.0";
4
- export declare const WORKFLOW_DIALECT_VERSION = "1.0";
5
+ export declare const WORKFLOW_DIALECT_VERSION = "1.1";
5
6
  /** Media type for a packaged `.skill` archive (zip). */
6
7
  export declare const MEDIA_TYPE = "application/vnd.dot-skill+zip";
7
8
  /** Media type for the manifest JSON document inside a `.skill` archive. */
@@ -18,6 +19,21 @@ export type ProvenanceMode = "full" | "redacted" | "proof_only";
18
19
  export type MintStatus = "draft" | "minted";
19
20
  export type PermanenceAnchorKind = "registry" | "transparency_log" | "ledger" | "content_addressed_store" | "other";
20
21
  export type TrustProfile = "open" | "minted" | "anchored" | `issuer:${string}`;
22
+ /**
23
+ * Human-readable trust decision for TrustView / inspect --trust.
24
+ * - untrusted: unsigned, open, or failed verification
25
+ * - development: public-dev HMAC verified structurally — never production trust
26
+ * - self_reported: signed, but host/model claims are env/self-asserted (not issuer-verified)
27
+ * - verified_issuer: configured non-public issuer key bound the sealed claims
28
+ */
29
+ export type TrustState = "untrusted" | "development" | "self_reported" | "verified_issuer";
30
+ /** How the host/model claim was bound into the seal. */
31
+ export type HostClaimBinding = "self_reported" | "verified_issuer";
32
+ /**
33
+ * Class of mint issuer key material.
34
+ * public_dev_hmac MUST NOT be treated as production trust.
35
+ */
36
+ export type IssuerClass = "public_dev_hmac" | "configured_hmac" | "verified_issuer";
21
37
  export type InputSource = "human" | "environment" | "secret" | "artifact" | "derived";
22
38
  export type SensitivityLevel = "public" | "private" | "secret";
23
39
  export type AskWhen = "always" | "if_missing" | "never";
@@ -29,7 +45,7 @@ export type WorkflowStepKind = "instruct" | "prompt" | "tool" | "transform" | "b
29
45
  export type SkillRunStatus = "pending" | "running" | "paused" | "succeeded" | "failed" | "cancelled";
30
46
  export type RuntimeMode = "inspect" | "explain" | "dry_run" | "execute" | "resume";
31
47
  /** Parts the compiler checks before producing a package. */
32
- export type CompletenessPart = "agent_context" | "intent" | "sections" | "workflow" | "knowledge_or_prompts" | "inputs_declared" | "journey" | "generation_usage" | "human_approvals";
48
+ export type CompletenessPart = "agent_context" | "intent" | "sections" | "workflow" | "knowledge_or_prompts" | "inputs_declared" | "journey" | "generation_usage" | "human_approvals" | "semantic_contract" | "triggers" | "inputs" | "preconditions" | "steps" | "branches" | "human_decisions" | "capabilities" | "permissions" | "forbidden_actions" | "outputs" | "recovery" | "verification" | "corrections" | "provenance";
33
49
  export interface GenerationUsage {
34
50
  input_tokens?: number;
35
51
  output_tokens?: number;
@@ -79,6 +95,7 @@ export interface InputSlot {
79
95
  default?: unknown;
80
96
  sensitivity: SensitivityLevel;
81
97
  ask_when: AskWhen;
98
+ approval?: InputApproval;
82
99
  examples?: unknown[];
83
100
  provenance?: ProvenanceRef[];
84
101
  generalization_reason?: string;
@@ -139,9 +156,60 @@ export interface MintRecord {
139
156
  mint_issuer?: string;
140
157
  content_id?: string;
141
158
  }
159
+ /**
160
+ * Claims bound by the creation seal (identity + safety + content digests).
161
+ * Digest of this object is `sealed_manifest_digest`.
162
+ */
163
+ export interface SealedManifestClaims {
164
+ id: string;
165
+ version: string;
166
+ title: string;
167
+ intent?: string;
168
+ description: string;
169
+ package_digest: string;
170
+ permissions: Array<{
171
+ side_effect_class: SideEffectClass;
172
+ description: string;
173
+ paths?: string[];
174
+ hosts?: string[];
175
+ requires_consent: boolean;
176
+ }>;
177
+ policy: {
178
+ require_signatures: boolean;
179
+ require_minted?: boolean;
180
+ require_anchor?: boolean;
181
+ allow_network: boolean;
182
+ filesystem_roots?: string[];
183
+ consent_for: SideEffectClass[];
184
+ trust_profile?: TrustProfile;
185
+ max_tool_calls: number;
186
+ max_runtime_ms: number;
187
+ fail_on_unsupported_step: boolean;
188
+ };
189
+ capabilities: Array<{
190
+ name: string;
191
+ side_effect_class: SideEffectClass;
192
+ required: boolean;
193
+ }>;
194
+ inputs: Array<{
195
+ name: string;
196
+ sensitivity: SensitivityLevel;
197
+ required: boolean;
198
+ source: InputSource;
199
+ }>;
200
+ content: ContentDigest[];
201
+ contract?: {
202
+ title: string;
203
+ intent: string;
204
+ skill_kind: string;
205
+ sensitivity: string;
206
+ };
207
+ }
142
208
  export interface CreationAttestation {
143
209
  kind: "creation_attestation";
144
210
  package_digest: string;
211
+ /** Digest over identity + permissions/policy/capabilities + content index. */
212
+ sealed_manifest_digest: string;
145
213
  skill_id: string;
146
214
  skill_version: string;
147
215
  minted_at: string;
@@ -155,6 +223,12 @@ export interface CreationAttestation {
155
223
  model?: string;
156
224
  deployment?: "local" | "hosted" | "hybrid" | "unknown";
157
225
  endpoint?: string;
226
+ /** Whether host/model claims are self-asserted or issuer-verified. */
227
+ host_claim_binding: HostClaimBinding;
228
+ /** Issuer key class — public_dev_hmac is never production trust. */
229
+ issuer_class: IssuerClass;
230
+ /** Agent-runtime markers observed at mint (inspectable; still spoofable locally). */
231
+ agent_runtime_markers?: string[];
158
232
  journey: {
159
233
  /** @deprecated Prefer source_id — Skillerr recipe id when adapted. */
160
234
  recipe_id?: string;
@@ -172,6 +246,35 @@ export interface CreationAttestation {
172
246
  };
173
247
  policy_profile?: TrustProfile;
174
248
  }
249
+ /** Seal / trust summary readable without compile or model body ingest. */
250
+ export interface TrustView {
251
+ trust_state: TrustState;
252
+ mint_status: MintStatus;
253
+ signed: boolean;
254
+ issuer?: string;
255
+ issuer_class?: IssuerClass;
256
+ host_claim_binding?: HostClaimBinding;
257
+ agent?: {
258
+ host?: string;
259
+ provider?: string;
260
+ model?: string;
261
+ runtime?: string;
262
+ version?: string;
263
+ key_id?: string;
264
+ deployment?: string;
265
+ markers?: string[];
266
+ };
267
+ package_digest: string;
268
+ sealed_manifest_digest?: string;
269
+ attestation_digest?: string;
270
+ label: string;
271
+ warnings: string[];
272
+ issues: Array<{
273
+ severity: "error" | "warning";
274
+ code: string;
275
+ message: string;
276
+ }>;
277
+ }
175
278
  export interface PermanenceAnchor {
176
279
  kind: PermanenceAnchorKind;
177
280
  package_digest: string;
@@ -192,7 +295,16 @@ export interface SkillManifest {
192
295
  title: string;
193
296
  description: string;
194
297
  intent?: string;
195
- triggers?: string[];
298
+ /** Authoritative 0.5 semantic contract. Absent only on legacy/draft adapters. */
299
+ contract?: SkillContract;
300
+ triggers?: ContractTrigger[];
301
+ preconditions?: ExplicitDeclaration<ContractPrecondition>;
302
+ branches?: ExplicitDeclaration<ContractBranch>;
303
+ human_decisions?: ExplicitDeclaration<ContractHumanDecision>;
304
+ forbidden_actions?: SkillContract["forbidden_actions"];
305
+ recovery?: ExplicitDeclaration<RecoveryEdge>;
306
+ verification?: ExplicitDeclaration<VerificationAssertion>;
307
+ corrections?: SkillContract["corrections"];
196
308
  authors?: Array<{
197
309
  id: string;
198
310
  display_name?: string;
@@ -217,6 +329,8 @@ export interface SkillManifest {
217
329
  package_sensitivity?: PackageSensitivity;
218
330
  mint?: MintRecord;
219
331
  attestation_digest?: string;
332
+ /** Present on minted packages — binds identity/policy/content claims in the seal. */
333
+ sealed_manifest_digest?: string;
220
334
  anchors?: PermanenceAnchor[];
221
335
  legacy?: boolean;
222
336
  needs_human_review?: boolean;
@@ -331,6 +445,11 @@ export interface Workflow {
331
445
  entrypoint: string;
332
446
  steps: WorkflowStep[];
333
447
  constraints?: SteeringConstraint[];
448
+ preconditions?: ExplicitDeclaration<ContractPrecondition>;
449
+ branches?: ExplicitDeclaration<ContractBranch>;
450
+ human_decisions?: ExplicitDeclaration<ContractHumanDecision>;
451
+ recovery?: ExplicitDeclaration<RecoveryEdge>;
452
+ verification?: ExplicitDeclaration<VerificationAssertion>;
334
453
  }
335
454
  export interface CompilationIssue {
336
455
  severity: "error" | "warning" | "info";
@@ -360,6 +479,8 @@ export interface CompilationReport {
360
479
  pending_approvals: string[];
361
480
  approved: boolean;
362
481
  completeness: CompletenessReport;
482
+ semantic_contract: "native_0.5" | "legacy_lossy";
483
+ losses?: string[];
363
484
  }
364
485
  export interface SkillPackageFiles {
365
486
  manifest: SkillManifest;