Skip to content

Commit 8b2a8c8

Browse files
HamptonMakesclaude
andauthored
Ship default plan types with templates, installable via rake (#187)
* Ship default plan types with templates, installable via rake Eleven default plan types as markdown files (YAML front matter + template body) under engine/db/default_plan_types/: Engineering Design, Exploration, PRD, Project 1-Pager, Research, Technical Documentation, Implementation Plan, Test Plan, Handoff, Scratchpad, General. Each description names the audience and moment of reading; templates carry per-section guidance as HTML comments (invisible on render, visible to agents reading template_content). Scratchpad and General deliberately ship without templates; no default_tags are set (tags stay orthogonal to types). PlanTypes::InstallDefaults creates missing types and fills blank fields on existing ones — a host's hand-edited descriptions and templates are never overwritten unless force. Exposed as `rails coplan:plan_types:install_defaults` (FORCE=1 to overwrite) and wired into the engine seed, so fresh installs get the full set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: deterministic installer specs, force restores blank shipped values The installer specs assumed an empty coplan_plan_types table, but the PG CI job seeds before rspec and a data migration installs General — start from a clean table like engine_seed_spec does. FORCE=1 now means "back to the shipped defaults" on every field: a custom template or default_tags on a type that ships without them (Scratchpad, General) is cleared instead of surviving the overwrite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent df80e70 commit 8b2a8c8

16 files changed

Lines changed: 564 additions & 19 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
module CoPlan
2+
module PlanTypes
3+
# Installs the plan types shipped with the engine
4+
# (engine/db/default_plan_types/*.md — YAML front matter for the
5+
# attributes, Markdown body as the template).
6+
#
7+
# Admin edits are data, defaults are code, and the defaults must never
8+
# silently clobber the data: without `force`, existing types only gain
9+
# values for fields that are currently blank (the common upgrade case —
10+
# a type created before templates existed gets the default template,
11+
# but a hand-written description survives). With `force`, the shipped
12+
# defaults win on every field — blank shipped values included, so a
13+
# custom template on a type that ships without one (Scratchpad, General)
14+
# is cleared. Types unknown to the defaults are never touched either way.
15+
class InstallDefaults
16+
DEFAULTS_DIR = CoPlan::Engine.root.join("db", "default_plan_types")
17+
FRONT_MATTER = /\A---\n(?<yaml>.*?)\n---\n?(?<body>.*)\z/m
18+
19+
Result = Struct.new(:created, :updated, :skipped, keyword_init: true)
20+
21+
def self.call(force: false, dir: DEFAULTS_DIR)
22+
new(force:, dir:).call
23+
end
24+
25+
def initialize(force: false, dir: DEFAULTS_DIR)
26+
@force = force
27+
@dir = Pathname(dir)
28+
end
29+
30+
def call
31+
result = Result.new(created: [], updated: [], skipped: [])
32+
33+
@dir.glob("*.md").sort.each do |path|
34+
attrs = parse(path)
35+
type = PlanType.find_by_name(attrs[:name])
36+
37+
if type.nil?
38+
PlanType.create!(**attrs)
39+
result.created << attrs[:name]
40+
elsif apply(type, attrs)
41+
result.updated << attrs[:name]
42+
else
43+
result.skipped << attrs[:name]
44+
end
45+
end
46+
47+
result
48+
end
49+
50+
private
51+
52+
def parse(path)
53+
match = FRONT_MATTER.match(path.read)
54+
raise ArgumentError, "#{path.basename}: missing YAML front matter" unless match
55+
56+
meta = YAML.safe_load(match[:yaml]) || {}
57+
name = meta["name"].to_s.strip
58+
raise ArgumentError, "#{path.basename}: front matter needs a name" if name.empty?
59+
60+
{
61+
name: name,
62+
description: meta["description"].to_s.strip.presence,
63+
icon: meta["icon"].to_s.strip.presence,
64+
default_tags: Array(meta["default_tags"]).map(&:to_s),
65+
template_content: match[:body].strip.presence
66+
}
67+
end
68+
69+
# Assigns default values onto an existing type; returns whether
70+
# anything changed. Only blank fields are filled unless forcing;
71+
# forcing restores the shipped value even when it's blank.
72+
def apply(type, attrs)
73+
attrs.except(:name).each do |field, value|
74+
next if value.blank? && !@force
75+
next unless @force || type[field].blank?
76+
77+
type[field] = value
78+
end
79+
return false unless type.changed?
80+
81+
type.save!
82+
true
83+
end
84+
end
85+
end
86+
end
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
name: Engineering Design
3+
icon: scroll
4+
description: >-
5+
A formal record of a technical design decision, written for reviewers
6+
deciding whether to build it and maintainers later asking why it was.
7+
Alternatives weighed, risks named. Still exploring options? Use
8+
Exploration instead.
9+
---
10+
<!-- Engineering Design: a decision record. The reader is a reviewer with
11+
five minutes, then a maintainer two years from now. Keep the whole
12+
document readable in five minutes. Delete these comments as you fill
13+
each section in. -->
14+
15+
## Problem
16+
17+
<!-- 2-3 sentences. What breaks, or stays broken, if nothing is done.
18+
State it plainly - no selling. -->
19+
20+
## Constraints
21+
22+
<!-- The non-negotiables: compatibility requirements, deadlines, systems
23+
that must not change, budgets. These justify the design below. -->
24+
25+
## Design
26+
27+
<!-- What will be built. Lead with a mermaid diagram when structure or
28+
flow explains it faster than prose. Be concrete: component names,
29+
boundaries, data shapes, failure behavior. -->
30+
31+
## Alternatives considered
32+
33+
<!-- One row per real alternative, including "do nothing". A design
34+
without alternatives reads as a decision that was never examined.
35+
36+
| Option | Why not |
37+
|--------|---------|
38+
-->
39+
40+
## Risks
41+
42+
<!-- What could go wrong with the chosen design, and how you would
43+
notice it happening. -->
44+
45+
## Rollout
46+
47+
<!-- How it ships safely: order of changes, flags, data migration, and
48+
the way back if it goes wrong. -->
49+
50+
## Open questions
51+
52+
<!-- Decisions deliberately not made yet, and what resolves each one. -->
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: Exploration
3+
icon: compass
4+
description: >-
5+
Working through a problem that is not decided yet - candidate
6+
approaches, sketches, code samples, tradeoffs. The reader is you, your
7+
collaborators, and the agent working alongside you. When one approach
8+
wins, retype this as an Engineering Design and restructure.
9+
---
10+
<!-- Exploration: thinking in progress, shared. Structure is loose on
11+
purpose - fragments and code samples are welcome. Keep dead ends in the
12+
document: they save the next reader from redigging the same hole. -->
13+
14+
## Question
15+
16+
<!-- One line: what are we trying to figure out? -->
17+
18+
## Approaches
19+
20+
<!-- One ### subsection per approach. Sketch it, code-sample it, note
21+
what it costs and what it buys. -->
22+
23+
## Current leaning
24+
25+
<!-- Which way you are leaning, and why. -->
26+
27+
## What would change my mind
28+
29+
<!-- The facts, measurements, or results that would flip the leaning. -->
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
name: General
3+
icon: file-text
4+
description: >-
5+
A plan that fits no other type. Check the type list before choosing
6+
this - a more specific type almost always exists.
7+
---
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: Handoff
3+
icon: file-text
4+
description: >-
5+
State transfer at the end of a work session - agent or human - for
6+
whoever picks the work up next. Optimize their first ten minutes.
7+
Archive it once it has been picked up.
8+
---
9+
<!-- Handoff: written for whoever continues this work, possibly with
10+
none of your context. Links beat prose - every claim of "done" carries
11+
its artifact. -->
12+
13+
## Goal of the work
14+
15+
<!-- What the overall effort is trying to achieve, in a line or two. -->
16+
17+
## Done
18+
19+
<!-- What is complete, each item with its artifact link: PR, commit,
20+
plan, document. -->
21+
22+
## Not done
23+
24+
<!-- What remains. Be honest - this list is why the handoff exists. -->
25+
26+
## Decisions made
27+
28+
<!-- Choices settled during the session and the reasoning, so the next
29+
person doesn't relitigate them. -->
30+
31+
## Landmines
32+
33+
<!-- Gotchas discovered the hard way: flaky tests, misleading names,
34+
things that look broken but aren't. -->
35+
36+
## Next steps
37+
38+
<!-- Where to start, in order. The first item is the very next action. -->
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
name: Implementation Plan
3+
icon: map
4+
description: >-
5+
A step-by-step plan for building a specific change - the document an
6+
agent or engineer executes. Steps are checkboxes with a verification
7+
each. The reader is whoever does the work, and whoever approves it
8+
first.
9+
---
10+
<!-- Implementation Plan: a living checklist. Check steps off as you
11+
execute - the checkboxes are the plan's state, so no separate status
12+
notes. Each step needs a way to verify it worked. -->
13+
14+
## Goal
15+
16+
<!-- The end state, in 1-2 sentences. -->
17+
18+
## Current state
19+
20+
<!-- What exists now, with the file and repo references the executor
21+
starts from. -->
22+
23+
## Steps
24+
25+
<!-- Each step: a concrete action and how to verify it worked. Split
26+
any step you cannot verify. -->
27+
28+
- [ ] First step — verify: …
29+
- [ ] Second step — verify: …
30+
31+
## Risks & rollback
32+
33+
<!-- What might break while executing, and the way back if it does. -->
34+
35+
## Out of scope
36+
37+
<!-- Nearby work this plan deliberately does not touch. -->
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: PRD
3+
icon: scale
4+
description: >-
5+
A product requirements document: what to build and why, for the team
6+
building it and the stakeholders agreeing to it. The how belongs in an
7+
Engineering Design.
8+
---
9+
<!-- PRD: the agreement about what gets built. Requirements must be
10+
testable statements - if you cannot check it, it is not a requirement. -->
11+
12+
## Problem
13+
14+
<!-- Who has the problem, when it bites them, and the evidence it is
15+
real. -->
16+
17+
## Goals
18+
19+
<!-- What done looks like, as outcomes - not a feature list. -->
20+
21+
## Non-goals
22+
23+
<!-- What this deliberately does not do. As load-bearing as the goals:
24+
scope disputes get settled here. -->
25+
26+
## Requirements
27+
28+
<!-- Numbered, each marked Must or Should, each testable. -->
29+
30+
## Success metrics
31+
32+
<!-- How you will know it worked: measurable, with the current baseline
33+
when known. -->
34+
35+
## Open questions
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: Project 1-Pager
3+
icon: rocket
4+
description: >-
5+
A one-page pitch for a project: the problem, the bet, what it costs,
6+
what changes if it works. The reader has ten minutes and decides
7+
whether this deserves investment. Persuasive language is welcome in
8+
this type - but every claim still needs a specific behind it.
9+
---
10+
<!-- Project 1-Pager: the whole case on one page. This type overrides
11+
the default writing-style rules: persuasion is allowed. Specifics are
12+
still required - an adjective is not evidence. If it runs past a page,
13+
cut until it fits. -->
14+
15+
## The problem
16+
17+
<!-- What hurts today, for whom, and what it costs to leave alone. -->
18+
19+
## The bet
20+
21+
<!-- What we would do, and the outcome we believe it produces. -->
22+
23+
## What it takes
24+
25+
<!-- People, time, dependencies. Honest costs - a pitch that hides the
26+
bill gets one meeting. -->
27+
28+
## What changes if it works
29+
30+
<!-- The after-state, concretely. Numbers where you have them. -->
31+
32+
## Why now
33+
34+
<!-- What makes this the right moment rather than next quarter. -->
35+
36+
## Open questions
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: Research
3+
icon: flask
4+
description: >-
5+
Findings from an information-gathering run - internal systems,
6+
history, competitive analysis, legal, external sources. Every claim
7+
carries a footnote citation to a durable source and the date it was
8+
confirmed. The reader acts on the findings without redoing the work.
9+
---
10+
<!-- Research: the reader trusts this document instead of re-searching.
11+
That trust is built one citation at a time - every claim gets a
12+
footnote[^like-this] with a durable source link and the date you
13+
confirmed it. Dates on facts are required here; dates on the document
14+
are still banned. -->
15+
16+
## Question
17+
18+
<!-- What this research set out to answer. -->
19+
20+
## Answer
21+
22+
<!-- The findings up front, in a few sentences: your best supported
23+
answer and how confident you are. Not "it depends". -->
24+
25+
## Findings
26+
27+
<!-- One ### subsection per finding. Cite every claim. Distinguish what
28+
a source says from what you infer. -->
29+
30+
## What we still don't know
31+
32+
<!-- The gaps and unconfirmed claims, and what it would take to close
33+
each one. -->
34+
35+
## Method
36+
37+
<!-- Where you looked, briefly - enough for someone to extend the
38+
search, not a diary of it. -->
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
name: Scratchpad
3+
icon: lightbulb
4+
description: >-
5+
A brainstorming space with no structure required - not expected to be
6+
readable by anyone else yet. When it firms up, retype it (usually as
7+
an Exploration or Engineering Design) and restructure.
8+
---

0 commit comments

Comments
 (0)