From c52034f3fe2e05460537822258c64f04c42810de Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 6 Nov 2026 21:40:52 +0000 Subject: [PATCH] Define original-value text templates and YAML fallback --- docs/roadmap/future.md | 8 +- docs/roadmap/promptkit-v0.19.0.md | 133 +++++++++++++++++++----------- 2 files changed, 89 insertions(+), 52 deletions(-) diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index 8a38309..c5640bd 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -163,13 +163,15 @@ steps. No delivery date or final API is selected here. The [shared core report output prerequisite](promptkit-v0.19.0.md#shared-core-report-output-prerequisite) is now part of the working adoption roadmap. It records application-owned -content selection, core-owned rendering, a text fallback with optional templates, +content selection, core-owned rendering, text output with optional templates, and universal format availability. Explicit operator selection wins; otherwise core selects text for a supplied template or chooses from the logical report shape. Command-specific format defaults are omitted from the initial API. Plain text, YAML, and JSON land together. The roadmap selects standard Go JSON -serialization conventions for ordinary report values, with separate core -adaptation for native configuration YAML. Text-template and native-document +serialization conventions for core-serialized report values, with separate core +adaptation for native configuration YAML. Text templates use Go's `text/template` +with the original Go report value. Without a template, structured text output +reuses the YAML renderer; template errors never trigger fallback. Native-document decisions remain there. XML is removed from current consideration. Markdown and other potential formats are not selected for this adoption; new core formats will work with diff --git a/docs/roadmap/promptkit-v0.19.0.md b/docs/roadmap/promptkit-v0.19.0.md index 79772c2..8690da6 100644 --- a/docs/roadmap/promptkit-v0.19.0.md +++ b/docs/roadmap/promptkit-v0.19.0.md @@ -399,9 +399,12 @@ existing reporting facility rather than creating a second delivery lifecycle. ### Agreed shared representation rules **Agreed:** use Go's standard `encoding/json` serialization conventions to -interpret ordinary Go report values. Prepare one logical representation for -automatic selection and rendering in text, YAML, and JSON. This selects how Go -values become report data; it does not select JSON as the default output format. +interpret ordinary Go report values for core serialization. Prepare one logical +representation for YAML/JSON output and for automatic selection and text +rendering when no text template is used. Application-supplied text templates instead +receive the original Go value, as specified below. JSON conventions do not +select JSON as the default output format or expose core's intermediate data +representation as a public template contract. Reuse the standard library's field selection, JSON tags, omission rules, nested value handling, and supported custom JSON serialization. Avoid a new CommandKit @@ -409,9 +412,10 @@ tag convention or reflection-based serialization engine. Suitable upstream values can reuse their existing JSON contract; thin projections remain useful when the desired operator content differs from that representation. -- **One field interpretation.** JSON field tags and custom serialization govern - ordinary values in every output format. Conflicting YAML tags or YAML-specific - serialization do not change that interpretation. For example, a field tagged +- **One serialized field interpretation.** JSON field tags and custom + serialization govern ordinary values in core-serialized outputs. Conflicting + YAML tags or YAML-specific serialization do not change that interpretation. + For example, a field tagged `json:"retry_count" yaml:"retries"` appears as `retry_count` in both JSON and YAML. Do not independently serialize the original Go value with each encoder. - **Explicit omission.** Honor omissions selected by the JSON contract. Core @@ -422,9 +426,11 @@ when the desired operator content differs from that representation. including accidental rounding of large integers through floating point. This preserves the serialized value rather than promising precision beyond the supplied value and its serialization contract. -- **Observable failures.** Values rejected by the serialization contract produce - presentation errors through the existing reporting lifecycle. Do not silently - drop unsupported data or substitute arbitrary string representations. +- **Observable failures.** When serialization is used, values rejected by its + contract produce presentation errors through the existing reporting lifecycle. + Do not silently drop unsupported data or substitute arbitrary string + representations. Templated text executes against the original value without + requiring a JSON round trip. **Agreed separate treatment:** native configuration YAML uses explicit core adaptation with defined cross-format mappings, not blind conversion through the @@ -442,32 +448,47 @@ assuming that an upstream type can be handed off without adaptation. ### Agreed plain-text rendering -Core provides a default plain-text fallback and accepts an optional template -from the application or integration as part of the report handoff. When text is -selected, core uses the template if supplied and otherwise renders the selected -report data using its standard fallback. A template selects text automatically -only when the operator omits `--format`; explicit YAML or JSON takes precedence. -YAML and JSON use the same selected content and shared representation rules, -independently of the text -template. Applications do not supply separate YAML/JSON writers. +**Agreed template boundary:** applications and integrations own the report value +and optional text template. Core prepares and executes templates using Go's +built-in `text/template`, passing the original Go value supplied in the report +handoff. Templates use Go field names, types, and standard template behavior, +not JSON field names or CommandKit's intermediate representation. For example, +a Go field `PromptID` tagged `json:"prompt_id"` is accessed as `.PromptID`. -Recommend a readable hierarchical fallback with named fields, nested values, -and list items. A template can arrange the supplied content as a sentence, -table, or another useful presentation. Core owns template execution, shared -formatting helpers, and delivery errors. Go's `text/template` and reusable -templates declared once are implementation candidates; the template API, -helper set, and exact fallback layout still need design. +JSON tags and custom JSON serialization govern structured rendering, not the +template's field access. An exported field tagged `json:"-"` remains accessible +to the application's template, and custom JSON serialization does not replace +the template input. The application owns that text content choice. Core retains +ownership of execution, shared helpers, delivery, and presentation failures. +Prefer reusable templates prepared during setup; exact public preparation and +handoff signatures and the small helper set remain implementation design tasks. -This resolves the earlier human-oriented presentation discussion (point 4). -Universal core formats resolve point 5; per-command supported-format lists and -per-format application renderers are not the selected mechanism. +When text is selected and a template is supplied, execute it as supplied and +deliver its output without applying a second formatting pass. Template syntax +or execution errors are errors, not a reason to fall back to another renderer. +Use standard `text/template` semantics rather than introducing a new template +language. A template selects text automatically only when the operator omits +`--format`; explicit YAML or JSON takes precedence and does not execute it. + +**Agreed text behavior without a template:** use core's logical report +representation to select the following rendering behavior: + +- Print strings directly, nonempty sequences containing only strings one item per line, + and numbers or booleans as their values. +- For mappings, nested or mixed collections, empty collections, and null, reuse + the shared YAML renderer. Empty sequences use this rule even when their Go + element type is string, retaining the visible `[]` result. + +Automatic selection already chooses YAML for the second group. The additional +case is explicit `--format text` with structured data and no template, such as +`config show --format text`. Text and YAML intentionally coincide in that case. +This retains universal format support without a separate hierarchical text +renderer or pretty-printer. It supersedes the proposed generic text outline. +Applications do not supply separate YAML/JSON writers, and a failing template +never enters this no-template path. ### Remaining core reporting decisions -- **Text handoff.** Settle the template API and helper functions, whether - templates receive the original Go value or shared representation, fallback - conventions, and template preparation and failure behavior. Prefer a small - reusable mechanism; applications select content and layout, core renders it. - **Native documents and multiple results.** Define how native safe YAML snapshots and ordered multi-scope documents enter the shared representation, and how multiple documents/results appear in JSON and text. Preserve native @@ -475,10 +496,12 @@ per-format application renderers are not the selected mechanism. commands from universal format support. Keep format translation in core and domain evidence selection in the integrations. -Exact public signatures, flag integration/collision handling, and replacement -of existing format plumbing are implementation design tasks. The decisions -above do not reopen content selection, JSON conventions for ordinary report -values, universal formats, automatic selection, or joint format delivery. +Exact public signatures, reusable template preparation and helper functions, +flag integration/collision handling, and replacement of existing format plumbing +are implementation design tasks. The decisions above do not reopen content +selection, JSON conventions for core serialization, original Go values for text +templates, no-template text rendering, universal formats, automatic selection, +or joint format delivery. Report serialization does not settle the separate JSON input-number conversion choices in OD-2 and OD-11. @@ -502,8 +525,8 @@ projection using the agreed JSON serialization conventions. Do not mirror a whole upstream object graph just to rename fields or rearrange equivalent data. Reuse small path, snapshot, location, and duration projections where they are genuinely needed. Core reuses -the JSON contract across renderers; migrate YAML-only report tags or provide a -thin projection where necessary. Native configuration documents follow their +the JSON contract across its serialization paths; migrate YAML-only report tags +or provide a thin projection where necessary. Native configuration documents follow their explicit adaptation path rather than the ordinary Go-value path. Exceptions serve concrete report semantics: preserving absent/null/false/zero @@ -517,8 +540,10 @@ design, not an integration-owned alternative formatting pipeline. Separate content projection from format rendering and from invocation delivery. Use the existing Reporter and outcome lifecycle for delivery and failures. -Share common helpers without forcing text output through a YAML round trip or -forcing semantically different reports into one schema. Validate representative +Text templates receive original Go values. Simple text output uses the logical +report values directly, while structured text without a template delegates to +the YAML renderer without a YAML encode/decode round trip. Do not force +semantically different reports into one schema. Validate representative reports and meaningful adaptation boundaries, rather than freezing every incidental formatting detail in tests. @@ -526,15 +551,15 @@ incidental formatting detail in tests. 1. **Confirm remaining implementation choices.** Use the accepted flags, report content, and automatic format policy as the MVP target. Resolve the remaining - text-template and native-document decisions; specify the public API and - internal conversion design under the agreed JSON representation contract. + native-document decisions; specify the public API, reusable template helpers, + and internal conversion design under the agreed JSON representation contract. Resolve outstanding acquisition/binding grammar and flag collisions; use concrete examples to review report details during implementation rather than reopening accepted scope. 2. **Implement shared core report output.** Deliver the agreed automatic format policy, universal `--format` selection, format-independent Reporter operation, writer-based API, and shared representation/encoding machinery. - Deliver YAML encoding, text fallback/templates, and JSON encoding together + Deliver YAML encoding, text printing/templates, and JSON encoding together in the core feature release. Exercise the public API with core reporting and an application-owned command example, and consolidate suitable existing integration reports onto it. Cover the selected contracts and update their @@ -584,7 +609,7 @@ CommandKit to retest PromptKit rendering, schema, namespace, or ConfigKit resolution algorithms. Default tests remain offline and independent of real credentials. -- [ ] Remaining text-template and native-document decisions are recorded. +- [ ] Remaining native-document decisions are recorded. Public signatures and shared representation conventions are documented with implementation. - [ ] Core owns universal `--format` options, help, validation, and selection. @@ -600,14 +625,24 @@ Default tests remain offline and independent of real credentials. configuration values. Focused configuration values follow the same rules. - [ ] Plain text, YAML, and JSON ship together; representative reports exercise shared representation and explicit selection across all three. -- [ ] Plain text uses the supplied template or core's fallback. Core owns - rendering and errors in both cases. The integration chooses concise/detailed - content; changing format does not implicitly change the selected detail level. +- [ ] Text templates execute with standard `text/template` behavior against the + original Go report value, retaining field names and types. JSON tags and custom + JSON serialization do not rename, omit, or replace the template input. + Explicit YAML/JSON output does not execute the text template. +- [ ] Template syntax and execution failures remain observable errors; a failing + template never falls back to scalar printing or YAML output. +- [ ] Text without a template prints strings, nonempty string lists, numbers, + and booleans directly; structured values, empty collections, and null use the + shared YAML renderer. Cover explicit `--format text` for those values without + introducing a separate pretty-printer. +- [ ] The integration chooses concise/detailed content; changing format does + not implicitly change the selected detail level. Core owns rendering and + delivery in both templated and non-templated paths. - [ ] The invocation and writer-based public APIs share rendering behavior; handlers submit report data without their own format switches or encoder setup. Existing quiet-mode, presentation-failure, and domain-outcome behavior is preserved through the Reporter lifecycle. -- [ ] Ordinary Go reports follow the standard JSON contract across formats, +- [ ] Core-serialized ordinary Go reports follow the standard JSON contract, including JSON tags, supported custom serialization, and selected omissions. Conflicting YAML tags do not rename fields or change values in YAML output. Verify that automatic selection follows the resulting logical shape. @@ -771,7 +806,7 @@ These decisions concern significant choices within the proposed scope. Resolved items retain their numbers and record the agreed decision. OD numbers are local to this roadmap, not the retired adoption documents. -The core ownership, JSON representation conventions, text fallback/template, +The core ownership, JSON representation conventions, text printing/templates, universal-format, automatic-selection, and joint format-delivery decisions are now agreed above. Remaining details are listed under [remaining core reporting decisions](#remaining-core-reporting-decisions). @@ -798,7 +833,7 @@ calling the model." Document resource I/O and rendered content disclosure directly in help and CLI guidance. The report is an inspection snapshot, not a saved execution handle or a guarantee that later execution uses the same snapshot or succeeds. Core's -text fallback supplies explicit `--format text` output without requiring a +YAML renderer also supplies explicit `--format text` output without requiring a dedicated preview template; a specialized template is not required for initial delivery. ### OD-2: Request controls and provider-parameter grammar @@ -1019,7 +1054,7 @@ has an explicit empty difference list. Both concise and detailed comparison hand off structured mappings without a text template; core's automatic policy selects YAML. Universal format choices supersede the earlier YAML-only detailed restriction. The same selected comparison evidence is handed to core in every -format; explicit text uses core's fallback. +format; explicit text without a template reuses core's YAML renderer. Keep the projection close to native report values, using the [shared reporting approach](#initial-report-implementation-approach) rather than