feat(opcore): support nested body schema and raw JSON body fields in ParseInline #212

Closed
opened 2026-07-09 20:29:20 +00:00 by coilyco-ops · 2 comments
Member

Summary

ward-mcp needs a truthful way to describe and carry complex HTTP request bodies from inline KDL, without forcing bespoke per-service MCP servers.

The immediate consumer is coilyco-flight-deck/ward-mcp issue #16, surfaced by the SigNoz query_range body shape. That consumer is downstream of this issue. ward-mcp cannot fix this cleanly until opcore grows a richer neutral input model.

Problem

Today http/opcore/inline.go only accepts flat body declarations like:

body "title" "body"

Those fields are always promoted as flat string fields. http/opcore/schema.go likewise models inputs as a flat map[string]Property, so object-valued body fields cannot be represented truthfully in the derived schema.

ward-mcp already forwards arbitrary JSON body values at runtime, but the generated schema is lossy, so MCP clients lose discoverability or infer the wrong types.

Requested change

Extend opcore so the inline source can express richer body shapes while staying transport-neutral.

Recommended minimum scope:

  • Keep existing flat body "a" "b" syntax unchanged as shorthand.
  • Add additive block syntax for body fields.
  • Support at least:
    • scalar fields: string|boolean|integer|number
    • object-valued fields
    • array-valued fields
    • required=true
    • raw=true on an object/array field as an escape hatch for arbitrary JSON subtrees
  • Extend the neutral schema model so JSON Schema emission can describe these shapes truthfully.

A representative target shape is:

body {
    field "start" type="integer" required=true
    field "end" type="integer" required=true
    field "requestType" type="string" required=true
    object "variables" raw=true
    object "formatOptions" raw=true
    object "compositeQuery" raw=true required=true
}

Constraints

  • Keep the model transport-neutral. This should live in opcore, not as MCP-only special handling.
  • Preserve backward compatibility for existing inline specs.
  • Do not expand to full arbitrary JSON Schema authoring in v1.
  • Do not let raw-body support apply to path or query surfaces.

Suggested implementation areas

  • http/opcore/schema.go
  • http/opcore/inline.go
  • http/opcore/descriptor.go if the body-field representation must grow beyond flat Field
  • tests covering:
    • backward-compatible flat body parsing
    • JSON Schema emission for object/array fields
    • raw=true field emission
    • required-field propagation

Downstream dependency

coilyco-flight-deck/ward-mcp should pick this up after it lands, to expose the richer schema through MCP and migrate the SigNoz-style spec without custom server code.


Filed by ward agent advisor cross-repo fan-out from coilyco-flight-deck/ward-mcp#16 (part 1 of 2, ward#424).

— Codex, via ward agent

## Summary `ward-mcp` needs a truthful way to describe and carry complex HTTP request bodies from inline KDL, without forcing bespoke per-service MCP servers. The immediate consumer is `coilyco-flight-deck/ward-mcp` issue `#16`, surfaced by the SigNoz `query_range` body shape. That consumer is downstream of this issue. **ward-mcp cannot fix this cleanly until opcore grows a richer neutral input model.** ## Problem Today `http/opcore/inline.go` only accepts flat body declarations like: ```kdl body "title" "body" ``` Those fields are always promoted as flat string fields. `http/opcore/schema.go` likewise models inputs as a flat `map[string]Property`, so object-valued body fields cannot be represented truthfully in the derived schema. ward-mcp already forwards arbitrary JSON body values at runtime, but the generated schema is lossy, so MCP clients lose discoverability or infer the wrong types. ## Requested change Extend `opcore` so the inline source can express richer body shapes while staying transport-neutral. Recommended minimum scope: - Keep existing flat `body "a" "b"` syntax unchanged as shorthand. - Add additive block syntax for body fields. - Support at least: - scalar fields: `string|boolean|integer|number` - object-valued fields - array-valued fields - `required=true` - `raw=true` on an object/array field as an escape hatch for arbitrary JSON subtrees - Extend the neutral schema model so JSON Schema emission can describe these shapes truthfully. A representative target shape is: ```kdl body { field "start" type="integer" required=true field "end" type="integer" required=true field "requestType" type="string" required=true object "variables" raw=true object "formatOptions" raw=true object "compositeQuery" raw=true required=true } ``` ## Constraints - Keep the model transport-neutral. This should live in `opcore`, not as MCP-only special handling. - Preserve backward compatibility for existing inline specs. - Do not expand to full arbitrary JSON Schema authoring in v1. - Do not let raw-body support apply to path or query surfaces. ## Suggested implementation areas - `http/opcore/schema.go` - `http/opcore/inline.go` - `http/opcore/descriptor.go` if the body-field representation must grow beyond flat `Field` - tests covering: - backward-compatible flat body parsing - JSON Schema emission for object/array fields - `raw=true` field emission - required-field propagation ## Downstream dependency `coilyco-flight-deck/ward-mcp` should pick this up after it lands, to expose the richer schema through MCP and migrate the SigNoz-style spec without custom server code. --- Filed by `ward agent advisor` cross-repo fan-out from coilyco-flight-deck/ward-mcp#16 (part 1 of 2, ward#424). <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-RESERVATION: held 🔒

reservation details

Holder: container engineer-codex-cli-guard-212 on host kais-macbook-pro-2.local.

Reserved by ward agent --harness codex (reserved 2026-07-09T22:40:47Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (1h TTL). --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/cli-guard#212 · branch issue-212 · harness codex · workflow direct-main
  • Run: engineer-codex-cli-guard-212 · ward v0.540.0 · dispatched 2026-07-09T22:40:47Z
  • Comment thread: 0 included in the pre-flight read, 0 stripped (ward's own automated comments).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.540.0).

— Codex, via ward agent

<!-- ward-agent-reservation --> WARD-RESERVATION: held 🔒 <details><summary>reservation details</summary> Holder: container `engineer-codex-cli-guard-212` on host `kais-macbook-pro-2.local`. Reserved by `ward agent --harness codex` (reserved 2026-07-09T22:40:47Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (1h TTL). `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/cli-guard#212` · branch `issue-212` · harness `codex` · workflow `direct-main` - **Run:** `engineer-codex-cli-guard-212` · ward `v0.540.0` · dispatched `2026-07-09T22:40:47Z` - **Comment thread:** 0 included in the pre-flight read, 0 stripped (ward's own automated comments). Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.540.0). </details> </details> <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-OUTCOME: done

details

workflow: direct-main; review summary: review gate skipped by ~/.ward/config.yaml default
retrospective: the change felt surgical once the body field tree was split out from the flat flag path.
confidence: high
surprises: KDL needed boolean shims so the new required=true and raw=true examples could parse as written.
follow-ups: ward-mcp can now consume nested and raw body shapes from opcore without bespoke server code.

WARD-OUTCOME: done <details><summary>details</summary> workflow: direct-main; review summary: review gate skipped by ~/.ward/config.yaml default retrospective: the change felt surgical once the body field tree was split out from the flat flag path. confidence: high surprises: KDL needed boolean shims so the new `required=true` and `raw=true` examples could parse as written. follow-ups: ward-mcp can now consume nested and raw body shapes from opcore without bespoke server code. </details>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/cli-guard#212
No description provided.