# Modifying CLI Output Schema

> Adding or modifying Golem CLI StructuredOutput implementations, command-output.schema.json, or DTO-backed output schema generators.

- Skill: `golemcloud/modifying-cli-output-schema` (Agent Skill)
- Install (CLI): `npx skillmds@latest add golemcloud/modifying-cli-output-schema`
- Raw SKILL.md: https://api.skillmd.com/api/skills/golemcloud/modifying-cli-output-schema/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: golemcloud (https://skillmd.com/u/golemcloud)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/golemcloud/modifying-cli-output-schema

---


# Modifying CLI Output Schema

Use this skill when changing structured output from `golem-cli`, including:

- adding or modifying a `StructuredOutput` 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 under `cli/golem-cli/src/model/cli_output/`.

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

1. Keep the public `$type` discriminator model. Every structured output document
   must have the right `$type` value for the current contract.
2. `$type` values are 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. If a contract intentionally changes a `$type`, update every in-tree
   consumer directly; do not preserve the old value through aliases or duplicate output variants.
3. Keep machine-readable structured output on stdout and human logs, prompts,
   progress, and diagnostics on stderr.
4. 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.
5. 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.
6. For exact object schemas, set `additionalProperties: false` and keep
   `required` entries aligned with `properties`.
7. 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 `$type`s
   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/mod.rs` — `StructuredOutput`, schema loading, focused-schema
  support, and serialization helpers.
- `cli/golem-cli/src/model/cli_output/tests.rs` — 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_structured_output_value` or
`to_structured_output_value_masked` when the output contains maskable data.

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 `AgentOplogEntryView`
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 `AgentOplogEntryView` sample in `cli_output/tests.rs`. Keep
`ValueAndTypeJson.value` and JSON snapshot payload leaves generic unless custom
relational validation is introduced.

## Workflow

1. Identify the affected output kind and `StructuredOutput` type.
2. Update the Rust DTO/view model if needed.
3. Update `command-output.schema.json` to match actual serde output.
4. Add or update top-level output metadata (`description`,
   `x-golem-output-mode`, `x-golem-command`, and optionally
   `x-golem-commands`) for affected schema definitions.
5. Add or improve the generator in `cli_output/tests.rs` using real DTO/view values.
6. Run focused schema tests and inspect failures as DTO/schema drift.
7. Check whether user-facing skills under `golem-skills/skills` need updates
   when CLI output field names, `$type` names, or examples change.
8. Check whether `golem-skills/tests` needs updates when output field names,
   `$type` names, JSON formatting, or invoke JSON unwrapping changes.
9. 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.
10. 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:

```shell
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:

```shell
cd golem-skills/tests/harness
npm run build
npm test
```

## Validation

Run these for CLI output schema/generator changes:

```shell
cargo fmt --package golem-cli -- --check
cargo test -p golem-cli cli_output_schema_ --lib -- --report-time
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:

```shell
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:

```shell
cargo test -p golem-cli cli_output_schema_accepts_registered_generated_examples --lib -- --report-time
```

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

1. `$type` is registered in both source and schema and matches the current contract.
2. `$type` is suffixless and semantically named; it is command-like when that is
   accurate, but not assumed to be a literal CLI command path.
3. Schema matches actual `serde_json::to_value` output.
4. Top-level schema definition has `description`, `x-golem-output-mode`, and
   `x-golem-command` metadata; reused types have `x-golem-commands` when useful.
5. Output generator constructs real DTO/view values.
6. Important enum and nested variants are covered by examples or generators.
7. User-facing skills under `golem-skills/skills` have been checked when public
   output changed.
8. `golem-skills/tests` impact has been checked when public output changed.
9. Generated docs from user-facing skills were regenerated if `golem-skills/skills`
   changed.
10. `golem output-schema` prints the current raw schema document.
11. `golem output-schema --types` and `--type <TYPE>` expose compact discovery
    and pruned schemas for coding agents.
12. Remaining `JsonValue` leaves are documented and intentional.
13. Focused schema tests, check task, summary update, and `cargo check -p
   golem-cli` pass.

