Skip to content

Commit e74668b

Browse files
authored
Remove task frontmatter from output (#191)
1 parent 3a4c369 commit e74668b

5 files changed

Lines changed: 80 additions & 139 deletions

File tree

README.md

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ The tool assembles context into a structured prompt with the following component
1818
├─────────────────────────────────────────────────────────────┤
1919
│ │
2020
│ ┌───────────────────────────────────────────────────────┐ │
21-
│ │ 1. Task Frontmatter (YAML) │ │
22-
│ │ • Task metadata (selectors, agent, etc.) │ │
23-
│ │ • Always included when task has frontmatter │ │
21+
│ │ 1. Rules Content (Markdown) │ │
22+
│ │ • Coding standards and guidelines │ │
23+
│ │ • Team conventions and best practices │ │
24+
│ │ • Filtered by selectors (-s flag) │ │
25+
│ │ • Skipped in resume mode (-r flag) │ │
2426
│ └───────────────────────────────────────────────────────┘ │
2527
│ │
2628
│ ┌───────────────────────────────────────────────────────┐ │
@@ -31,15 +33,7 @@ The tool assembles context into a structured prompt with the following component
3133
│ └───────────────────────────────────────────────────────┘ │
3234
│ │
3335
│ ┌───────────────────────────────────────────────────────┐ │
34-
│ │ 3. Rules Content (Markdown) │ │
35-
│ │ • Coding standards and guidelines │ │
36-
│ │ • Team conventions and best practices │ │
37-
│ │ • Filtered by selectors (-s flag) │ │
38-
│ │ • Skipped in resume mode (-r flag) │ │
39-
│ └───────────────────────────────────────────────────────┘ │
40-
│ │
41-
│ ┌───────────────────────────────────────────────────────┐ │
42-
│ │ 4. Task Content (Markdown) │ │
36+
│ │ 3. Task Content (Markdown) │ │
4337
│ │ • Task-specific instructions │ │
4438
│ │ • Parameter substitutions (${param}) │ │
4539
│ │ • Command expansions (!`command`) │ │
@@ -50,10 +44,10 @@ The tool assembles context into a structured prompt with the following component
5044
```
5145

5246
**Key Points:**
53-
- **Task Frontmatter**: Provides metadata for agent decision-making and workflow automation
54-
- **Skills**: Enable progressive disclosure of specialized capabilities
5547
- **Rules**: Reusable context that applies across multiple tasks
48+
- **Skills**: Enable progressive disclosure of specialized capabilities
5649
- **Task Content**: Specific instructions for the current task with dynamic content expansion
50+
- **Note**: Task frontmatter is used for filtering and metadata but is not included in the output
5751

5852
## Features
5953

@@ -767,40 +761,49 @@ The AI agent can then read the full skill content from the provided location whe
767761

768762
### Task Frontmatter
769763

770-
Task frontmatter is **always** automatically included at the beginning of the output when a task file has frontmatter. This allows the AI agent or downstream tool to access metadata about the task being executed. There is no flag needed to enable this - it happens automatically.
764+
Task frontmatter contains metadata used for filtering, agent selection, and workflow automation. While the frontmatter itself is not included in the generated output, it serves important purposes:
765+
766+
**What frontmatter is used for:**
767+
- **Task selection**: Filtering between multiple task files using selectors
768+
- **Agent specification**: The `agent` field can override the `-a` command-line flag
769+
- **Rule filtering**: The `selectors` field automatically filters rules without requiring explicit `-s` flags
770+
- **Workflow control**: Fields like `resume` control task behavior in different modes
771771

772772
**Example usage:**
773773
```bash
774774
coding-context -p issue_number=123 fix-bug
775775
```
776776

777-
**Output format:**
778-
```yaml
777+
**Example task file:**
778+
```markdown
779779
---
780780
resume: false
781+
selectors:
782+
languages: go
783+
stage: implementation
781784
---
782785
# Fix Bug Task
783786

787+
Fix the bug in issue #${issue_number}...
788+
```
789+
790+
**Output format:**
791+
The task frontmatter is NOT included in the output. Only the task content (below the frontmatter delimiters) is included:
792+
```markdown
793+
# Fix Bug Task
794+
784795
Fix the bug in issue #123...
785796
```
786797

787-
This can be useful for:
788-
- **Agent decision making**: The AI can see metadata like priority, environment, or stage
789-
- **Workflow automation**: Downstream tools can parse the frontmatter to make decisions
790-
- **Debugging**: You can verify which task variant was selected and what selectors were applied
798+
This design keeps the output focused on actionable content while still allowing frontmatter to control behavior and filtering.
791799

792800
**Example with selectors in frontmatter:**
793801
```bash
794802
coding-context implement-feature
795803
```
796804

797-
If the task has `selectors` in its frontmatter, they will be visible in the output:
798-
```yaml
799-
---
800-
selectors:
801-
languages: go
802-
stage: implementation
803-
---
805+
If the task has `selectors` in its frontmatter, they will automatically filter rules, but the frontmatter itself won't appear in the output:
806+
```markdown
804807
# Implementation Task
805808
...
806809
```

SPECIFICATION.md

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ selectors:
230230
**Rules:**
231231
- `task_name` field is optional metadata
232232
- Tasks matched by filename (e.g., `fix-bug.md` → task name `fix-bug`)
233-
- Frontmatter is automatically output with task
233+
- Frontmatter is used for filtering and metadata but not included in output
234234
- Can specify `selectors` to auto-filter rules
235235
- Supports parameter expansion: `${param_name}`
236236

@@ -1096,20 +1096,28 @@ Remote directories support (via go-getter):
10961096

10971097
### 11.1 Assembly Order
10981098

1099-
1. **Task frontmatter** (YAML format, automatically included if present)
1099+
1. **Rule content** (all included rules, content only)
11001100
2. **Skill metadata** (XML format, if skills found)
1101-
3. **Rule content** (all included rules, content only)
1102-
4. **Task content** (with expansions applied)
1103-
5. **User prompt** (if provided, after `---` delimiter)
1101+
3. **Task content** (with expansions applied)
1102+
4. **User prompt** (if provided, after `---` delimiter)
1103+
1104+
**Note**: Task frontmatter is used for filtering and metadata purposes but is not included in the output.
11041105

11051106
### 11.2 Output Format
11061107

11071108
**To stdout (the context):**
1108-
```yaml
1109-
---
1110-
task_name: fix-bug
1111-
resume: false
1112-
---
1109+
```markdown
1110+
# Rule 1 Content
1111+
1112+
Rule 1 text...
1113+
1114+
# Rule 2 Content
1115+
1116+
Rule 2 text...
1117+
1118+
# Skills
1119+
1120+
You have access to the following skills. Skills are specialized capabilities that provide domain expertise, workflows, and procedural knowledge. When a task matches a skill's description, you can load the full skill content by reading the SKILL.md file at the location provided.
11131121

11141122
<available_skills>
11151123
<skill>
@@ -1119,14 +1127,6 @@ resume: false
11191127
</skill>
11201128
</available_skills>
11211129

1122-
# Rule 1 Content
1123-
1124-
Rule 1 text...
1125-
1126-
# Rule 2 Content
1127-
1128-
Rule 2 text...
1129-
11301130
# Task Content
11311131

11321132
Fix bug #123...
@@ -1148,8 +1148,7 @@ INFO: Estimated tokens: 2,345
11481148
With `-r` flag:
11491149
1. All rules are **skipped**
11501150
2. Implicit selector: `-s resume=true` added
1151-
3. Task frontmatter still included
1152-
4. Useful for continuing work with established context
1151+
3. Useful for continuing work with established context
11531152

11541153
### 11.4 Token Estimation
11551154

@@ -1396,12 +1395,14 @@ Bootstrap scripts output to stderr (not context) because:
13961395
- Allows logging without polluting context
13971396
- Enables verification without affecting AI input
13981397

1399-
#### 14.2.5 Frontmatter in Task Output
1400-
Task frontmatter is automatically included because:
1401-
- Enables agent decision-making
1402-
- Supports downstream tooling
1403-
- Aids debugging and verification
1404-
- No overhead for simple cases
1398+
#### 14.2.5 Task Frontmatter Usage
1399+
Task frontmatter serves metadata purposes:
1400+
- Enables task selection and filtering via selectors
1401+
- Specifies agent preferences
1402+
- Controls workflow behavior (e.g., resume mode)
1403+
- Defines rule filtering via `selectors` field
1404+
1405+
The frontmatter is not included in the output to keep the generated context focused on actionable content.
14051406

14061407
### 14.3 Limitations
14071408

examples/.agents

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
agents

integration_test.go

Lines changed: 18 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -379,15 +379,12 @@ Command with param: !`+"`echo '${secret}'`"+`
379379
output := runTool(t, "-C", tmpDir, "-p", "evil=!`echo INJECTED`", "-p", "secret=TOPSECRET", "test-security")
380380

381381
// Split output into lines to separate stderr logs from stdout prompt
382+
// Since task frontmatter is no longer printed, we identify stdout by filtering out stderr log lines
382383
lines := strings.Split(output, "\n")
383384
var promptLines []string
384-
inPrompt := false
385385
for _, line := range lines {
386-
// Look for the start of the frontmatter (which marks beginning of stdout)
387-
if strings.HasPrefix(line, "---") {
388-
inPrompt = true
389-
}
390-
if inPrompt {
386+
// Stderr log lines start with "time=", stdout lines don't
387+
if !strings.HasPrefix(line, "time=") {
391388
promptLines = append(promptLines, line)
392389
}
393390
}
@@ -974,78 +971,46 @@ This is a test task.
974971
t.Fatalf("failed to write task file: %v", err)
975972
}
976973

977-
// Test that frontmatter is always printed
974+
// Test that task frontmatter is NOT printed
978975
output := runTool(t, "-C", dirs.tmpDir, "test-task")
979976

980-
lines := strings.Split(output, "\n")
981-
982-
// Find the first non-log line (skip lines starting with "time=")
983-
var firstContentLine string
984-
for _, line := range lines {
985-
if !strings.HasPrefix(line, "time=") {
986-
firstContentLine = line
987-
break
988-
}
989-
}
990-
991-
// First content line should be frontmatter delimiter
992-
if firstContentLine != "---" {
993-
t.Errorf("expected first content line to be '---', got %q", firstContentLine)
994-
}
995-
996-
// Should contain task frontmatter fields
997-
if !strings.Contains(output, "task_name: test-task") {
998-
t.Errorf("task frontmatter field 'task_name' not found in output")
977+
// Task frontmatter fields should NOT be in the output
978+
if strings.Contains(output, "task_name: test-task") {
979+
t.Errorf("task frontmatter field 'task_name' should not be in output")
999980
}
1000-
if !strings.Contains(output, "author: tester") {
1001-
t.Errorf("task frontmatter field 'author' not found in output")
981+
if strings.Contains(output, "author: tester") {
982+
t.Errorf("task frontmatter field 'author' should not be in output")
1002983
}
1003-
if !strings.Contains(output, "version: 1.0") {
1004-
t.Errorf("task frontmatter field 'version' not found in output")
984+
if strings.Contains(output, "version: 1.0") {
985+
t.Errorf("task frontmatter field 'version' should not be in output")
1005986
}
1006987

1007-
// Find the second --- (end of frontmatter)
1008-
secondDelimiterIdx := -1
1009-
for i := 1; i < len(lines); i++ {
1010-
if lines[i] == "---" {
1011-
secondDelimiterIdx = i
1012-
break
1013-
}
1014-
}
1015-
if secondDelimiterIdx == -1 {
1016-
t.Errorf("expected to find closing frontmatter delimiter '---'")
988+
// Rule frontmatter should NOT be printed
989+
if strings.Contains(output, "language: go") {
990+
t.Errorf("rule frontmatter should not be printed in output")
1017991
}
1018992

1019-
// Rule content should appear after frontmatter
993+
// Rule content should be in the output
1020994
if !strings.Contains(output, "# Test Rule") {
1021995
t.Errorf("rule content not found in output")
1022996
}
1023997

1024-
// Task content should appear after rules
998+
// Task content should be in the output
1025999
if !strings.Contains(output, "# Test Task") {
10261000
t.Errorf("task content not found in output")
10271001
}
10281002

1029-
// Verify order: frontmatter should come before rules, rules before task content
1030-
frontmatterIdx := strings.Index(output, "task_name: test-task")
1003+
// Verify order: rules should appear before task content
10311004
ruleIdx := strings.Index(output, "# Test Rule")
10321005
taskIdx := strings.Index(output, "# Test Task")
10331006

1034-
if frontmatterIdx == -1 || ruleIdx == -1 || taskIdx == -1 {
1007+
if ruleIdx == -1 || taskIdx == -1 {
10351008
t.Fatalf("could not find all required sections in output")
10361009
}
10371010

1038-
if frontmatterIdx > ruleIdx {
1039-
t.Errorf("frontmatter should appear before rules")
1040-
}
10411011
if ruleIdx > taskIdx {
10421012
t.Errorf("rules should appear before task content")
10431013
}
1044-
1045-
// Rule frontmatter should NOT be printed
1046-
if strings.Contains(output, "language: go") {
1047-
t.Errorf("rule frontmatter should not be printed in output")
1048-
}
10491014
}
10501015

10511016
func TestTaskBootstrapFromFile(t *testing.T) {

main.go

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"strings"
1212
"syscall"
1313

14-
yaml "github.com/goccy/go-yaml"
1514
"github.com/kitproj/coding-context-cli/pkg/codingcontext"
1615
"github.com/kitproj/coding-context-cli/pkg/codingcontext/selectors"
1716
"github.com/kitproj/coding-context-cli/pkg/codingcontext/taskparser"
@@ -144,40 +143,12 @@ func main() {
144143
logger.Info("Rules written", "path", rulesFile)
145144
}
146145

147-
// Output only task frontmatter and content
148-
if taskContent := result.Task.FrontMatter.Content; taskContent != nil {
149-
fmt.Println("---")
150-
if err := yaml.NewEncoder(os.Stdout).Encode(taskContent); err != nil {
151-
logger.Error("Failed to encode task frontmatter", "error", err)
152-
os.Exit(1)
153-
}
154-
fmt.Println("---")
155-
}
146+
// Output only task content (task frontmatter is not included)
156147
fmt.Println(result.Task.Content)
157148
} else {
158149
// Normal mode: output everything
159-
// Output task frontmatter (always enabled)
160-
if taskContent := result.Task.FrontMatter.Content; taskContent != nil {
161-
fmt.Println("---")
162-
if err := yaml.NewEncoder(os.Stdout).Encode(taskContent); err != nil {
163-
logger.Error("Failed to encode task frontmatter", "error", err)
164-
os.Exit(1)
165-
}
166-
fmt.Println("---")
167-
}
168-
169-
// Output available skills metadata (progressive disclosure)
170-
if len(result.Skills.Skills) > 0 {
171-
skillsXML, err := result.Skills.AsXML()
172-
if err != nil {
173-
logger.Error("Failed to encode skills as XML", "error", err)
174-
os.Exit(1)
175-
}
176-
fmt.Println(skillsXML)
177-
fmt.Println()
178-
}
179-
180-
// Output the combined prompt (rules + task)
150+
// Output the combined prompt (rules + skills + task)
151+
// Note: Task frontmatter is not included in the output
181152
fmt.Println(result.Prompt)
182153
}
183154
}

0 commit comments

Comments
 (0)