Status
Scope reshaped 2026-05-13 after Aaron's design conversation. Original "pre-fill the path" issue evolved into a coherent capture-classification model. Note: notes#130 (merged) shipped the initial `quickPath()` pre-fill — this issue now covers the remaining reshape work: hierarchical tag-role defaults + idempotent schema setup. The full audit UI is split out to notes#129.
Design model
Path = organizational structure (where the file lives). Default: `Notes//` for ALL captures (text + audio). User can override per-capture or per-vault.
Tag = semantic classification (what the file IS). Default Tag Role values shift to hierarchical:
- `captureText` → `capture/text` (with `parent_names: ["capture"]`)
- `captureVoice` → `capture/voice` (with `parent_names: ["capture"]`)
Why capture/* not note/*: in vault, EVERY note is a note. Tagging one `#note` is tautological — adds no signal. `#capture` distinguishes notes-the-user-captured from imported / generated / derived ones. That's a real semantic axis. Plus your Tag Role keys already say "captureText"/"captureVoice" — the noun `capture` is already in the vocabulary.
Hierarchy via parent_names (vault feature, see `parachute-vault/core/src/notes.ts:425`):
- `tag: "capture"` query → returns notes with `capture/text` OR `capture/voice` (descendants auto-expanded).
- Future extensions like `capture/photo`, `capture/web-clip` slot in without renaming.
What to ship
- Update Tag Role defaults:
captureText → capture/text, captureVoice → capture/voice in `tag-roles.ts`.
- New file
src/lib/vault/schema.ts declaring `NOTES_REQUIRED_SCHEMA`:
export const NOTES_REQUIRED_SCHEMA = {
tags: [
{ name: "capture", description: "Notes captured directly by user (text or voice)" },
{ name: "capture/text", parent_names: ["capture"], description: "Text capture" },
{ name: "capture/voice", parent_names: ["capture"], description: "Voice capture" },
],
};
- Idempotent
update-tag on first capture-per-role: when Capture saves a note with role-applied tag, ensure the parent + child exist with correct `parent_names`. Calls are idempotent — already-correct tags are no-ops.
- Existing vaults preserve their values: if user has `captureText = "quick"` (current default from rc.6), that stays. The schema-ensure call still ensures `capture` parent + children exist, but doesn't change their Tag Role choices.
- Fix path-collision concern (raised in notes#130 review): regenerate `quickPath()` on
reset() when the operator hasn't manually edited the path. Two captures in the same second should produce distinct paths.
Not in scope
- Full Settings audit UI + connect-time banner → notes#129.
- Per-vault customization of path templates → notes#128 research scope.
Acceptance
- New vault first capture: schema is auto-set up (`capture` parent + `capture/text` child with `parent_names`).
- Existing vault first capture: Tag Role values respected; schema still ensures parents/children exist.
- Hierarchical query works: a note tagged `capture/text` matches a query for `capture`.
- Multi-capture-in-one-second produces distinct paths.
- Tests cover all four cases.
Related
- notes#130 — shipped initial `quickPath()` pre-fill (this reshape builds on it).
- notes#129 — schema-ensure UI follow-up.
- patterns#57 — surface-declares-required-schema pattern (this is the first instance).
Status
Scope reshaped 2026-05-13 after Aaron's design conversation. Original "pre-fill the path" issue evolved into a coherent capture-classification model. Note: notes#130 (merged) shipped the initial `quickPath()` pre-fill — this issue now covers the remaining reshape work: hierarchical tag-role defaults + idempotent schema setup. The full audit UI is split out to notes#129.
Design model
Path = organizational structure (where the file lives). Default: `Notes//` for ALL captures (text + audio). User can override per-capture or per-vault.
Tag = semantic classification (what the file IS). Default Tag Role values shift to hierarchical:
Why
capture/*notnote/*: in vault, EVERY note is a note. Tagging one `#note` is tautological — adds no signal. `#capture` distinguishes notes-the-user-captured from imported / generated / derived ones. That's a real semantic axis. Plus your Tag Role keys already say "captureText"/"captureVoice" — the noun `capture` is already in the vocabulary.Hierarchy via parent_names (vault feature, see `parachute-vault/core/src/notes.ts:425`):
What to ship
captureText→capture/text,captureVoice→capture/voicein `tag-roles.ts`.src/lib/vault/schema.tsdeclaring `NOTES_REQUIRED_SCHEMA`:update-tagon first capture-per-role: when Capture saves a note with role-applied tag, ensure the parent + child exist with correct `parent_names`. Calls are idempotent — already-correct tags are no-ops.reset()when the operator hasn't manually edited the path. Two captures in the same second should produce distinct paths.Not in scope
Acceptance
Related