/schema-author
Design the Zod output schema of a Smithers <Task> as the contract between steps. Use when a step's output feeds a later step (or a branch/loop condition) and must be reliable — design the schema first, keep it minimal, and prefer typed fields over prose so downstream rendering
$ npx -y skills add smithersai/smithers --skill schema-author --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/schema-author
Context preview
The summary Claude sees to decide when to auto-load this skill.
Design the Zod output schema of a Smithers <Task> as the contract between steps. Use when a step's output feeds a later step (or a branch/loop condition) and must be reliable — design the schema first, keep it minimal, and prefer typed fields over prose so downstream rendering
SKILL.md
schema-author.SKILL.mdname: schema-author
description: Design the Zod output schema of a Smithers <Task> as the contract between steps. Use when a step's output feeds a later step (or a branch/loop condition) and must be reliable — design the schema first, keep it minimal, and prefer typed fields over prose so downstream rendering can depend on it.
Schema Author
This skill is about **one thing: the output schema**, the Zod shape a `<Task>` produces and the next step consumes: Smithers's contract between steps. The runtime injects a JSON-schema description into the prompt, parses the response, validates against Zod, retries on mismatch, and persists the row; everything downstream (`ctx.outputMaybe(...)`, `<Branch>`, `<Loop until={...}>`) reads that row. A loose or prose-heavy schema makes every later step unreliable; a tight, typed one makes the graph deterministic.
This is the BAML insight: **the prompt is a schema.** Don't beg the model for JSON in prose: declare the type and let the runtime enforce it, before you write the prompt or the workflow.
When to reach for it
- A step's output feeds a *later* step, a branch condition, or a loop's `until`,
where a wrong shape would silently break the run.
- An agent keeps returning the right *idea* in the wrong *shape* (free text where
you need an enum, missing a field downstream code indexes into).
- You're about to add a reviewer/retry to compensate for output you could just
*type* instead.
Skip it when the output is terminal (nothing downstream reads it): a `summary` string is fine.
Design the contract first, keep it minimal
Author the schema in `createSmithers({...})` *before* the prompt or the graph. Include only what downstream actually reads: a one-line `summary` plus the few fields the next step indexes into. Every extra field is another thing the agent can get wrong and another retry.
const { Workflow, smithers, outputs } = createSmithers({
triage: z.object({
summary: z.string(), // human-readable, terminal
severity: z.enum(["low", "medium", "high"]), // a <Branch> reads this
category: z.enum(["bug", "feature", "question"]), // routes to a specialist
needsHuman: z.boolean(), // gates an <Approval>
}),
});- **Prefer enums and typed fields over prose.** `z.enum([...])`, `z.boolean()`,
`z.number()` give the next step something it can switch on. A free-string status is a bug waiting for a typo.
- **Make required things required.** Optional fields downstream assumes exist
are the classic silent failure: if `fix` always reads `analysis.issues`, don't make `issues` optional.
- **Constrain values, not just types.** `z.number().min(0).max(100)`,
`z.array(...).min(1)`: a validation failure feeds the error back and the agent self-corrects on retry, so tighter bounds are free reliability. Annotate non-obvious fields with `.describe("...")`; that text rides into the injected JSON-schema block and steers the agent.
Wire it: every `<Task>` gets `output={outputs.x}`
The schema is referenced by the typed `outputs.x` handle, which gives compile-time checks (a typo in the key is a type error):
<Task id="triage" output={outputs.triage} agent={analyst}>
{`Triage: ${ctx.input.report}`}
</Task>
{/* downstream reads typed fields — no string parsing, no guessing */}
<Branch
if={ctx.outputMaybe(outputs.triage, { nodeId: "triage" })?.severity === "high"}
then={<Task id="escalate" .../>}
else={<Task id="queue" .../>}
/>The prompt body stays clean: end it with the task, let the runtime append the schema. Don't hand-write a "return JSON like {…}" block: it fights the injected one (see `skills/prompt-author/SKILL.md`).
When a task simply consumes an upstream output with no branching involved, prefer `<Task deps={{ triage: outputs.triage }}>` with a `(deps) => ...` callback: it makes the dependency explicit and needs no `ctx.outputMaybe` guard. `ctx.outputMaybe`/`<Branch>` stays right when downstream logic depends on the row's content, as above.
Rich or extensible outputs: `z.looseObject`
When you can't enumerate every field up front (a typed-extraction step, a payload that carries pass-through metadata, an evolving spec), use `z.looseObject({...})`: name and type the fields downstream *depends on*, and let the agent attach extra keys without tripping validation.
extract: z.looseObject({
title: z.string(),
amount: z.number(), // downstream math reads this
// agent may also return vendor, date, lineItems… — preserved, not rejected
}),Use a strict `z.object` when the shape is a true contract a branch/loop keys off; use `z.looseObject` when richness and forward-compatibility matter more than locking the shape.
Verify the contract holds
Attach a `schemaAdherence` scorer to confirm the shape holds run to run, and read the persisted row:
bunx smthrs scores <run-id> # did adherence hold?
bunx smthrs output <run-id> triage # see the persisted row
See `skills/smithers/SKILL.md` for the runtime/CLI surface and `docs/llms-core.txt` ("The runtime injects a JSON-schema description … validates against Zod") for the exact validate-and-retry mechanics.
Read more
name: schema-author description: Design the Zod output schema of a Smithers <Task> as the contract between steps. Use when a step's output feeds a later step (or a branch/loop condition) and must be reliable — design the schema first, keep it minimal, and prefer typed fields over prose so downstream rendering can depend on it.
Schema Author
This skill is about **one thing: the output schema**, the Zod shape a `<Task>` produces and the next step consumes: Smithers's contract between steps. The runtime injects a JSON-schema description into the prompt, parses the response, validates against Zod, retries on mismatch, and persists the row; everything downstream (`ctx.outputMaybe(...)`, `<Branch>`, `<Loop until={...}>`) reads that row. A loose or prose-heavy schema makes every later step unreliable; a tight, typed one makes the graph deterministic.
This is the BAML insight: **the prompt is a schema.** Don't beg the model for JSON in prose: declare the type and let the runtime enforce it, before you write the prompt or the workflow.
When to reach for it
- A step's output feeds a *later* step, a branch condition, or a loop's `until`,
where a wrong shape would silently break the run.
- An agent keeps returning the right *idea* in the wrong *shape* (free text where
you need an enum, missing a field downstream code indexes into).
- You're about to add a reviewer/retry to compensate for output you could just
*type* instead.
Skip it when the output is terminal (nothing downstream reads it): a `summary` string is fine.
Design the contract first, keep it minimal
Author the schema in `createSmithers({...})` *before* the prompt or the graph. Include only what downstream actually reads: a one-line `summary` plus the few fields the next step indexes into. Every extra field is another thing the agent can get wrong and another retry.
const { Workflow, smithers, outputs } = createSmithers({
triage: z.object({
summary: z.string(), // human-readable, terminal
severity: z.enum(["low", "medium", "high"]), // a <Branch> reads this
category: z.enum(["bug", "feature", "question"]), // routes to a specialist
needsHuman: z.boolean(), // gates an <Approval>
}),
});- **Prefer enums and typed fields over prose.** `z.enum([...])`, `z.boolean()`,
`z.number()` give the next step something it can switch on. A free-string status is a bug waiting for a typo.
- **Make required things required.** Optional fields downstream assumes exist
are the classic silent failure: if `fix` always reads `analysis.issues`, don't make `issues` optional.
- **Constrain values, not just types.** `z.number().min(0).max(100)`,
`z.array(...).min(1)`: a validation failure feeds the error back and the agent self-corrects on retry, so tighter bounds are free reliability. Annotate non-obvious fields with `.describe("...")`; that text rides into the injected JSON-schema block and steers the agent.
Wire it: every `<Task>` gets `output={outputs.x}`
The schema is referenced by the typed `outputs.x` handle, which gives compile-time checks (a typo in the key is a type error):
<Task id="triage" output={outputs.triage} agent={analyst}>
{`Triage: ${ctx.input.report}`}
</Task>
{/* downstream reads typed fields — no string parsing, no guessing */}
<Branch
if={ctx.outputMaybe(outputs.triage, { nodeId: "triage" })?.severity === "high"}
then={<Task id="escalate" .../>}
else={<Task id="queue" .../>}
/>The prompt body stays clean: end it with the task, let the runtime append the schema. Don't hand-write a "return JSON like {…}" block: it fights the injected one (see `skills/prompt-author/SKILL.md`).
When a task simply consumes an upstream output with no branching involved, prefer `<Task deps={{ triage: outputs.triage }}>` with a `(deps) => ...` callback: it makes the dependency explicit and needs no `ctx.outputMaybe` guard. `ctx.outputMaybe`/`<Branch>` stays right when downstream logic depends on the row's content, as above.
Rich or extensible outputs: `z.looseObject`
When you can't enumerate every field up front (a typed-extraction step, a payload that carries pass-through metadata, an evolving spec), use `z.looseObject({...})`: name and type the fields downstream *depends on*, and let the agent attach extra keys without tripping validation.
extract: z.looseObject({
title: z.string(),
amount: z.number(), // downstream math reads this
// agent may also return vendor, date, lineItems… — preserved, not rejected
}),Use a strict `z.object` when the shape is a true contract a branch/loop keys off; use `z.looseObject` when richness and forward-compatibility matter more than locking the shape.
Verify the contract holds
Attach a `schemaAdherence` scorer to confirm the shape holds run to run, and read the persisted row:
bunx smthrs scores <run-id> # did adherence hold? bunx smthrs output <run-id> triage # see the persisted row
See `skills/smithers/SKILL.md` for the runtime/CLI surface and `docs/llms-core.txt` ("The runtime injects a JSON-schema description … validates against Zod") for the exact validate-and-retry mechanics.
Agent workflows you can watch live, rewind, fork, and replay. Tell your coding agent to do real, multi-step work, then Smithers runs it for minutes or days: watch every step live, gate the risky ones behind human approvals, and rewind, fork, or replay any run.
Repo: smithersai/smithers
Other skills on smithers.
- /orchestrate
Drive Smithers — a durable control plane for long-running coding agents — from inside Hermes. Use for any multi-step, long-running, crash-safe, or human-in-the-loop work: "run a workflow", "implement and review", "keep iterating until tests pass", "plan then build". You are the
Open skill - /orchestrate
Drive Smithers durable workflows from OpenClaw. Use for multi-step, long-running, background, human-in-the-loop, retryable, or repeatable work. Prefer creating or improving a Smithers workflow over repeating ad-hoc agent turns, and use evals plus optimization to improve
Open skill - /smithers
Drive Smithers, a durable control plane for long-running coding agents, from Claude Code. Use when the user wants multi-step, long-running, crash-safe, or human-in-the-loop agent work ('orchestrate agents', 'run a workflow', 'implement this and review it', 'keep iterating until
Open skill - /smithers
Drive Smithers, a durable control plane for long-running coding agents, from Codex. Use when the user wants multi-step, long-running, crash-safe, or human-in-the-loop agent work ("orchestrate agents", "run a workflow", "implement this and review it", "keep iterating until tests
Open skill - /context-engineer
The concierge proxy — turn a vague user script ("I need the agent to help me do X") into a context contract, route it to the right skills/workflows, add backpressure (tests/evals/reviews/approvals), execute, and report. Use when a request is multi-step, durable, or
Open skill - /eval-driven-development
How this repo does eval-driven development (EDD) for Smithers workflows — write the failing suite first, build until green, validate on a holdout, then optimize. Use when adding evals to a workflow, changing a prompt/model/graph that has a suite, setting up a dev/holdout split,
Open skill

