feat(skill): add architecture, yaml, moderator, list subcommands (#517)

This commit is contained in:
2026-05-25 22:42:05 +08:00
parent 8123399189
commit 108f134020
7 changed files with 311 additions and 1 deletions
@@ -0,0 +1,60 @@
export function generateArchitectureReference(): string {
return `# Workflow Engine — Architecture Reference
## Key Concepts
### CAS (Content-Addressed Storage)
Every artifact in the workflow engine is stored as a CAS node — an immutable, content-addressed record identified by its XXH64 hash (13-char Crockford Base32). CAS provides deduplication, integrity verification, and an append-only audit trail.
Stored artifacts include:
- **Workflow definitions** — the YAML-parsed payload
- **Step nodes** — each moderator→agent→extract cycle
- **Detail nodes** — per-step metadata and turn history
- **Turn records** — individual agent interactions within a step
### Thread
A Thread is a single execution of a Workflow, identified by a ULID (26-char Crockford Base32: 10 timestamp + 16 random). Thread state is an immutable CAS chain — each step points to its predecessor via a \`prev\` hash, forming a linked list.
Active threads are indexed in \`threads.yaml\`; completed threads move to \`history.jsonl\`.
A thread progresses by running \`uwf thread exec\`, which performs one moderator→agent→extract cycle per step.
### Workflow
A Workflow is a YAML definition (\`WorkflowPayload\`) stored as a CAS node. It defines:
- **Roles** — named actors with system prompts and output schemas
- **Graph** — status-based routing edges between roles
- **Conditions** — edge predicates evaluated by the moderator
Workflow names follow verb-first kebab-case: \`solve-issue\`, \`review-code\`.
### Step
A Step is one moderator→agent→extract cycle, stored as a CAS node (\`StepNodePayload\`). Each step contains:
- **output** — the agent's extracted frontmatter output
- **detail** — a CAS reference to turn-level records
- **prev** — CAS hash of the previous step (forming the chain)
- **role** — which role produced this step
### Turn
A Turn is an agent-internal interaction within a single Step. Turns are stored per-turn in the detail node, capturing the raw agent I/O before extraction.
## Data Flow
\`\`\`
uwf thread exec <thread-id>
→ Moderator evaluates graph edges based on current status
→ Selects next role (or $END)
→ Agent CLI is spawned with context
→ Agent produces frontmatter markdown
→ Extract pipeline parses output into structured data
→ New CAS step node is appended to the thread chain
\`\`\`
## Storage Layout
All data lives under \`~/.uncaged/workflow/\`:
- \`cas/\` — content-addressed store (XXH64-keyed)
- \`threads.yaml\` — active thread index
- \`history.jsonl\` — completed thread archive
- \`registry.yaml\` — workflow name → CAS hash mapping
`;
}
+3
View File
@@ -1,5 +1,8 @@
export { encodeUint64AsCrockford } from "./base32.js";
export { generateArchitectureReference } from "./architecture-reference.js";
export { generateCliReference } from "./cli-reference.js";
export { generateModeratorReference } from "./moderator-reference.js";
export { generateYamlReference } from "./yaml-reference.js";
export { env } from "./env.js";
export type {
AgentFrontmatter,
@@ -0,0 +1,64 @@
export function generateModeratorReference(): string {
return `# Moderator Reference
## Overview
The moderator is the workflow engine's routing component. It evaluates the directed graph defined in the workflow YAML to determine the next role (or \`$END\`) after each step — with zero LLM cost.
## Status-Based Routing
The moderator uses **status-based routing**: it inspects the previous step's extracted output (specifically the \`$status\` field and other output fields) and matches them against edge conditions in the graph.
### Routing Algorithm
1. Find all edges where \`from\` matches the current role
2. For each edge (in order), evaluate the \`when\` condition:
- If \`when\` is absent → unconditional match (always taken)
- If \`when\` is present → every key/value pair must match the step output
3. The first matching edge determines the next role
4. If no edge matches → thread stalls (error condition)
### Example
\`\`\`yaml
graph:
- from: developer
to: reviewer
when:
$status: done
- from: developer
to: $END
when:
$status: failed
- from: reviewer
to: developer
when:
$status: needs-changes
- from: reviewer
to: $END
when:
$status: approved
\`\`\`
In this graph:
- After \`developer\` produces \`$status: done\`, the moderator routes to \`reviewer\`
- After \`reviewer\` produces \`$status: needs-changes\`, it routes back to \`developer\`
- \`$status: failed\` or \`$status: approved\` terminates the thread
## Edge Evaluation Details
- Edges are evaluated **in declaration order** — put specific conditions before general ones
- \`when\` values are compared as **exact string matches**
- Multiple \`when\` fields are ANDed — all must match
- An edge without \`when\` acts as a **fallback** — place it last
## Integration with Steps
Each \`uwf thread exec\` cycle:
1. Moderator reads the thread's head step output
2. Evaluates graph edges to pick the next role
3. If next is \`$END\`, marks thread as completed
4. Otherwise, spawns the agent for the selected role
5. Extract pipeline parses agent output → new step node → append to CAS chain
`;
}
@@ -0,0 +1,73 @@
export function generateYamlReference(): string {
return `# Workflow YAML Schema Reference
## Top-Level Structure
A workflow YAML file defines the complete workflow specification:
\`\`\`yaml
name: solve-issue # verb-first kebab-case identifier
description: "..." # human-readable description
roles: # named actors in the workflow
planner:
system: | # system prompt for the agent
You are a planner...
outputSchema: # JSON Schema for structured output
type: object
required: [plan, $status]
properties:
plan:
type: string
$status:
type: string
enum: [ready, failed]
graph: # status-based routing edges
- from: $START
to: planner
- from: planner
to: developer
when:
$status: ready
- from: planner
to: $END
when:
$status: failed
\`\`\`
## roles
Each role defines an actor in the workflow:
| Field | Type | Description |
|-------|------|-------------|
| \`system\` | string | System prompt — instructions for the agent |
| \`outputSchema\` | JSON Schema | Defines the structured output the agent must produce |
| \`agent\` | string (optional) | Override the default agent command for this role |
### outputSchema
The \`outputSchema\` is a standard JSON Schema object. The extract pipeline validates agent output against it. Key conventions:
- \`$status\` field drives routing decisions in the graph
- Use \`enum\` to constrain status values
- All required fields must appear in the agent's frontmatter output
## graph
The graph is an array of directed edges defining status-based routing:
| Field | Type | Description |
|-------|------|-------------|
| \`from\` | string | Source role name, or \`$START\` |
| \`to\` | string | Target role name, or \`$END\` |
| \`when\` | object | Condition map — field/value pairs to match against previous output |
### Special Nodes
- \`$START\` — entry point, must have exactly one outgoing edge
- \`$END\` — terminal node, thread completes when reached
### Edge Evaluation
Edges are evaluated in order. The first edge whose \`when\` condition matches the current step output is selected. If no \`when\` is specified, the edge is unconditional (always matches).
`;
}