Skip to content

feat(cli): JSON Schema generation + IDE autocomplete support#325

Merged
4 commits merged intomainfrom
feat/json-schema-and-ide
Apr 28, 2026
Merged

feat(cli): JSON Schema generation + IDE autocomplete support#325
4 commits merged intomainfrom
feat/json-schema-and-ide

Conversation

@Destynova2
Copy link
Copy Markdown
Contributor

Summary

  • Adds grob schema subcommand that prints a JSON Schema (Draft 7) for ~/.grob/config.toml, generated from JsonSchema-decorated config structs in src/cli/config/. Operators editing the file get autocomplete, hover docs, and inline type errors in VS Code (Even Better TOML), JetBrains, Neovim (taplo / coc-toml), and Helix.
  • Pre-generated schemas/grob-config.schema.json checked into the repo, kept in sync by a new CI job schema-up-to-date that fails any PR where the committed schema drifts from the code.
  • Workspace .vscode/settings.json wires the schema in for contributors editing project configs; docs/how-to/ide-autocomplete.md covers VS Code / JetBrains / Neovim / Helix / CLI validation setups for end users.

Implementation notes

  • schemars = "0.8" added to Cargo.toml. All structs in src/cli/config/*.rs plus the Port / BudgetUsd / BodySizeLimit newtypes derive JsonSchema. SecretString fields use #[schemars(with = \"Option<String>\")] so the schema describes them as opaque strings (literal value, \$ENV_VAR, or secret:<name>).
  • AppConfig is mirrored by a SchemaAppConfig wrapper in src/cli/config/schema.rs. Sections that live in cross-cutting feature modules (dlp, mcp, policies, tap, auth, tool_layer, log_export, pledge, classifier) are surfaced as serde_json::Value placeholders so future feature blocks remain valid without forcing a JsonSchema derive on every internal feature module. The well-known sections (server, router, providers, models, tiers, presets, budget, security, cache, secrets, compliance, otel, tee, fips, user, harness) are fully typed.
  • grob schema is short-circuited in main.rs before config loading runs, so it works on a freshly cloned machine with no ~/.grob/config.toml.
  • Enum variants render as JSON Schema oneOf (verified for AuthType -> apikey/oauth, SecretsBackend -> local_encrypted/env/file, EnforcementMode, ModelStrategy, FanOutMode, PoolStrategy).

Test plan

  • cargo nextest run --lib -> 1060 / 1060 pass, including 7 new tests covering schema generation + the cmd_schema command.
  • cargo test --doc -> doctest for cli::schema::generate compiles.
  • cargo fmt --all -- --check clean.
  • cargo clippy --all-targets -- -D warnings clean (default + CI feature subset + harness feature).
  • cargo run --bin grob -- schema | jq . -> valid JSON, 33 named definitions, all 26 top-level config sections present.
  • diff schemas/grob-config.schema.json <(grob schema) -> empty (CI guard verified locally before push).
  • CI green (release-plz path filter ignores schemas/ so this PR will not bump the version; release-plz runs only on src/**, Cargo.toml, Cargo.lock -> the release path triggers as expected since Cargo.toml and Cargo.lock changed).
  • Manual: open ~/.grob/config.toml in VS Code with Even Better TOML installed, hover [server] field -> description renders.

🤖 Generated with Claude Code

Clément LIARD added 4 commits April 28, 2026 22:41
CI re-runs the full test suite (incl. doctests) on every PR via the
.github/workflows/ci.yml tests job, so local pre-push duplication
adds ~20 min per push without catching anything new. Pre-push hooks
should be fast-fail; expensive checks belong on the CI server.

Closes audit finding: silent productivity tax (pre-push duplication).
Documents the three-state intent (true/false/absent) of ProviderConfig.is_enabled
and the dependency on deny_unknown_fields (added in the next commit) to
reject typos like enbaled = false at parse time. Behaviour is unchanged;
this is purely contractual clarity to support the silent-typo-killer audit.

Closes audit finding: silent typo killer on provider config.
Adds #[serde(deny_unknown_fields)] to AppConfig and the major
sub-structs (ProviderConfig, ModelConfig, TierConfig, RouterConfig,
ScoringConfig, CacheConfig, BudgetConfig, DlpConfig, SecurityConfig).

Without this guard, a typo like enbaled = false in a [[providers]]
block silently parses (the unknown key is dropped) and the provider
remains enabled with the wrong intent. With the guard, parsing fails
loudly and the operator gets an actionable error pointing at the
offending key.

Tested with the full nextest suite (1268 tests) plus all doctests:
no fixture, preset or example carries a stale field, so this is a
pure tightening with no migration cost.

Closes audit finding: silent typo killer on TOML config.
Each entry in DENIED_SECTIONS / DENIED_KEYS now carries a short
justification table covering why it can not be hot-reloaded — either
because the data is sensitive (credentials, DLP rules) or because the
consumer is constructed once at process start (TLS listener, secret
backend, TEE attestation, FIPS gate).

Adds tee, fips, server.tls and secrets.backend to the deny-list so
the documented "static-init" rationale matches actual behaviour. Also
emits an INFO log on every denied attempt telling the operator to
restart instead of expecting the silent reload to apply.

Adds two unit tests covering the new deny entries (tee/fips sections
and server.tls / secrets.backend keys) and asserts that sibling keys
in the same sections remain editable.

Closes audit finding: hot-reload UX (silent ignore of denied edits).
@Destynova2 Destynova2 enabled auto-merge April 28, 2026 20:51
auto-merge was automatically disabled April 28, 2026 21:47

Pull Request is not mergeable

@Destynova2 Destynova2 closed this pull request by merging all changes into main in a6a684e Apr 28, 2026
@Destynova2 Destynova2 deleted the feat/json-schema-and-ide branch April 28, 2026 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant