/** * Typed Claude Code authoring surface — the compile-time half of the purity * contract, bound to the Claude Code tool vocabulary. * * The core `experimental_agent()` / `skill()` builders (`vigiles/spec`) are generic over a * tool `ToolVocabulary` that DEFAULTS to fully-open (`string` at every purity * level), so they accept any tools — backwards-compatible, harness-agnostic. * This module re-binds them to the CONCRETE Claude Code vocabulary derived from * `claudeCodeDialect`, so authoring a spec with an invalid `purity`×`tools` * combination is a `tsc` error at EDIT TIME, before any vigiles command runs: * * import { experimental_agent } from "vigiles/claude-code"; * * experimental_agent({ purity: "pure", tools: ["Read", "Bash"] }); * // ^^^^^^ tsc error — Bash side-effecting * * experimental_agent({ purity: "bounded", tools: ["Read", "Bash", "Write"] }); // OK * experimental_agent({ purity: "bounded", tools: ["mcp__x__y"] }); * // ^^^^^^^^^^^ tsc error — MCP not decidable * * experimental_agent({ tools: ["anything", "mcp__x__y"] }); // no purity → open, OK * * This is a STRICT ADDITION to the runtime/compile checks: `purityViolations` * (`vigiles compile`) and `decidePurityGate` (the PreToolUse gate) are unchanged * and remain the universal backstop. In particular the command-level decision a * `bounded` unit makes for `Bash` (read-only command allowed, mutating denied) * is the RUNTIME gate's job — the type only admits the `Bash` TOOL at `bounded`. * * The CC literal tool names live ONLY in this adapter (and the dialect it reads * from), never in core — the hexagonal boundary that keeps the domain * harness-agnostic. */ import { type AgentSpec, type AgentSpecInput, type SkillSpec, type SkillSpecInput, type AuthoredPurity, type ToolVocabulary } from "../../core/spec.js"; import type { ClaudeCodeReadOnlyTool, ClaudeCodeBoundedTool } from "./dialect.js"; /** * The Claude Code tool vocabulary, split by the purity floor that admits each * tool (mirrors the runtime ladder in `core/effects.ts`): * - `readOnly`: tools a `pure` unit may declare (Read/Grep/Glob/LS). * - `bounded`: read-only ∪ Write/Edit/MultiEdit/NotebookEdit ∪ `Bash`. */ export interface ClaudeCodeToolVocabulary extends ToolVocabulary { readonly readOnly: ClaudeCodeReadOnlyTool; readonly bounded: ClaudeCodeBoundedTool; } /** * Define a Claude Code subagent with the purity floor enforced AT COMPILE TIME * against the Claude Code tool catalog. Identical to the core `experimental_agent()` at * runtime (it IS the core builder); the only difference is the typed `tools` * constraint. `P` is inferred from the literal `purity` field. */ declare function agentSpec(spec: AgentSpecInput): AgentSpec; /** * The Claude Code subagent root. Carries the SAME vocabulary members as the core * builder, and it must: they stopped being standalone exports when the vocabulary * moved onto the root, so an author who picked this door would otherwise have no * way to reach them — the same asymmetry `experimental_skill.input()` closed. * * @experimental */ export declare const experimental_agent: typeof agentSpec & { result: (ok: Ok, err: Err) => import("../../core/spec.js").OutputContract; delegate: (agent: string, task?: string, needsContract?: import("../../core/spec.js").Shape) => import("../../core/spec.js").RailwayStep; railway: (spec: Omit) => import("../../core/spec.js").Railway; needs: (shape: N) => import("../../core/spec.js").NeedsContract; pipeStep: (a: import("../../core/spec.js").TypedAgentSpec, needsContract?: Needs) => import("../../core/spec.js").PipeStep; start: (first: import("../../core/spec.js").PipeStep, Ok, Err> | import("../../core/spec.js").TypedAgentSpec) => import("../../core/spec.js").Pipeline; andThen: (prior: import("../../core/spec.js").Pipeline, next: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }) => import("../../core/spec.js").Pipeline; pipe: { (a: import("../../core/spec.js").TypedAgentSpec): import("../../core/spec.js").Pipeline; (a: import("../../core/spec.js").TypedAgentSpec, b: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }): import("../../core/spec.js").Pipeline; (a: import("../../core/spec.js").TypedAgentSpec, b: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }, c: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }): import("../../core/spec.js").Pipeline; (a: import("../../core/spec.js").TypedAgentSpec, b: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }, c: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }, d: import("../../core/spec.js").Supplies extends true ? import("../../core/spec.js").PipeStep : { readonly __HANDOFF_ERROR: import("../../core/spec.js").Supplies; }): import("../../core/spec.js").Pipeline; }; }; /** * Define a Claude Code skill with the purity floor enforced AT COMPILE TIME * against the Claude Code tool catalog. Identical to the core * `experimental_skill()` at runtime; the typed `tools` constraint is the only * difference. * * Carries the same `.input` / `.step` helpers as the core builder, and it must: * those two stopped being standalone exports when the helper vocabulary moved * onto the skill builder, so an author who picked this door would otherwise have * no way to reach them. Before the move they came from `vigiles/spec` — a second * import for one skill, which is the asymmetry this closes rather than a cost it * introduces. * * @experimental */ declare function skillSpec(spec: SkillSpecInput): SkillSpec; /** * @experimental */ export declare const experimental_skill: typeof skillSpec & { input: (name: string, hint: string, opts?: { required?: boolean; }) => import("../../core/spec.js").SkillInput; step: (instr: string | import("../../core/spec.js").InstructionFragment[], opts?: { gate?: import("../../core/spec.js").Gate; retry?: number; }) => import("../../core/spec.js").SkillStep; }; export {}; //# sourceMappingURL=typed-spec.d.ts.map