diff --git a/packages/cli-workflow/src/__tests__/skill.test.ts b/packages/cli-workflow/src/__tests__/skill.test.ts index 34aa2f5..18d345c 100644 --- a/packages/cli-workflow/src/__tests__/skill.test.ts +++ b/packages/cli-workflow/src/__tests__/skill.test.ts @@ -6,6 +6,7 @@ import { describe, expect, test } from "vitest"; const __dirname = dirname(fileURLToPath(import.meta.url)); import { + cmdSkillActor, cmdSkillArchitecture, cmdSkillCli, cmdSkillList, @@ -21,8 +22,8 @@ describe("skill commands", () => { expect(result).toContain("architecture"); expect(result).toContain("yaml"); expect(result).toContain("moderator"); + expect(result).toContain("actor"); for (const name of result) { - expect(typeof name).toBe("string"); expect(name).toMatch(/^\S+$/); } }); @@ -62,6 +63,15 @@ describe("skill commands", () => { expect(result).toContain("uwf"); }); + test("skill actor returns non-empty markdown string", () => { + const result = cmdSkillActor(); + expect(typeof result).toBe("string"); + expect(result).toContain("frontmatter"); + expect(result).toContain("CAS"); + expect(result).toContain("status"); + expect(result.length).toBeGreaterThan(200); + }); + test("skill help subcommand is suppressed", () => { const output = execFileSync("bun", ["src/cli.ts", "skill", "--help"], { cwd: join(__dirname, "..", ".."), @@ -73,6 +83,7 @@ describe("skill commands", () => { expect(output).toContain("architecture"); expect(output).toContain("yaml"); expect(output).toContain("moderator"); + expect(output).toContain("actor"); expect(output).toContain("list"); }); }); diff --git a/packages/cli-workflow/src/cli.ts b/packages/cli-workflow/src/cli.ts index 16ff419..1f4a9c1 100755 --- a/packages/cli-workflow/src/cli.ts +++ b/packages/cli-workflow/src/cli.ts @@ -17,6 +17,7 @@ import { cmdConfigGet, cmdConfigList, cmdConfigSet } from "./commands/config.js" import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js"; import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js"; import { + cmdSkillActor, cmdSkillArchitecture, cmdSkillCli, cmdSkillList, @@ -503,6 +504,13 @@ skill console.log(cmdSkillYaml()); }); +skill + .command("actor") + .description("Print the actor reference (frontmatter protocol + CAS)") + .action(() => { + console.log(cmdSkillActor()); + }); + skill .command("moderator") .description("Print the moderator reference") diff --git a/packages/cli-workflow/src/commands/skill.ts b/packages/cli-workflow/src/commands/skill.ts index 8a5ddeb..c31ae75 100644 --- a/packages/cli-workflow/src/commands/skill.ts +++ b/packages/cli-workflow/src/commands/skill.ts @@ -1,11 +1,12 @@ export { + generateActorReference as cmdSkillActor, generateArchitectureReference as cmdSkillArchitecture, generateCliReference as cmdSkillCli, generateModeratorReference as cmdSkillModerator, generateYamlReference as cmdSkillYaml, } from "@uncaged/workflow-util"; -const SKILL_NAMES = ["cli", "architecture", "yaml", "moderator"] as const; +const SKILL_NAMES = ["cli", "architecture", "yaml", "moderator", "actor"] as const; export function cmdSkillList(): ReadonlyArray { return [...SKILL_NAMES]; diff --git a/packages/workflow-util/src/actor-reference.ts b/packages/workflow-util/src/actor-reference.ts new file mode 100644 index 0000000..6c80094 --- /dev/null +++ b/packages/workflow-util/src/actor-reference.ts @@ -0,0 +1,68 @@ +export function generateActorReference(): string { + return `# Actor Reference + +You are executing a workflow role. Your system prompt defines your goal, procedure, and output requirements. This reference covers two things you need to know about the workflow engine. + +## 1. Frontmatter Output Protocol + +Your response **MUST** begin with a YAML frontmatter block at byte position 0 — no preamble text before it. + +\`\`\` +--- +status: done +myField: some value +--- + +... markdown body (your work, explanation, notes) ... +\`\`\` + +### Standard Field + +| Field | Values | Default | Description | +|-------|--------|---------|-------------| +| \`status\` | \`done\`, \`needs_input\`, \`in_progress\`, \`failed\` | \`done\` | Completion signal — determines which graph edge the moderator follows next | + +### Schema-Defined Fields + +Your role's output schema (shown in the system prompt under "Deliverable Format") defines additional fields. Output **only** the fields listed there — do not invent extra fields. + +### Body + +Everything after the closing \`---\` fence is the markdown body. Use it for explanations, logs, or human-readable notes. The body is stored but not parsed by the engine. + +### Retry + +If the engine cannot parse your frontmatter, it will ask you to retry (up to 2 times). Just output the corrected frontmatter block — don't panic. + +## 2. CAS (Content-Addressable Store) + +Your frontmatter output is automatically stored in CAS. You can also **use CAS directly** to store intermediate artifacts, build merkle DAGs for large outputs, or reference data from previous steps. + +### Commands + +\`\`\` +uwf cas put-text # store plain text, print hash +uwf cas put # store typed JSON data, print hash +uwf cas get # read a CAS node (type + payload) +uwf cas has # check if a hash exists +uwf cas refs # list direct references from a node +uwf cas walk # recursive traversal from a node +uwf cas schema list # list registered schemas +uwf cas schema get # show a schema definition +\`\`\` + +### Merkle DAG Pattern + +For large outputs, store parts individually and reference their hashes: + +\`\`\`bash +# Store individual sections +HASH1=$(uwf cas put-text "section 1 content") +HASH2=$(uwf cas put-text "section 2 content") + +# Reference hashes in your frontmatter or in a parent node +\`\`\` + +This enables progressive loading — consumers can fetch the root and resolve children on demand. +`; +} diff --git a/packages/workflow-util/src/index.ts b/packages/workflow-util/src/index.ts index 380c195..ec4f277 100644 --- a/packages/workflow-util/src/index.ts +++ b/packages/workflow-util/src/index.ts @@ -1,3 +1,4 @@ +export { generateActorReference } from "./actor-reference.js"; export { generateArchitectureReference } from "./architecture-reference.js"; export { encodeUint64AsCrockford } from "./base32.js"; export { generateCliReference } from "./cli-reference.js";