Skip to content

Commit a3723ba

Browse files
committed
feat: add entry templates for rich learnings and decisions
- Add .context/templates/ with learning.md and decision.md templates - Templates are copied during ctx init for --file usage - Document rich entry workflow in AGENT_PLAYBOOK.md - Completes Phase 13: Rich Context Entries Signed-off-by: Jose Alekhinne <alekhinejose@gmail.com>
1 parent 628fe0b commit a3723ba

6 files changed

Lines changed: 155 additions & 4 deletions

File tree

.context/AGENT_PLAYBOOK.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,65 @@ For complex sessions (architecture, debugging), include:
167167
| Completed task | Mark [x] in TASKS.md |
168168
| Had important discussion | Save to sessions/ |
169169

170+
## Rich Entries with Templates
171+
172+
For complex learnings or decisions that need more structure, use the `--file` flag
173+
with entry templates located in `.context/templates/`.
174+
175+
### Available Templates
176+
177+
| Template | Structure | Use When |
178+
|----------|-----------|----------|
179+
| `learning.md` | Context → Lesson → Application | Documenting complex discoveries with actionable guidance |
180+
| `decision.md` | Context → Options → Decision → Rationale → Consequences | Recording architectural choices with full reasoning |
181+
182+
### Workflow: Inline vs File
183+
184+
**Use inline** (`ctx add learning "message"`) for:
185+
- Quick, simple observations
186+
- One-liner tips or gotchas
187+
- Discoveries that need no context
188+
189+
**Use --file** (`ctx add learning --file entry.md`) for:
190+
- Multi-paragraph explanations
191+
- Decisions requiring trade-off analysis
192+
- Learnings that need context and application guidance
193+
194+
### Example: Rich Learning
195+
196+
```bash
197+
# Copy template
198+
cp .context/templates/learning.md /tmp/my-learning.md
199+
200+
# Edit with your content
201+
# Then add:
202+
ctx add learning --file /tmp/my-learning.md
203+
```
204+
205+
### Example: Rich Decision
206+
207+
```bash
208+
# Copy template
209+
cp .context/templates/decision.md /tmp/my-decision.md
210+
211+
# Fill in:
212+
# - Context: What situation prompted this?
213+
# - Options: What alternatives were considered?
214+
# - Decision: What was chosen?
215+
# - Rationale: Why this choice?
216+
# - Consequences: What changes as a result?
217+
218+
ctx add decision --file /tmp/my-decision.md
219+
```
220+
221+
### Stdin Support
222+
223+
You can also pipe content directly:
224+
```bash
225+
echo "Quick learning from exploration" | ctx add learning
226+
cat detailed-analysis.md | ctx add decision
227+
```
228+
170229
## Before Session Ends
171230

172231
**CRITICAL**: Before the user ends the session, offer to save context:

.context/TASKS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,6 @@
141141
### Phase 13: Rich Context Entries `#priority:medium` `#area:cli`
142142
- [x] Add --file flag to ctx add — read entry content from a file instead of CLI arg
143143
- [x] Add stdin support to ctx add — if no content arg and stdin is pipe, read from stdin
144-
- [ ] Create learning template with Context/Lesson/Application structure for --file usage
145-
- [ ] Create decision template with Context/Options/Decision/Rationale structure for --file usage
146-
- [ ] Document rich entry workflow in AGENT_PLAYBOOK.md — explain when/how agents should use --file vs inline
144+
- [x] Create learning template with Context/Lesson/Application structure for --file usage
145+
- [x] Create decision template with Context/Options/Decision/Rationale structure for --file usage
146+
- [x] Document rich entry workflow in AGENT_PLAYBOOK.md — explain when/how agents should use --file vs inline

internal/cli/init.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ func runInit(cmd *cobra.Command, _ []string) error {
151151

152152
cmd.Printf("\n%s initialized in %s/\n", green("Context"), contextDir)
153153

154+
// Create entry templates in .context/templates/
155+
if err := createEntryTemplates(cmd, contextDir, initForce); err != nil {
156+
// Non-fatal: warn but continue
157+
cmd.Printf(" %s Entry templates: %v\n", color.YellowString("⚠"), err)
158+
}
159+
154160
// Create IMPLEMENTATION_PLAN.md in project root (orchestrator directive)
155161
if err := createImplementationPlan(cmd, initForce); err != nil {
156162
// Non-fatal: warn but continue
@@ -493,6 +499,47 @@ func updateCtxSection(cmd *cobra.Command, existing string, newTemplate []byte, g
493499
return nil
494500
}
495501

502+
// createEntryTemplates creates .context/templates/ with entry templates for rich entries.
503+
// These templates help users format detailed learnings and decisions using --file flag.
504+
func createEntryTemplates(cmd *cobra.Command, contextDir string, force bool) error {
505+
green := color.New(color.FgGreen).SprintFunc()
506+
yellow := color.New(color.FgYellow).SprintFunc()
507+
508+
templatesDir := filepath.Join(contextDir, "templates")
509+
if err := os.MkdirAll(templatesDir, 0755); err != nil {
510+
return fmt.Errorf("failed to create %s: %w", templatesDir, err)
511+
}
512+
513+
// Get list of entry templates
514+
entryTemplates, err := templates.ListEntryTemplates()
515+
if err != nil {
516+
return fmt.Errorf("failed to list entry templates: %w", err)
517+
}
518+
519+
for _, name := range entryTemplates {
520+
targetPath := filepath.Join(templatesDir, name)
521+
522+
// Check if file exists and --force not set
523+
if _, err := os.Stat(targetPath); err == nil && !force {
524+
cmd.Printf(" %s templates/%s (exists, skipped)\n", yellow("○"), name)
525+
continue
526+
}
527+
528+
content, err := templates.GetEntryTemplate(name)
529+
if err != nil {
530+
return fmt.Errorf("failed to read entry template %s: %w", name, err)
531+
}
532+
533+
if err := os.WriteFile(targetPath, content, 0644); err != nil {
534+
return fmt.Errorf("failed to write %s: %w", targetPath, err)
535+
}
536+
537+
cmd.Printf(" %s templates/%s\n", green("✓"), name)
538+
}
539+
540+
return nil
541+
}
542+
496543
// checkCtxInPath verifies that ctx is available in PATH.
497544
// The hooks use "ctx" expecting it to be in PATH, so init should fail
498545
// if the user hasn't installed ctx globally yet.

internal/templates/embed.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package templates
99

1010
import "embed"
1111

12-
//go:embed *.md
12+
//go:embed *.md entry-templates/*.md
1313
var FS embed.FS
1414

1515
// GetTemplate reads a template file by name from the embedded filesystem.
@@ -32,3 +32,24 @@ func ListTemplates() ([]string, error) {
3232
}
3333
return names, nil
3434
}
35+
36+
// ListEntryTemplates returns available entry template file names.
37+
func ListEntryTemplates() ([]string, error) {
38+
entries, err := FS.ReadDir("entry-templates")
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
names := make([]string, 0, len(entries))
44+
for _, entry := range entries {
45+
if !entry.IsDir() {
46+
names = append(names, entry.Name())
47+
}
48+
}
49+
return names, nil
50+
}
51+
52+
// GetEntryTemplate reads an entry template by name.
53+
func GetEntryTemplate(name string) ([]byte, error) {
54+
return FS.ReadFile("entry-templates/" + name)
55+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## [Decision Title]
2+
3+
**Status**: Accepted | Proposed | Superseded | Deprecated
4+
5+
**Context**: [What situation prompted this decision? What problem are we solving?]
6+
7+
**Options Considered**:
8+
1. **Option A**: [Description] - Pros: [...] Cons: [...]
9+
2. **Option B**: [Description] - Pros: [...] Cons: [...]
10+
11+
**Decision**: [What was decided?]
12+
13+
**Rationale**: [Why was this the right choice? What trade-offs were made?]
14+
15+
**Consequences**: [What are the implications? What changes as a result?]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### [Title - What was learned]
2+
3+
**Discovered**: [Date/Session context]
4+
5+
**Context**: [What situation prompted this discovery? What were you trying to do?]
6+
7+
**Lesson**: [What did you learn? Be specific and actionable.]
8+
9+
**Application**: [How should this be applied going forward? When does this matter?]

0 commit comments

Comments
 (0)