| name | modifying-cli-output-schema |
| description | Adding or modifying Golem CLI structured output types, CliOutput implementations, command-output.schema.json, or DTO-backed output schema generators. |
Modifying CLI Output Schema
Use this skill when changing structured output from golem-cli, including:
- adding or modifying a
CliOutput implementation;
- changing a DTO/view used by structured CLI output;
- editing
cli/golem-cli/command-output-schema/command-output.schema.json;
- changing schema tests or arbitrary generators in
cli/golem-cli/src/model/cli_output.rs.
This is different from the application manifest schema under
cli/schema.golem.cloud/app/golem/. For manifest schema version changes, use
modifying-cli-manifest-schema instead.
Core Rules
- Keep the public
$type discriminator model. Every structured output document
must have the right stable $type value.
$type values are stable semantic output identifiers. Prefer command-like
names when there is a direct command correspondence (for example
agent.invoke or component.manifest-trace). For streaming outputs, use
the command family plus the streamed resource or event type (for example
agent.stream for stream events and agent.oplog for oplog entries). Use
domain/subdocument names when the output is part of a larger command flow
(for example deploy.diff). Do not add redundant .result or .event
suffixes.
- Keep machine-readable structured output on stdout and human logs, prompts,
progress, and diagnostics on stderr.
- Prefer typed schema definitions over
JsonValue. Use generic JSON only when
the payload is semantically arbitrary or cannot be related in JSON Schema
draft-07.
- Match serde's actual serialized shape, not the Rust type shape you expect.
Tagged enums, flattened enum payloads, skipped fields, and custom serializers
are common drift sources.
- For exact object schemas, set
additionalProperties: false and keep
required entries aligned with properties.
- Every top-level output definition listed in
x-golem-cli-output-types must
include description, x-golem-output-mode, and x-golem-command metadata.
Use x-golem-output-mode: "single" for normal one-document commands and
"stream" for commands that emit one document per event or entry. Use
"multi-document" for finite command-bounded outputs where multiple $types
may appear conditionally during one command run. Use x-golem-command for
the primary or representative emitting command, and add x-golem-commands
when an output type is emitted by multiple public commands.
Important Files
cli/golem-cli/command-output-schema/command-output.schema.json — public
handwritten CLI output schema.
cli/golem-cli/src/model/cli_output.rs — CliOutput registry checks,
schema tests, and DTO-backed arbitrary generators.
cli/golem-cli/src/model/text/** — many structured output view types.
cli/golem-cli/src/model/** — CLI DTO/view models used by structured output.
golem output-schema — top-level command that prints the raw schema document
for automated agents and tooling. --types prints only output type names;
repeated --type <TYPE> prints a pruned schema containing only selected
output definitions and recursively referenced definitions.
Makefile.toml — check-cli-output-schema and
update-cli-output-schema-summary tasks.
Generator Rules
Property-based schema examples should construct real Rust DTO/view values and
serialize them through to_cli_output_value.
Do not hand-build full output JSON documents in generators. Hand-built JSON is
acceptable only for:
- minimal negative schema tests;
- intentionally arbitrary
serde_json::Value leaves;
- small helper payloads that are themselves semantically JSON values.
When schema coverage is expanded, expand the generator too. The generator should
exercise meaningful variants and nested shapes, not just the empty/default case.
If a generator reveals schema drift, inspect the serialized DTO and fix the
schema or the DTO intentionally.
Accepted Generic JSON Leaves
These generic areas are intentional unless the task explicitly says otherwise:
ValueAndTypeJson.value: draft-07 cannot validate it relationally against
sibling typ.
AgentConfigEntryDto.value: this is NormalizedJsonValue and is semantically
arbitrary JSON.
- Manifest config JSON leaves inside typed manifest trace output.
- Snapshot JSON payload leaves inside typed
agent.oplog entries.
- Raw/default/display secret values: valid shape depends on secret type and
display context.
Oplog Coverage
agent.oplog uses the public oplog DTOs (PublicOplogEntry and nested public
types) from golem-common. The CLI output schema models the public oplog entry
union explicitly, and the output generator builds a single AgentOplogView
sample containing all public oplog variants plus nested invocation, snapshot,
retry policy, span, plugin, and update shapes.
When changing public oplog entries, update both the PublicOplogEntry schema
family and the deterministic oplog sample in cli_output.rs. Keep
ValueAndTypeJson.value and JSON snapshot payload leaves generic unless custom
relational validation is introduced.
Workflow
- Identify the affected output kind and
CliOutput type.
- Update the Rust DTO/view model if needed.
- Update
command-output.schema.json to match actual serde output.
- Add or update top-level output metadata (
description,
x-golem-output-mode, x-golem-command, and optionally
x-golem-commands) for affected schema definitions.
- Add or improve the generator in
cli_output.rs using real DTO/view values.
- Run focused schema tests and inspect failures as DTO/schema drift.
- Check whether user-facing skills under
golem-skills/skills need updates
when CLI output field names, $type names, or examples change.
- Check whether
golem-skills/tests needs updates when output field names,
$type names, JSON formatting, or invoke JSON unwrapping changes.
- Verify
golem output-schema still prints the current raw schema document,
golem output-schema --types lists compact type names, and focused schemas
such as golem output-schema --type agent.invoke remain valid and pruned.
- Regenerate the local output summary when the registry or output types change.
User-Facing Skill Impact
CLI structured output changes can make embedded user-facing skills stale. Always
search golem-skills/skills when changing:
- machine-readable CLI field names, such as
resultJson / resultsJson;
$type naming conventions;
- examples showing
--format json, --format yaml, or structured output;
- command names or flags used in skill instructions.
If any files under golem-skills/skills change, regenerate the generated How-To
Guide docs before finishing:
cargo make generate-docs-skills
CI rejects drift via cargo make check-docs-skills.
Golem Skill Harness Impact
CLI structured output changes can break generated-application skill tests under
golem-skills/tests, especially the harness code that invokes golem-cli and
unwraps JSON output.
When public CLI output changes, inspect and update affected files under:
golem-skills/tests/harness/src/;
golem-skills/tests/harness/tests/;
golem-skills/tests/harness/scenarios/.
The full scenario suite can require credentials, services, and significant time,
and is normally run later in PR/CI. Locally, run focused harness unit/build
checks only when harness TypeScript code or fixtures changed:
cd golem-skills/tests/harness
npm run build
npm test
Validation
Run these for CLI output schema/generator changes:
cargo fmt --package golem-cli
cargo test -p golem-cli cli_output_schema_ --lib
cargo make check-cli-output-schema
cargo make update-cli-output-schema-summary
cargo check -p golem-cli
Smoke-check schema exposure when the command or schema file changed:
cargo run -p golem-cli -- output-schema
cargo run -p golem-cli -- output-schema --types
cargo run -p golem-cli -- output-schema --type agent.invoke
If arbitrary generators changed, rerun the generated-example prop test a few
times:
cargo test -p golem-cli cli_output_schema_accepts_registered_generated_examples --lib
Remove transient cli/golem-cli/proptest-regressions/ files created by failing
local generator runs unless the project intentionally wants to commit that
regression seed.
Common Drift Sources
- Nullable fields that are
Option<T> in DTOs but schema forgot null.
- Enum case casing (
kebab-case, camelCase, or Rust variant names).
- Internally tagged enum payloads that flatten fields into the same object.
- Custom serializers such as manifest trace
appliedLayers.
skip_serializing_if fields that should not be required.
- New nested DTO variants not covered by generators.
EnvironmentSetupPlanView serializes the precomputed EnvironmentSetupPlan.display.
That display must be constructed with the active MaskingConfig; do not build
this view from unmasked environment setup display data.
Checklist
$type is stable and registered in both source and schema.
$type is suffixless and semantically named; it is command-like when that is
accurate, but not assumed to be a literal CLI command path.
- Schema matches actual
serde_json::to_value output.
- Top-level schema definition has
description, x-golem-output-mode, and
x-golem-command metadata; reused types have x-golem-commands when useful.
- Output generator constructs real DTO/view values.
- Important enum and nested variants are covered by examples or generators.
- User-facing skills under
golem-skills/skills have been checked when public
output changed.
golem-skills/tests impact has been checked when public output changed.
- Generated docs from user-facing skills were regenerated if
golem-skills/skills
changed.
golem output-schema prints the current raw schema document.
golem output-schema --types and --type <TYPE> expose compact discovery
and pruned schemas for coding agents.
- Remaining
JsonValue leaves are documented and intentional.
- Focused schema tests, check task, summary update, and
cargo check -p golem-cli pass.