Skip to content

Commit 8e0161f

Browse files
committed
Align prompt output specs with compact check output
1 parent 6665e3e commit 8e0161f

11 files changed

Lines changed: 111 additions & 19 deletions

File tree

cmd/dun/main.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ func runCheck(args []string, stdout io.Writer, stderr io.Writer) int {
292292
case "llm":
293293
printLLM(stdout, result)
294294
case "json", "prompt":
295-
if err := json.NewEncoder(stdout).Encode(result); err != nil {
295+
compact := compactResultForOutput(result, root)
296+
if err := json.NewEncoder(stdout).Encode(compact); err != nil {
296297
fmt.Fprintf(stderr, "encode json: %v\n", err)
297298
return dun.ExitCheckFailed
298299
}
@@ -1157,6 +1158,32 @@ func printLLM(stdout io.Writer, result dun.Result) {
11571158
}
11581159
}
11591160

1161+
func compactResultForOutput(result dun.Result, root string) dun.Result {
1162+
stateHash := repoStateHashFn(root)
1163+
out := dun.Result{Checks: make([]dun.CheckResult, len(result.Checks))}
1164+
for i, check := range result.Checks {
1165+
out.Checks[i] = check
1166+
if check.Prompt == nil {
1167+
continue
1168+
}
1169+
compact := *check.Prompt
1170+
taskHint := "Prompt omitted. Run `dun check --prompt` to get task IDs, then `dun task <id> --prompt`."
1171+
if stateHash != "" {
1172+
group := buildTaskGroup(check, stateHash)
1173+
taskID := ""
1174+
if len(group.Tasks) > 0 {
1175+
taskID = group.Tasks[0].ID
1176+
}
1177+
if taskID != "" {
1178+
taskHint = fmt.Sprintf("Prompt omitted. Run `dun task %s --prompt` to view full prompt.", taskID)
1179+
}
1180+
}
1181+
compact.Prompt = taskHint
1182+
out.Checks[i].Prompt = &compact
1183+
}
1184+
return out
1185+
}
1186+
11601187
func runVersion(args []string, stdout io.Writer, stderr io.Writer) int {
11611188
fs := flag.NewFlagSet("version", flag.ContinueOnError)
11621189
fs.SetOutput(stderr)

cmd/dun/main_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,51 @@ func TestRunTaskPrompt(t *testing.T) {
257257
}
258258
}
259259

260+
func TestRunCheckJSONOmitsPromptContent(t *testing.T) {
261+
root := setupEmptyRepo(t)
262+
origCheck := checkRepo
263+
origHash := repoStateHashFn
264+
repoStateHashFn = func(string) string { return "deadbeef" }
265+
checkRepo = func(_ string, _ dun.Options) (dun.Result, error) {
266+
return dun.Result{
267+
Checks: []dun.CheckResult{
268+
{
269+
ID: "agent-check",
270+
Status: "prompt",
271+
Signal: "prompt signal",
272+
Prompt: &dun.PromptEnvelope{
273+
Kind: "dun.prompt.v1",
274+
ID: "agent-check",
275+
Prompt: "Check-ID: agent-check\n\nThis is a big prompt.",
276+
Callback: dun.PromptCallback{
277+
Command: "dun respond --id agent-check --response -",
278+
Stdin: true,
279+
},
280+
},
281+
},
282+
},
283+
}, nil
284+
}
285+
t.Cleanup(func() {
286+
checkRepo = origCheck
287+
repoStateHashFn = origHash
288+
})
289+
290+
var stdout bytes.Buffer
291+
var stderr bytes.Buffer
292+
code := runInDirWithWriters(t, root, []string{"check", "--format=json"}, &stdout, &stderr)
293+
if code != dun.ExitSuccess {
294+
t.Fatalf("expected success, got %d: %s", code, stderr.String())
295+
}
296+
output := stdout.String()
297+
if strings.Contains(output, "This is a big prompt.") {
298+
t.Fatalf("expected prompt content to be omitted")
299+
}
300+
if !strings.Contains(output, "dun task agent-check@deadbeef --prompt") {
301+
t.Fatalf("expected prompt hint to include task id")
302+
}
303+
}
304+
260305
func TestRunCheckJSONEncodeError(t *testing.T) {
261306
root := setupEmptyRepo(t)
262307
errWriter := &failWriter{err: errors.New("write failed")}

docs/design/contracts/API-001-dun-cli.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ $ dun [command] [options] [arguments]
3838
- Schema: See Data Contracts (config schema)
3939

4040
**Output**:
41-
- Format: `llm` text blocks or JSON
41+
- Format: prompt-as-data JSON by default (prompt payloads omitted; use
42+
`dun task <id> --prompt` to fetch), `llm` text for `--format=llm`, JSON for
43+
`--format=json`
4244
- Schema: See Data Contracts (output schema)
4345

4446
**Exit Codes**:
@@ -52,7 +54,7 @@ $ dun [command] [options] [arguments]
5254
```bash
5355
# Default prompt-as-data output
5456
$ dun check
55-
{"checks":[{"id":"helix-create-architecture","status":"prompt","signal":"agent prompt ready","prompt":{"kind":"dun.prompt.v1","id":"helix-create-architecture","prompt":"Check-ID: helix-create-architecture\n...","callback":{"command":"dun respond --id helix-create-architecture --response -","stdin":true}}}]}
57+
{"checks":[{"id":"helix-create-architecture","status":"prompt","signal":"agent prompt ready","prompt":{"kind":"dun.prompt.v1","id":"helix-create-architecture","prompt":"Prompt omitted. Run `dun task helix-create-architecture@abcd123 --prompt` to view full prompt.","callback":{"command":"dun respond --id helix-create-architecture --response -","stdin":true}}}]}
5658

5759
# LLM output
5860
$ dun check --format=llm
@@ -433,6 +435,10 @@ equivalent JSON shape.
433435
}
434436
```
435437

438+
**Note**: When emitted via `dun check`, `prompt.prompt` may contain a compact
439+
placeholder instead of the full prompt. Use `dun task <id> --prompt` to
440+
retrieve the full prompt payload.
441+
436442
### Output Schema (list)
437443
```json
438444
{

docs/helix/01-frame/features/F-002-output-formats.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ dun:
44
depends_on:
55
- helix.prd
66
review:
7-
self_hash: 83b2a3c2ac4e9a760bd04598c3ff9c3ea3504c0f49e8d246cd9a61d540e87898
7+
self_hash: 5d4226456b8fd1dca4daae652bbcd24fb50d14f2b1e01193db67cd5a5cf2da35
88
deps:
9-
helix.prd: 58d3c4be8edb0a0be9d01a3325824c9b350f758a998d02f16208525949c4f1ad
9+
helix.prd: 07d49919dec51a33254b7630622ee086a5108ed5deecd456f7228f03712e699d
1010
---
1111
# Feature Spec: F-002 Output Formats
1212

@@ -17,7 +17,8 @@ consumption by humans and tools.
1717

1818
## Requirements
1919

20-
- Default output format is prompt envelopes for agent checks.
20+
- Default output format is prompt envelopes for agent checks, but `dun check`
21+
omits full prompt payloads (prompt field contains a task hint).
2122
- Provide `--format=llm` for concise human-readable summaries.
2223
- Provide `--format=json` for structured results.
2324
- The decision prompt (`dun check --prompt`) must list tasks without inlining
@@ -41,7 +42,8 @@ consumption by humans and tools.
4142

4243
## Acceptance Criteria
4344

44-
- `dun check` emits prompt envelopes by default when agent checks are present.
45+
- `dun check` emits prompt envelope metadata by default when agent checks are
46+
present; prompt payloads are omitted and replaced with a task hint.
4547
- `dun check --format=llm` prints concise summaries.
4648
- `dun check --format=json` emits structured JSON output.
4749
- `dun check --prompt` emits a compact, bounded task list (no inline prompt
@@ -50,8 +52,8 @@ consumption by humans and tools.
5052
- Default limits: top 10 tasks per check; summary <= 200 bytes; reason <= 160
5153
bytes; truncation uses `...`.
5254
- Task IDs include the repo-state hash and are rejected if stale.
53-
- JSON output remains a full check result (including prompt envelopes where
54-
available); it is not size-bounded like the decision prompt.
55+
- JSON output remains structured and deterministic but omits full prompt
56+
payloads; it is not size-bounded like the decision prompt.
5557

5658
## Gaps & Conflicts
5759

docs/helix/01-frame/user-stories/US-002-output-formats.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ can consume results in the right format for my workflow.
1111

1212
## Acceptance Criteria
1313

14-
- `dun check` emits prompt envelopes by default when agent checks are present.
14+
- `dun check` emits prompt envelope metadata by default when agent checks are
15+
present; prompt payloads are omitted and replaced with a task hint.
1516
- `dun check --format=llm` prints concise summaries for humans.
1617
- `dun check --format=json` emits structured JSON output.
1718
- Output is deterministic for a given repo state.

docs/helix/01-frame/user-stories/US-016-task-workflow.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ command to fetch full prompts,
2828

2929
### AC-3: Task Prompt Retrieval
3030
- [ ] `dun task <task-id>` prints a concise task summary.
31+
- [ ] Task summaries never include full prompt payloads.
3132
- [ ] `dun task <task-id> --prompt` prints the full prompt payload.
3233
- [ ] Decision prompt hints how to fetch the full prompt.
3334

docs/helix/02-design/solution-designs/SD-002-output-formats.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ dun:
44
depends_on:
55
- F-002
66
review:
7-
self_hash: f543f44dd37dea76fd38919c5f15a737ba8fbb46e621a5a1c83c526892fb0757
7+
self_hash: 8c32ec1de236d13a6d5cbd49f766f542ae1222821a9de0fe451079e7ec351af0
88
deps:
9-
F-002: 83b2a3c2ac4e9a760bd04598c3ff9c3ea3504c0f49e8d246cd9a61d540e87898
9+
F-002: 5d4226456b8fd1dca4daae652bbcd24fb50d14f2b1e01193db67cd5a5cf2da35
1010
---
1111
# Solution Design: Output Formats
1212

@@ -17,7 +17,8 @@ remain deterministic and easy to parse.
1717

1818
## Goals
1919

20-
- Emit prompt envelopes by default for agent checks.
20+
- Emit prompt envelopes by default for agent checks, omitting full prompt
21+
payloads from `dun check` output.
2122
- Provide `--format=llm` for concise human-readable summaries.
2223
- Provide `--format=json` for structured results.
2324
- Preserve deterministic ordering and stable results for a given repo state.
@@ -48,7 +49,7 @@ remain deterministic and easy to parse.
4849
## Components
4950

5051
- Result Model: canonical representation of check outcomes.
51-
- Prompt Emitter: renders prompt envelopes.
52+
- Prompt Emitter: renders prompt envelopes with compact prompt placeholders.
5253
- LLM Renderer: emits concise summaries.
5354
- JSON Renderer: emits structured machine output.
5455
- Output Selector: chooses renderer based on CLI flags.

docs/helix/02-design/technical-designs/TD-002-output-formats.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ dun:
1717
- Provide prompt, LLM, and JSON output formats for check results.
1818
- Keep output deterministic and stable for automation.
1919
- Allow format selection via CLI flags and config.
20+
- Omit full prompt payloads from `dun check` output and expose them via
21+
`dun task <id> --prompt`.
2022

2123
## Non-Goals
2224

@@ -35,6 +37,8 @@ dun:
3537
### Key Decisions
3638

3739
- Default to `prompt` format for agent loops.
40+
- `dun check` output uses prompt placeholders; full prompts are retrieved via
41+
`dun task`.
3842
- JSON output should be schema-stable to avoid breaking integrations.
3943

4044
## Component Changes

docs/helix/02-design/technical-designs/TD-016-task-workflow.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ full prompt payloads to a follow-up `dun task` command.
3939
**File**: `cmd/dun/task.go`
4040

4141
- Add `dun task <task-id>` to emit task summary metadata.
42+
- Ensure task summaries never include full prompt payloads.
4243
- Add `--prompt` flag to print the full prompt.
4344
- Re-run checks to resolve the selected task in the current state.
4445

docs/helix/03-test/test-plans/TP-002-output-formats.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Test plan for US-002: Emit Output Formats for Agents and Tools.
1212

1313
| ID | Criterion | Status |
1414
|----|-----------|--------|
15-
| AC-1 | `dun check` emits prompt envelopes by default when agent checks are present | Partially Covered |
15+
| AC-1 | `dun check` emits prompt envelopes by default when agent checks are present (prompt payloads omitted) | Partially Covered |
1616
| AC-2 | `dun check --format=llm` prints concise summaries for humans | Covered |
1717
| AC-3 | `dun check --format=json` emits structured JSON output | Covered |
1818
| AC-4 | Output is deterministic for a given repo state | Gap |
@@ -37,6 +37,7 @@ Test plan for US-002: Emit Output Formats for Agents and Tools.
3737
- No test verifies prompt envelope `kind` field is always `dun.prompt.v1`
3838
- No test verifies callback command format is correct across all agent checks
3939
- No test verifies prompt envelope contains required fields (id, prompt, callback)
40+
- No test verifies prompt payloads are omitted from `dun check` output
4041

4142
### AC-2: LLM Format Output
4243

@@ -106,7 +107,7 @@ func TestCheckDefaultFormatIsPrompt(t *testing.T) {
106107
t.Fatalf("expected success, got %d", code)
107108
}
108109

109-
// Default output should be parseable as JSON with prompt envelope
110+
// Default output should be parseable as JSON with prompt envelope placeholder
110111
var result dun.Result
111112
if err := json.Unmarshal(stdout.Bytes(), &result); err != nil {
112113
t.Fatalf("expected JSON output by default: %v", err)
@@ -120,6 +121,9 @@ func TestCheckDefaultFormatIsPrompt(t *testing.T) {
120121
if check.Prompt == nil {
121122
t.Fatalf("expected prompt envelope in default output")
122123
}
124+
if !strings.Contains(check.Prompt.Prompt, "Prompt omitted") {
125+
t.Fatalf("expected compact prompt placeholder, not full prompt payload")
126+
}
123127
}
124128
```
125129

0 commit comments

Comments
 (0)