aboutsummaryrefslogtreecommitdiff
path: root/docs/design/2026-07-15-subprojects-convention-home-instance.org
blob: a1c4397438f7925f9edc14c991d7ffda6dcf3627 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#+TITLE: Subprojects — Convention
#+AUTHOR: Craig Jennings
#+DATE: 2026-07-15

# The reference spec for the subproject pattern: what a subproject is, when to
# create one (consolidation), how to keep it legible (the brief + content
# split), and how to archive one cleanly. Not read every session — the
# always-on parts (the subproject index + the read-first rule) live in
# notes.org and point here. Read this when consolidating a project, creating
# or maintaining a subproject brief, or archiving a subproject.

* Vocabulary (say it the same way every time)

The terminology is the point — it's what lets us talk precisely about where a
subproject's documents and assets live, and archive them cleanly.

- *Parent project* (a.k.a. hub) — a top-level project that owns an =.ai/=
  scope: its own protocols, session cadence, memory, inbox, todo. home, work,
  rulesets, .emacs.d are parent projects. Reached by launching an agent
  session in its directory.
- *Subproject* — a formerly-standalone project that has been *consolidated*
  into a parent and now lives as a subdirectory of it (=danneel/=,
  =finances/=, =kit/= …). A subproject shares the parent's =.ai/= tooling and
  session — it is not a separate agent scope — but keeps its own working
  files, assets, notes, and history self-contained under its one subdirectory.
- *Consolidation* — the process of turning a standalone project into a
  subproject of a parent. (home's nine subprojects were consolidated on
  2026-06-11.) The inverse — promoting a subproject back to a standalone
  project — is rare but allowed; it's just consolidation run backward.
- *Subproject archiving* — retiring a completed or abandoned subproject
  cleanly. Because a subproject is self-contained under one subdirectory,
  archiving is a move plus a pointer reconcile, not an excavation.
- *Subproject brief* — the read-first orientation doc for one subproject, at
  =<subproject>/<subproject>-brief.org=.

The cross-project boundary rule (=claude-rules/cross-project.md=) governs
*parent* projects, which are separate =.ai/= scopes. It does *not* apply
between a parent and its subprojects — they share one scope.

* Why the pattern exists

As a standalone project, each of these units auto-loaded its own notes.org —
its full depth — at every startup, so recall felt instant. Consolidated into a
parent, a subproject is one compressed section competing with the others, and
the parent's startup surfaces hub-wide state, not any one subproject's depth.
So a session starts cold on a given subproject and re-reads several files on
demand. This convention restores fast, accurate orientation without
re-bloating what loads every session — and gives consolidation and archiving a
named, repeatable shape.

* Document & asset location (what makes clean archiving possible)

Everything for a subproject lives under =<subproject>/= — its =notes.org=,
=assets/=, working files, event log, briefs. Links *within* a subproject are
relative to the subproject dir, so the whole tree can move without breaking
them. The parent's own top-level =assets/= is for parent-level material only,
never a subproject's. This self-containment is exactly what lets archiving be
a single =mv= plus a pointer reconcile. Keep it strict: a subproject's asset
in the parent's shared =assets/= is a future broken link.

* The two layers (parent vs subproject)

- *Always-on layer* — the parent's notes.org. Read at every startup, so every
  line is a tax paid whether or not it's relevant today. Holds only what must
  be seen session-independently.
- *On-demand layer* — the subproject brief + the subproject's notes.org.
  Loaded only when working that subproject. Holds the depth.

The whole design is: sort content by *when it's needed*, keep the always-on
layer thin, put the depth one open away.

* Creating a subproject (consolidation criteria)

Consolidate a standalone project into a parent as a subproject when *all* hold:

1. *Domain fit* — the project is a facet of a domain the parent already owns
   (danneel is home life-admin; finances is home).
2. *Low independent cadence* — it no longer needs its own session rhythm.
   You'd rather reach it from the parent than launch it standalone, and its
   standalone startup/sync/session overhead now outweighs the isolation.
3. *Shared-scope safety* — it does not need a git/remote/visibility posture
   distinct from the parent. A public code project, a team repo, or anything
   with its own CI or gitignore-privacy posture *stays standalone* — folding
   it would break the parent's privacy model (see
   =claude-rules/git-hosting-privacy-model= and the gitignore-vs-track
   decision). Personal/documentation units fold; code-with-a-public-remote
   does not.
4. *No independent collaborators* depend on it as a standalone deliverable.

Keep it standalone when any of those fail: active independent development, its
own team or remote, a distinct visibility/security posture, or activity high
enough that competing in the parent's hub would bury it.

*The consolidation act itself* (mechanics, mirroring home's 2026-06-11 fold):
move the project tree under the parent as =<parent>/<subproject>/=; import its
tasks into the parent's todo with an area =:tag:= and a =:MIGRATED_FROM:=
property; fold its live reminders/decisions into the parent's notes as
pointers (see the content split); build the subproject brief; record the fold
in a consolidation manifest (=docs/consolidation-manifest-<subproject>.org=).
Retire the source to =~/projects/.retired/<name>= once parity is verified.

* The subproject brief

** Path (fixed — discovery is mechanical)

=<subproject>/<subproject>-brief.org= (=danneel/danneel-brief.org=,
=finances/finances-brief.org=). The subproject name is the directory name, so
the brief name follows for free. One predictable name means the read-first
rule never has to hunt; put descriptive richness *inside*, not in the filename.

** Spine (scales from light to deep)

Required in every brief, even a fifteen-line one:
- *One-paragraph situation* — what this subproject is, in plain language.
- *Current state / open threads* — the live stuff. The only high-churn
  section; everything else is stable.
- *Reading list* — the subproject's deeper files and what each holds. The
  brief *points into* notes.org and the rest; it does not copy them.

Add only where the subproject warrants it (danneel, jr-estate, finances earn
all of these; elibrary or documents may earn none):
- Cast / contacts.
- Timeline (for matters with history).
- Key facts / numbers, with explicit *verify* flags anywhere the underlying
  record disagrees with itself. A brief that asserts a wrong number is worse
  than no brief — flag, don't guess.

** Read-first rule (the behavior)

When a session's work targets a subproject — a file under =<subproject>/=, its
=:tag:=, or Craig naming the topic — open =<subproject>/<subproject>-brief.org=
*first*, before touching anything else in it. If the subproject has no brief
yet, creating it is the first step of the work (lazy backfill), and the same
pass reconciles that subproject's parent-vs-subproject content.

* Parent-vs-subproject content criterion

The test for any piece of content: *if next session I'm working a different
subproject, do I still need to see this?* Three bins:

1. *Yes, and it's a fact or policy* → hub-level → the parent's notes.org.
   Machine names, mail policy, calendar access, the hub map, the subproject
   index.
2. *Yes, but only because it's urgent* — a deadline or blocking status that
   would be missed if it only lived where I might not look this week → the
   parent holds a *one-line pointer* (item + date + "see the subproject
   brief"); the substance stays in the subproject.
3. *No* → the subproject. Working depth: contacts, contract facts, case
   theory, evidence, document index, and any reminder that isn't time-critical.

One hard rule over both axes: *one fact, one home.* The parent never copies
subproject substance — it points. The parent holds the trigger; the subproject
holds the truth. Every parent↔subproject duplicate is a second surface that
goes stale.

* Archiving a subproject (archiving criteria + clean process)

Archive a subproject when it reaches a *terminal* state:
- *Complete* — the work is done and closed (a settlement signed, a probate
  closed, a trip finished): no live threads, no open tasks, nothing
  time-sensitive in the parent still pointing at it; or
- *Abandoned / superseded* — dropped, or replaced by other work.

Clean archive process (self-containment is what makes each step a one-liner):
1. Close or settle its tasks in the parent's todo (DONE / CANCELLED), per the
   todo completion rules.
2. Move the whole subproject tree to the parent's archive:
   =<parent>/archive/<subproject>/= (keep it intact — archiving is reversible,
   not deletion).
3. Update inbound =file:= links that pointed into it (grep first, per the
   keep-links-current rule).
4. Move or retire its brief with it, and drop its row from the active
   subproject index (or mark it =archived= there).
5. Strip its pointers/reminders from the parent's always-on layer, and retire
   its =:tag:= from active use.
6. Record the archive in a manifest note
   (=docs/archive-manifest-<subproject>.org=): why, when, where it moved,
   what links were repointed. Mirrors the consolidation manifest.

The =:LAST_UPDATED:= on a brief plus "no open tasks under the tag" is the
signal a subproject is a candidate for archiving — surfaced at the review
cadence, never auto-archived.

* Freshness

- *Wrap-up hook*: at wrap-up, for each subproject touched this session, refresh
  its brief's Current-state section and bump its =:LAST_UPDATED:= date. Stable
  sections rarely change, so this is cheap.
- *Staleness nudge*: a brief whose =:LAST_UPDATED:= is old while its subproject
  was recently active is worth surfacing at startup.

* Self-improvement loop

Every real use emits a signal, and the signal is *captured*, not silently
acted on:
- Brief answers the question → *hit*.
- Brief is missing something, stale, or wrong → *miss*, logged in
  [[file:subprojects-log.org][subprojects-log.org]].
- Each miss drives *two* updates: *local* (fix that brief) and, if the same
  kind of miss recurs across subprojects, *structural* (fix this spine/spec,
  not just the one file). The structural half is the actual self-improvement —
  grow-and-refine from real use rather than rewriting from scratch (the ACE
  idea behind the =codify= skill).

* Metrics

Split by who can trust them.

*Process signals (I observe, cheaply):*
- *Orientation cost* — files/tool-calls before my first correct action in a
  subproject. Target: ~1 (the brief), occasionally a second deep dive.
- *Brief hit rate* — fraction of subproject questions answered from the brief
  alone. Should climb.
- *Freshness gap* — days between =:LAST_UPDATED:= and last subproject activity.
  Target ~0.

*Outcome signals (Craig is ground truth — weight these over the above):*
- *Craig-caught errors* — the real quality bar. Target: trend to zero. If
  briefs work, Craig stops catching me.
- *Felt speed* — did dropping into the subproject feel fast and right.

*Honesty caveat.* Most process signals are self-observed, and self-report is
biased toward "hit." So the external signals (Craig-caught errors, felt speed)
outrank mine, and the log is auditable so Craig can spot-check my self-grades.
The instrumentation must stay lighter than the briefs, or it rots like an
unmaintained brief. Small N, no clean A/B — this is directional evidence, not
proof.

* Review cadence

Fold a "subprojects health" check into the existing task-audit cadence: read
the log, look at the hit-rate / correction / freshness trends, flag any
subproject that's gone terminal (archive candidate), and check the
parent-vs-subproject criterion — anywhere the parent holds a copy where it
should hold a pointer. Decide continue / adjust / kill for the pattern itself.

* Kill criteria (falsifiable)

After ~6-8 subproject-sessions across ≥3 subprojects, drop or rework the
pattern if:
- the correction rate isn't falling, or Craig is still catching errors; or
- the freshness gap keeps reopening despite the wrap-up hook; or
- maintenance costs more time than the orientation it saves.

Success is the mirror: orientation down to ~1 read, Craig catching ~nothing,
briefs current, and I'm right fast in any subproject cold.

* Rollout

- Define the convention (this file) + the index scaffold in notes.org. Done
  2026-07-15.
- *Lazy backfill*: the next session that touches a subproject with no brief
  creates the brief as its first step — cost paid exactly when it's used.
- *Reconcile in the same pass*: building a subproject's brief includes
  reconciling its parent-vs-subproject content — push substance down, leave
  pointers up, drop dead reminders.
- *Promotion*: this pattern is home-instanced but general. Consolidation into
  subprojects will recur whenever any project folds into another, so this is a
  candidate to promote into the rulesets rules layer (proposed to rulesets
  2026-07-15).

* Adoption status

| Subproject | Brief exists | Reconciled | Notes                                 |
|------------+--------------+------------+---------------------------------------|
| danneel    | yes          | yes        | First worked instance, 2026-07-15.    |
|------------+--------------+------------+---------------------------------------|
| clipper    | no           | no         | Lazy backfill on next touch.          |
|------------+--------------+------------+---------------------------------------|
| documents  | no           | no         | Lazy backfill on next touch.          |
|------------+--------------+------------+---------------------------------------|
| elibrary   | no           | no         | No notes.org yet; lightest subproject.|
|------------+--------------+------------+---------------------------------------|
| finances   | no           | no         | Deep; earns the full spine.           |
|------------+--------------+------------+---------------------------------------|
| health     | no           | no         | Has its own notes.org.                |
|------------+--------------+------------+---------------------------------------|
| jr-estate  | no           | no         | Deep; earns the full spine.           |
|------------+--------------+------------+---------------------------------------|
| kit        | no           | no         | Lazy backfill on next touch.           |
|------------+--------------+------------+---------------------------------------|
| philosophy | no           | no         | Lazy backfill on next touch.          |