10 KiB
wf schema Command Design
Status
Approved design for implementation planning.
Purpose
wf schema gives human and machine clients a public discovery surface for the
workflow document models accepted by the product. It should cover draft, raw
plan, core workflow, and referenced component shapes without requiring agents
to inspect tests or implementation code.
The command has two output levels:
- a compact machine-readable outline by default;
- a complete valid JSON Schema document with
--verbose.
Goals
- Cover every schema definition reachable from workflow draft, raw plan, and core workflow roots.
- Keep default output compact enough for agent context windows.
- Keep all output valid JSON.
- Make verbose output a valid, self-contained JSON Schema document.
- Provide discoverable aliases for the common root models.
- Fail clearly and nonzero for unknown schema names.
- Avoid adding runtime dependencies for trivial in-process caching.
Non-Goals
- Building a general-purpose JSON Schema browser.
- Searching arbitrary source-code models outside the workflow document domain.
- Producing Python source declarations or generated Pydantic models.
- Replacing command-specific help, validation diagnostics, or workflow docs.
- Guaranteeing that compact outlines preserve every JSON Schema keyword.
Command Surface
wf schema
wf schema list
wf schema draft
wf schema raw
wf schema core
wf schema WorkflowDraft
wf schema RawWorkflowPlan
wf schema NodeUse
wf schema InputPathBinding
wf schema raw --verbose
wf schema NodeUse --verbose
wf schema with no argument is equivalent to wf schema list.
The command remains a single Typer command with an optional positional name.
draft, raw, and core are aliases, not subcommands.
Root Models And Aliases
| Alias | Canonical model | Purpose |
|---|---|---|
draft |
WorkflowDraft |
Patch-friendly draft workspace document |
raw |
RawWorkflowPlan |
Raw graph accepted by artifact creation |
core |
Workflow |
Canonical core workflow graph |
Canonical names are also accepted directly. Definitions exposed through the combined root schemas are queryable by their exact canonical names.
Schema Catalog
The implementation builds one cached catalog from:
TypeAdapter(WorkflowDraft).json_schema();TypeAdapter(RawWorkflowPlan).json_schema();TypeAdapter(Workflow).json_schema().
The catalog records:
- canonical root schemas;
- aliases;
- every reachable
$defsentry; - description/title metadata;
- which roots reference each definition.
Use functools.cache for catalog construction. The CLI process is short-lived;
a TTL cache and the cachetools dependency provide no useful behavior.
Pydantic's TypeAdapter.json_schema() remains the authority for schema
generation. Do not reimplement model-to-JSON-Schema conversion, discriminated
unions, aliases, defaults, validation constraints, or reference construction.
Use the existing jsonschema package to validate emitted full schemas. Custom
code is limited to catalog indexing, collision checks, and the explicitly
non-validating compact presentation layer.
If two roots expose different definitions with the same canonical name, catalog construction must fail with a clear internal error rather than silently choose one. Structurally identical definitions may be deduplicated.
List Output
wf schema and wf schema list emit JSON:
{
"schemas": [
{
"name": "NodeUse",
"aliases": [],
"kind": "definition",
"description": "Concrete use of a reusable node definition."
},
{
"name": "WorkflowDraft",
"aliases": ["draft"],
"kind": "root",
"description": "Patch-friendly JSON authoring document."
}
]
}
Entries are sorted by canonical name. Search/filtering is deferred until real catalog size or usage demonstrates a need.
Compact Outline Output
The default named-schema output is a JSON schema outline, not a JSON Schema
document. It must label itself accordingly and must not emit dangling $ref
values.
Example:
{
"name": "RawWorkflowPlan",
"kind": "schema_outline",
"type": "object",
"description": "Raw authoring plan using core graph models.",
"required": [
"name",
"input_schema",
"state_schema",
"output_schema",
"start",
"nodes",
"edges"
],
"properties": {
"name": {"type": "string"},
"start": {"type": "string"},
"nodes": {
"type": "array",
"items": {
"one_of": [
"NodeUse",
"SubgraphNode",
"ConditionNode",
"ForeachNode",
"EndNode",
"InterruptNode"
]
}
},
"edges": {"type": "array", "items": "Edge"}
},
"related": ["Edge", "NodeUse", "OutputBinding"],
"full_schema_command": "wf schema raw --verbose"
}
Outline Projection Rules
- Preserve
name,title,description, objectrequired, defaults, enums, constants, and basic validation bounds when present. - Preserve object property names.
- Convert local
$refvalues to canonical definition-name strings. - Convert
oneOfreference unions toone_ofandanyOfreference unions toany_ofwhen branches are named references. - Preserve simple inline primitive unions in compact JSON form.
- For arrays, summarize the item schema recursively.
- Add a sorted
relatedlist containing definitions referenced by the outline. - Do not recursively inline referenced definitions; callers can query them by name.
- Do not claim the outline is directly accepted as a validation schema.
The projection should be deterministic so snapshots and prompt provenance are stable across runs when source models do not change.
Verbose JSON Schema Output
wf schema <name> --verbose emits a complete, self-contained JSON Schema
document through the existing wf_cli.io.emit_json helper.
For root aliases/canonical root names, emit the complete Pydantic-generated root
schema with its $defs table.
For a component definition such as NodeUse, emit a valid root document:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$ref": "#/$defs/NodeUse",
"$defs": {
"NodeUse": {"type": "object", "properties": {"node": {"type": "string"}}},
"InputPathBinding": {"type": "object", "properties": {"path": {"type": "string"}}},
"InputValueBinding": {"type": "object", "properties": {"value": true}},
"OutputBinding": {"type": "object", "properties": {"to": {"type": "string"}}}
}
}
The short $defs bodies above are representative excerpts, not complete
runtime output. The real $defs table contains the full combined
Pydantic-generated definition catalog. Do not hand-roll transitive reference
pruning or JSON Schema reference resolution in the first implementation. The
larger verbose payload is an acceptable tradeoff for correctness; --verbose
is explicitly the unbounded form.
All verbose documents must pass Draft202012Validator.check_schema() and a
validator-backed local-reference resolution test.
Output And Errors
- Use
emit_json; never pass dictionaries directly totyper.echo. - Unknown names raise
typer.BadParameterand exit nonzero. - Unknown-name messages include close canonical/alias matches when available,
using the standard library
difflib.get_close_matches. - Missing names list the catalog rather than showing an empty command group.
- Internal catalog collisions or malformed generated schemas fail loudly with actionable errors.
--verboseapplies to both aliases and canonical names.
Example error:
Invalid value: unknown schema 'Node'. Did you mean 'NodeUse'?
Help Text
Help must describe the real single-command shape:
Usage: wf schema [OPTIONS] [NAME]
Print a compact workflow schema outline, or a full JSON Schema with --verbose.
Use `wf schema` or `wf schema list` to discover available names.
Common aliases: draft, raw, core.
Do not call aliases convenience subcommands.
Skills And Documentation
Update user-facing agent instructions so they use public discovery surfaces in this order:
wf schemato list available workflow document shapes;wf schema draftorwf schema rawfor compact guidance;wf schema <definition>for component details;--verboseonly when a complete validation schema is necessary;- workflow validation commands to check an authored document.
Remove the stale statement that wf schema is an empty WIP group. Keep test and
implementation file paths out of user-facing skills.
Tests
Focused CLI tests must cover:
wf schemaandwf schema listreturn the same sorted catalog;- catalog output is valid JSON and includes roots, aliases, and components;
- aliases and canonical root names resolve to the same model;
- compact output is valid JSON and contains no
$refkeys; - compact references are represented by queryable canonical names;
- verbose root output passes JSON Schema validation;
- verbose component output has no unresolved local
$refvalues; --verboseworks for aliases and canonical component names;- unknown names exit nonzero and offer a close-match suggestion;
- help text describes aliases rather than subcommands;
- the removed WIP help assertions are replaced with behavioral tests.
Run focused verification against the schema command and existing CLI app tests, then run Ruff and basedpyright on modified files.
Migration
The current uncommitted prototype is replaced rather than preserved:
- remove
cachetoolsfrom runtime dependencies and the lockfile; - remove TTL caches;
- replace
_sonset_sandstormwith explicit catalog helpers; - replace Python-repr output with JSON;
- replace detached
$defsfragments with compact outlines; - update stale CLI tests and skills.
No compatibility behavior is required because the previous wf schema surface
was explicitly an empty work-in-progress group and the prototype has not been
released as a documented contract.
Acceptance Criteria
- Agents can discover all supported workflow schema names without reading code.
- Default output is compact, deterministic, valid JSON, and has no dangling references.
--verboseoutput is valid, self-contained JSON Schema.- Unknown names fail nonzero.
- No new runtime dependency is needed.
- Focused CLI tests, Ruff, and basedpyright pass.
- User-facing skills direct agents to
wf schemainstead of tests or source.