update to 0.7.1 and migration

This commit is contained in:
Jason Stedwell
2026-06-19 23:03:06 -05:00
parent 8bf9871dbe
commit aa00243987
60 changed files with 2026 additions and 576 deletions
@@ -4,6 +4,8 @@ Server: `https://goldbrainapi.mpm.to` (reverse proxy → Obsidian Local REST API
Auth header: `Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8`
The endpoint has a **valid TLS certificate**`-k` is not required. Paths address the vault at its **root**.
> **Prefer `scripts/goldbrain.sh` over the raw recipes below.** It wraps every verb with auth, status checking, retry, idempotent append, and frontmatter patches. The recipes here are the underlying mechanics and the fallback. **If you call `curl` directly, check the HTTP status** — add `-o /dev/null -w "%{http_code}"` and branch on it. A `PATCH` to a non-existent heading returns `400 invalid-target` (errorCode 40080) and the write is *silently lost*; a bare `curl` that ignores status will report success anyway. `GET` returns `404` for a missing file. Treat any `>= 400` as a failed operation, surface it, and do not continue as if it succeeded.
---
## Reading Files
@@ -50,7 +52,7 @@ Returns JSON: `{ "files": [...], "folders": [...] }`.
```bash
cat > /tmp/obs_entry.md << 'OBSEOF'
- 2026-06-02: your entry here
- 2026-06-05: your entry here
OBSEOF
curl -s -X POST \
@@ -71,8 +73,8 @@ cat > /tmp/obs_file.md << 'OBSEOF'
---
type: session-log
status: complete
created: 2026-06-02
updated: 2026-06-02
created: 2026-06-05
updated: 2026-06-05
tags: [agent, session]
agent_written: true
source_notes: []
@@ -88,7 +90,7 @@ curl -s -X PUT \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_file.md \
"https://goldbrainapi.mpm.to/vault/_agent/sessions/2026-06-02-1430-my-session.md"
"https://goldbrainapi.mpm.to/vault/_agent/sessions/2026-06-05-1430-my-session.md"
```
---
@@ -117,7 +119,7 @@ curl -s -X PUT \
```bash
cat > /tmp/obs_patch.md << 'OBSEOF'
Bryan prefers concise status updates lead with the decision.
Bryan prefers concise status updates - lead with the decision.
OBSEOF
curl -s -X PATCH \
@@ -145,7 +147,7 @@ Returns `{ "headings": [...], "blocks": [...], "frontmatterFields": [...] }`. Co
### Replace a heading's content entirely
Same call with `Operation: replace` — e.g. to refresh a project's `Project Name::Current status`.
Same call with `Operation: replace` — e.g. to refresh a project's `Project Name::Status`.
### Prepend under a heading
@@ -160,7 +162,7 @@ curl -s -X PATCH \
-H "Target-Type: frontmatter" \
-H "Target: updated" \
-H "Content-Type: application/json" \
--data '"2026-06-02"' \
--data '"2026-06-05"' \
"https://goldbrainapi.mpm.to/vault/projects/active/vault-foundation.md"
```
@@ -183,7 +185,7 @@ Returns an array of `{ filename, score, matches: [{ context, match }] }`.
```bash
curl -s -X DELETE \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/archive/notes/old-note.md"
"https://goldbrainapi.mpm.to/vault/inbox/imports/old-note.md"
```
Only on explicit operator request. Deletion is destructive.
@@ -195,7 +197,7 @@ Only on explicit operator request. Deletion is destructive.
- Path separators (`/`) in the vault path are **literal** — do not encode them.
- Spaces in filenames or heading targets in a URL: use `%20`.
- Nested heading levels in a URL path: use `%3A%3A` for `::`.
- Heading text in the `Target:` header: the **full heading path** joined by `::` (e.g. `Operator Preferences::Fact / Pattern`), no `#`; spaces are fine; **percent-encode non-ASCII and regex-special characters** — em dash `—``%E2%80%94`, en dash ```%E2%80%93` (see the special-characters note under *Patching* above). Best practice: keep heading text ASCII so targets never need encoding.
- Heading text in the `Target:` header: the **full heading path** joined by `::` (e.g. `Operator Preferences::Fact / Pattern`), no `#`; spaces are fine; percent-encode non-ASCII.
---
@@ -212,10 +214,17 @@ Only on explicit operator request. Deletion is destructive.
| Task-scoped context / focus | `_agent/context/current-context.md` | PATCH / PUT |
| Working-session log | `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md` | PUT |
| Long-running project state | `projects/<lifecycle>/<slug>.md` (lifecycle: `incubating``active``on-hold`/`archived`; folder and `status:` MUST agree) | PUT + PATCH |
| Non-obvious decision (ADR) | `decisions/by-date/YYYY-MM-DD-<slug>.md` (mirror `by-project/`) | PUT |
| Ongoing area of responsibility (standing domain, no end state) | `areas/<domain>/<slug>.md` (`<domain>`: `business`/`personal`/`learning`/`systems`) | PUT |
| Non-obvious decision (ADR) | `decisions/by-date/YYYY-MM-DD-<slug>.md` (mirror only into an existing project note's `## Key Decisions`; otherwise skip) | PUT |
| Person context | `resources/people/<name>.md` | PUT / PATCH |
| Company / organization context | `resources/companies/<slug>.md` | PUT / PATCH |
| Concept / reference note | `resources/concepts/` or `resources/references/` | PUT |
| Meeting notes / call recap | `resources/meetings/YYYY-MM-DD-<slug>.md` | PUT |
| Skill / plugin capability entry (catalog, not build work) | `_agent/skills/active/<slug>.md` (→ `archived/` when retired) | PUT |
| Daily activity / Agent Log | `journal/daily/YYYY-MM-DD.md` | POST / PATCH |
| Periodic review | `reviews/{weekly,monthly,quarterly,annual}/` | PUT |
| Journal rollup | `journal/{weekly/YYYY-Www,monthly/YYYY-MM,quarterly/YYYY-Qn,annual/YYYY}.md` (weekly = opt-in on first session of a new ISO week; monthly = offered with Vault Health; quarterly/annual = manual) | PUT |
| Vault-health audit (agent self-maintenance) | `_agent/health/YYYY-MM-vault-health.md` (monthly; NOT a journal entry) | PUT |
| Session-end orientation pointer | `_agent/heartbeat/last-session.md` (one line, overwritten each session end) | PUT |
| Bootstrap marker (plugin-owned) | `_agent/goldbrain-vault.md` (`schema_version`, bootstrap date) — the "is this vault set up?" probe | GET / PUT |
**Slug rules:** kebab-case, ASCII, ~40 chars max. Every file carries canonical frontmatter (see `vault-layout.md`).
@@ -1,39 +1,140 @@
# Bootstrap Procedure
# Bootstrap & Repair
The goldbrain vault ships its **own** `BOOTSTRAP.md` at the vault root — that file is the canonical preflight/repair manifest. This plugin defers to it rather than duplicating the logic.
The **plugin is the single source of truth** for goldbrain's structure. Everything needed to stand up a vault ships in this skill under `scaffold/` there is no dependency on any in-vault control doc and no external/local re-seed path. This makes the vault portable: point the REST API at any empty Obsidian vault, run this procedure, and it becomes a working goldbrain vault.
> **Structure vs. procedure.** This file (and the vault's `BOOTSTRAP.md`/`STRUCTURE.md`) own *structure* — what folders and seed files must exist. Day-to-day *procedure* — parallel loading, search-before-write, append idempotency, project lifecycle transitions, scope switching, vault health, and the em-dash-safe PATCH rules — lives in `SKILL.md`. When repairing, ensure the four project-lifecycle folders exist: `projects/{incubating,active,on-hold,archived}/`.
The vault holds **data only**. It carries no `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md`. The "is this vault set up?" signal is a small marker file, `_agent/goldbrain-vault.md`.
## Normal case — vault already bootstrapped
## Quick path — run the scripts
At session start, read the in-vault manifest:
Bootstrap, repair, and migration are deterministic scripts; prefer them over running the curl steps by hand. They resolve the scaffold relative to their own location, so they work regardless of the caller's CWD:
```bash
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/BOOTSTRAP.md"
SCRIPTS="${CLAUDE_PLUGIN_ROOT}/skills/goldbrain-memory/scripts"
"$SCRIPTS/bootstrap.sh" --dry-run # preview what would be seeded
"$SCRIPTS/bootstrap.sh" # idempotent, additive — fills only what is missing (also the repair path)
"$SCRIPTS/migrate.sh" # plan a schema migration (dry-run)
"$SCRIPTS/migrate.sh" --apply # perform the migration (moves/deletes, after review)
```
If it returns content (200), the vault is set up. Skim its preflight checklist, then read `CLAUDE.md` for the operating contract and proceed with the loading procedure in `SKILL.md`. The in-vault `BOOTSTRAP.md` describes how to repair any missing folders/files; follow it if something is absent. **Never overwrite an existing file** during repair — generate only what is missing.
`bootstrap.sh` writes through `goldbrain.sh`, so every step is status-checked and the marker is written last. The manual steps below document what the script does (and serve as a fallback if the script can't run).
## Fresh-vault case — BOOTSTRAP.md returns 404
```
AUTH="Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8"
BASE="https://goldbrainapi.mpm.to"
```
This means the REST API is pointed at an empty vault. Confirm with the operator once:
---
> "The goldbrain vault looks empty — there's no `BOOTSTRAP.md`. The standard scaffold (control docs, folder tree, templates, seed notes) needs to be loaded before I can use it as memory. Want me to create the core seed files now?"
## Probe — is the vault bootstrapped?
If yes, create the minimum viable seed with `PUT` (the API creates intermediate directories automatically), then let the vault's own structure grow from there:
At session start, GET the marker:
1. `CLAUDE.md` — operating contract and session protocol
2. `BOOTSTRAP.md` — preflight/repair manifest
3. `STRUCTURE.md` — layout, taxonomy, frontmatter standard
4. `index.md` — navigation hub
5. `_agent/memory/semantic/operator-preferences.md` — operator profile (empty, no fabricated facts)
6. `_agent/context/current-context.md` — empty context bundle
7. `inbox/captures/inbox.md` — capture file
```bash
curl -s -o /dev/null -w "%{http_code}" -H "$AUTH" "$BASE/vault/_agent/goldbrain-vault.md"
```
Prefer copying the full prepared scaffold into the Obsidian vault folder over reconstructing it by hand — it is the source of truth for goldbrain's structure.
- **200** → bootstrapped. Read the marker's `schema_version`; if it is **less than** the plugin's current schema (2), run a migration pass (see *Migrations* below), otherwise proceed straight to the loading procedure in `SKILL.md`.
- **404** → empty/unconfigured vault. Run **Fresh bootstrap** below. (If you expected an existing vault, confirm with the operator once that the REST API is pointed at the right vault before seeding.)
## After bootstrap
---
Tell the operator briefly what was created, append a line to the daily note's **Agent Log**, and write a session log in `_agent/sessions/`. Do not over-explain — they can browse the vault.
## Fresh bootstrap (empty vault)
Idempotent and additive. **Never overwrite an existing file** — GET-probe each path and skip any that already returns `200`. The marker is written **last**, so the vault is only flagged "set up" after every piece is in place.
Throughout, `{{DATE}}` means today's date (`YYYY-MM-DD`), resolved from the conversation's `currentDate`. Substitute it before PUTting any scaffold file or anchor seed.
### 1. Folder tree
The REST API auto-creates parent directories on PUT, so creating the tree = seeding a file into each leaf. Obsidian and git both ignore empty dirs, so drop a one-line `README.md` into any leaf that wouldn't otherwise receive a file. Required tree (leaves marked `→ README`):
```
inbox/captures inbox/imports inbox/processing-log
journal/daily journal/weekly journal/monthly journal/quarterly journal/annual journal/templates
projects/active projects/incubating projects/on-hold projects/archived
areas/business areas/personal areas/learning areas/systems
resources/concepts resources/references resources/people resources/companies resources/meetings
decisions/by-date
_agent/context _agent/memory/working _agent/memory/episodic _agent/memory/semantic
_agent/sessions _agent/health _agent/templates _agent/heartbeat
_agent/skills/active _agent/skills/archived
```
> `decisions/by-project/` is intentionally **not** created — it is retired. A project-relevant decision is mirrored as a `[[wikilink]]` under that project's `## Key Decisions` heading instead.
>
> `reviews/` is **not** created — it is retired. Journal rollups (weekly/monthly/quarterly/annual) live under `journal/`; the monthly vault-health audit lives under `_agent/health/`.
A leaf README is just a one-liner, e.g.:
```bash
printf '# %s\n\nMemory vault folder. See the goldbrain-memory plugin for conventions.\n' "captures" \
| curl -s -X PUT -H "$AUTH" -H "Content-Type: text/markdown" --data-binary @- \
"$BASE/vault/inbox/captures/README.md"
```
### 2. Templates
PUT every file under this skill's `scaffold/templates/` to its mirrored vault path. The tree mirrors 1:1:
| Scaffold file | Vault path |
|---|---|
| `scaffold/templates/_agent/templates/session-log-template.md` | `_agent/templates/session-log-template.md` |
| `scaffold/templates/_agent/templates/context-bundle-template.md` | `_agent/templates/context-bundle-template.md` |
| `scaffold/templates/_agent/templates/working-memory-template.md` | `_agent/templates/working-memory-template.md` |
| `scaffold/templates/_agent/templates/semantic-memory-template.md` | `_agent/templates/semantic-memory-template.md` |
| `scaffold/templates/journal/templates/daily-note-template.md` | `journal/templates/daily-note-template.md` |
| `scaffold/templates/journal/templates/weekly-review-template.md` | `journal/templates/weekly-review-template.md` |
| `scaffold/templates/projects/project-template.md` | `projects/project-template.md` |
| `scaffold/templates/decisions/decision-template.md` | `decisions/decision-template.md` |
Templates keep their Obsidian Templater tokens (`{{date:YYYY-MM-DD}}` etc.) verbatim — those are resolved by Templater / by the skill's daily-note routine, not at seed time.
Resolve scaffold paths against the skill directory — **never a bare relative `@scaffold/...`**, which assumes the caller's CWD is the skill dir and silently sends an empty body otherwise:
```bash
SCAFFOLD="${CLAUDE_PLUGIN_ROOT}/skills/goldbrain-memory/scaffold"
curl -s -X PUT -H "$AUTH" -H "Content-Type: text/markdown" \
--data-binary @"$SCAFFOLD/templates/journal/templates/daily-note-template.md" \
"$BASE/vault/journal/templates/daily-note-template.md"
```
### 3. Anchor seeds (only if absent — no fabricated facts)
Substitute `{{DATE}}` → today, then PUT each:
| Scaffold file | Vault path |
|---|---|
| `scaffold/anchors/operator-preferences.seed.md` | `_agent/memory/semantic/operator-preferences.md` |
| `scaffold/anchors/current-context.seed.md` | `_agent/context/current-context.md` |
| `scaffold/anchors/inbox.seed.md` | `inbox/captures/inbox.md` |
The operator-preferences seed is deliberately empty — **do not invent preferences.** Real facts accrue through use.
### 4. Vault README (human signpost)
Substitute `{{DATE}}` if present, then PUT `scaffold/README.vault.md``/vault/README.md`. This is the only human-facing control doc in the vault and is **not** read by the agent for routing.
### 5. Marker (write last)
Substitute `{{DATE}}`, then PUT `scaffold/goldbrain-vault.md``/vault/_agent/goldbrain-vault.md`. Once this returns `200`, the vault is bootstrapped.
### 6. First-run trace
Create today's daily note from `journal/templates/daily-note-template.md` (resolve the `{{date:…}}` tokens to today), append a one-line `## Agent Log` entry noting the bootstrap, and write a session log in `_agent/sessions/YYYY-MM-DD-HHMM-bootstrap.md`. Tell the operator briefly what was created.
---
## Repair (existing vault, something missing)
Run the same steps 15, but GET-probe each path first and **only create what is missing**. Never overwrite. If a file exists but looks malformed, flag it in the session log rather than replacing it. Repair is safe to run any time and is the right response if the loading procedure hits an unexpected `404` on a structural path.
---
## Migrations (`schema_version` mismatch)
`scripts/migrate.sh` automates this: it reads the marker's `schema_version`, applies each intervening migration (idempotent, additive; destructive steps gated behind `--apply` and printed first), and stamps the marker at the end. Run it dry-run, review the plan, then `--apply`. The steps below are what it encodes — and the manual fallback.
When the marker's `schema_version` is older than the plugin's, apply the migration steps for each intervening version, then PATCH the marker's `schema_version` frontmatter to the new value.
- **0 → 1** (control-docs-in-plugin): the vault previously carried root control docs (`CLAUDE.md`, `BOOTSTRAP.md`, `STRUCTURE.md`, `index.md`). Back them up outside the vault, DELETE them, PUT the thin `scaffold/README.vault.md` over the old verbose `README.md`, write the `_agent/goldbrain-vault.md` marker, and scrub now-dangling `[[CLAUDE]]`/`[[BOOTSTRAP]]`/`[[STRUCTURE]]`/`[[index]]` links from the `## Related` sections of `operator-preferences.md` and `current-context.md` (leave historical session logs alone). Confirm with the operator before deleting.
- **1 → 2** (reviews-folded-into-journal): the `reviews/` tree is retired. (a) For each note under `reviews/weekly/` and `reviews/monthly/`, MOVE it into `journal/weekly/` (rename `YYYY-Www-review.md``YYYY-Www.md`) and `journal/monthly/` respectively, preserving the earliest `created:`. (b) Move any `reviews/monthly/YYYY-MM-vault-health.md` to `_agent/health/`. (c) Move `reviews/quarterly|annual/` artifacts to `journal/quarterly|annual/`. (d) Update inbound `[[reviews/...]]` wikilinks in `## Related` sections to the new paths. (e) DELETE the now-empty `reviews/` tree. Confirm with the operator before deleting; leave historical session logs alone. *(goldbrain's live vault is migrated by `scripts/migrate.sh --apply`, which performs steps (a)(e) deterministically; run it dry-run first and review the plan.)*
@@ -0,0 +1,45 @@
# Goldbrain — Operating Contract
The durable, client-independent contract for any agent operating against the goldbrain vault. These principles and safety rules formerly lived in the vault's `CLAUDE.md`; they now live in the plugin so they survive regardless of what is (or isn't) in the vault. Day-to-day *procedure* — loading order, search-first, triage, scope switching, PATCH/append rules — is owned by `SKILL.md`. This file holds the things that don't change between sessions or clients.
## What this agent is
You are an agent operating against an Obsidian vault that functions as a shared, long-term memory substrate for human work, Claude Code / CoWork sessions, and future REST/MCP clients. Your role is to read context, synthesize across notes, produce structured outputs, update memory carefully, and leave durable traces in the vault rather than keeping important state only in the conversation. The vault is the **system of record**, not a scratchpad.
## Core principles
- Treat the vault as the system of record for long-term memory.
- Prefer Markdown, YAML frontmatter, wiki-links, and stable folder conventions over proprietary structures.
- Write notes so both humans and agents can understand them without hidden context.
- Preserve history instead of silently overwriting important decisions, summaries, or inferred preferences.
- Keep agent-managed content (`agent_written: true` + `source_notes`) clearly separated from human-authored content.
- Default to **additive updates, explicit status changes, and traceable summaries.**
- Optimize for portability: the same vault should work across Claude Code, CoWork, MCP-compatible tools, and REST API clients.
## Memory model (where things live)
- **Working** → `_agent/memory/working/` — transient, time-boxed.
- **Episodic** → `_agent/memory/episodic/` — what happened, when.
- **Semantic** → `_agent/memory/semantic/` — durable facts, patterns, preferences (`operator-preferences.md`).
- **Context bundles** → `_agent/context/` — task-focused reading lists and active state.
## Safety rules
- Do not fabricate facts, relationships, or prior decisions.
- Do not mass-restructure the vault unless explicitly asked.
- Do not delete notes unless deletion is explicitly requested and clearly safe.
- Do not store secrets or API keys inside the vault, and never write the API key into a vault note.
- Default to additive updates and explicit status changes over destructive edits.
## REST/API readiness
Assume clients may operate without filesystem access, through the Obsidian Local REST API. Keep paths predictable, frontmatter parseable, titles stable, and all state stored in notes rather than hidden conversation memory. Structure must stay portable: a fresh, empty vault is brought fully online by the plugin's bootstrap (`references/bootstrap.md`), so nothing essential should depend on files existing in the vault ahead of time.
## Concurrency (shared vault)
The vault is a **shared** substrate — Claude Code, CoWork, and other REST/MCP clients may operate on it concurrently. The REST API offers no transactions, so writers coordinate cooperatively:
- Single-line, overwrite-style files (`_agent/heartbeat/last-session.md`, `current-context.md::Scope`) and append targets (`inbox.md`, `## Agent Log`) assume **one writer at a time**. Two sessions writing at once can clobber or duplicate.
- Before a burst of writes in a session that may overlap another, take the advisory lock (`goldbrain.sh lock <id>``_agent/locks/vault.lock`) and release it at session end. The lock is cooperative with a TTL (stale locks are reclaimable); it is a courtesy, not a hard mutex.
- Idempotent append (read-before-POST, via `goldbrain.sh append`) is the second line of defense against duplicate lines from retries or overlapping sessions.
- Status-check every write. A write that returns `>= 400` did **not** land — surface it rather than assuming success.
@@ -0,0 +1,113 @@
# Goldbrain Routing Map
**This document is canonical and complete.** Every write destination in the vault appears here exactly once, with the condition that routes content to it, what lands there, and why it is distinct from its neighbours. The rule for the whole system: **if a path is not in this map, nothing is written to it.** A path that cannot justify its separateness from a neighbour is a merge candidate, not a valid destination.
Views of the same truth: `scripts/routing.json` is the **machine-readable canonical source** (one route per destination, as a regex pattern + trigger + reason); `vault-lint.sh` loads it and flags any vault path that matches no route (and any write to a retired path). This prose map is the human-readable authority and must stay in sync with `routing.json`. The `SKILL.md` *Where to Write* table is the quick-reference and `vault-layout.md` is the physical tree. When they disagree, `routing.json` + this map win and the others are fixed to match.
## How to read a row
- **Trigger** — the observable condition that sends content here. If two rows could both fire, the more specific trigger wins.
- **What lands** — the unit of content written.
- **Distinct because** — the one reason this path is not merged into its nearest neighbour. This is the load-bearing column; a row without it is a bug.
- **Method** — the dominant REST verb (see `api-reference.md` for mechanics).
---
## inbox/ — unsorted intake
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `inbox/captures/inbox.md` | "Save this, sort later" — destination genuinely unknown at capture time | One date-prefixed line | The only path whose contract is *deferred routing*; everything else here has a known home | POST |
| `inbox/imports/<slug>.md` | Raw external material dropped in wholesale (export, paste, dump) | The raw artifact, unedited | Holds un-triaged *bulk*, vs `captures` which holds single lines | PUT |
| `inbox/processing-log/YYYY-MM-DD.md` | An inbox item is routed to its real home | One line: `<original> → <destination path>` | Audit trail of moves — never holds memory itself, only the record of routing | POST |
Captures and imports are temporary by contract. Triage drains them into the homes below and logs the move; the original is left until Bryan okays deletion.
## journal/ — the one append-only time-series stream
Rollups are coarser-grained journal entries over the same timeline, so they live in the same tree. There is no separate `reviews/` tree.
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `journal/daily/YYYY-MM-DD.md` | First agent activity on a given day | `## Agent Log` line(s) + day notes | Finest grain; the only journal note PATCHed repeatedly within its period | PATCH (auto-create) |
| `journal/weekly/YYYY-Www.md` | First substantive session of a new ISO week — **opt-in**, offer first | Light digest: open `active/` threads, aging inbox, week's scope changes | Coarser than daily, finer than monthly; ISO-week grain | PUT |
| `journal/monthly/YYYY-MM.md` | First substantive session of a new month — offered alongside Vault Health | Month digest, same shape as weekly | Month grain; separate cadence and trigger from weekly | PUT |
| `journal/quarterly/YYYY-Qn.md` | **Manual / on request only** | Quarter-scale narrative review | Strategic grain; never auto-fires | PUT |
| `journal/annual/YYYY.md` | **Manual / on request only** | Year-scale narrative review | Coarsest grain; never auto-fires | PUT |
| `journal/templates/` | Bootstrap only (seeded from plugin masters) | Note templates | Holds templates, not journal content; never a runtime routing target | PUT (seed) |
## projects/ — work with an end state
Lifecycle folders; `status:` frontmatter MUST equal the folder name (the linter checks this).
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `projects/active/<slug>.md` | Work in motion now | Project note (Status PATCHed fresh) | Default state for anything being worked | PUT + PATCH |
| `projects/incubating/<slug>.md` | Idea captured, work not started | Project note | Pre-work; promote to `active/` when work begins | PUT |
| `projects/on-hold/<slug>.md` | Paused but still tracked | Project note | Resumable; distinct from `archived` (which is terminal) | PUT |
| `projects/archived/<slug>.md` | Done, abandoned, or rolled up | Project note | Terminal; kept for history, never deleted | PUT |
**Project vs area:** has an end state → `projects/`. Never "done" → `areas/`.
## areas/ — standing responsibilities, no finish line
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `areas/<domain>/<slug>.md` | Ongoing domain Bryan maintains indefinitely (`<domain>`: business/personal/learning/systems) | Area note | No end state — the one thing that disqualifies it from `projects/` | PUT |
## resources/ — reference material about the world
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `resources/people/<name>.md` | A fact about a specific person | Person note (kebab-case slug) | Keyed to a person, not a topic or event | PUT / PATCH |
| `resources/companies/<slug>.md` | A fact about an organization (client, vendor, partner, employer) | Company note (kebab-case slug) | Keyed to an organization, not an individual (`people/`) or an external source (`references/`) | PUT / PATCH |
| `resources/concepts/<slug>.md` | A reusable concept/idea Bryan wants on file | Concept note | An idea, vs a `reference` which is an external source | PUT |
| `resources/references/<slug>.md` | An external source/link worth keeping | Reference note | Points outward (a source), vs `concepts` (an idea) | PUT |
| `resources/meetings/YYYY-MM-DD-<slug>.md` | Notes/recap tied to a specific meeting or call | Meeting note; mirror decisions to `decisions/by-date/`, commitments to the project | Event-anchored to a meeting, vs a project's ongoing thread | PUT |
## decisions/ — non-obvious decisions (ADR)
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `decisions/by-date/YYYY-MM-DD-<slug>.md` | A non-obvious decision worth recording | ADR: Context → Decision → Consequences | The chronological system of record for decisions | PUT |
**Mirror, don't duplicate:** if the decision belongs to an existing `projects/active/` note, PATCH a `[[wikilink]]` to the ADR under that project's `## Key Decisions`. No matching project → skip the mirror; the by-date ADR stands alone.
## _agent/ — the agent's own working substrate
| Path | Trigger | What lands | Distinct because | Method |
|------|---------|------------|------------------|--------|
| `_agent/goldbrain-vault.md` | Bootstrap / schema migration only | Marker: `schema_version`, bootstrap date | Plugin-owned probe; never hand-edited | GET / PUT |
| `_agent/context/current-context.md` | Active scope changes; task focus shifts | `## Scope`, `## Scope History`, priorities | Single *live* scope pointer, vs episodic which is a *past* record | PATCH / PUT |
| `_agent/memory/semantic/operator-preferences.md` | A preference/pattern about Bryan | Append under `## Observations`; promote to `## Fact / Pattern` when stable | The one curated profile; distinct from ad-hoc semantic notes | PATCH |
| `_agent/memory/semantic/<slug>.md` | A durable fact/pattern that isn't a Bryan-preference | Semantic note | Timeless fact, vs episodic (time-stamped event) and working (transient) | PUT |
| `_agent/memory/episodic/<slug>.md` | A record of *what happened, when* | Episodic note | Anchored to an event in time; not a standing fact | PUT |
| `_agent/memory/working/<slug>.md` | Short-lived state needed only for the current effort | Working note | Explicitly transient/time-boxed; safe to go stale | PUT |
| `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md` | A substantive session ends (decisions/artifacts/commitments) | Session log (see template) | Per-session record; the unit loading Step 4 scans | PUT |
| `_agent/health/YYYY-MM-vault-health.md` | First substantive session of a month (Vault Health pass) | Health-audit findings | Agent self-maintenance about vault integrity — NOT Bryan's work narrative, so not in `journal/` | PUT |
| `_agent/heartbeat/last-session.md` | End of every session, after the session log is written | One line: `<session-log-path> @ <ISO-timestamp>` | O(1) orientation pointer read first at load (Step 4); overwritten, never grows | PUT |
| `_agent/templates/` | Bootstrap only (seeded from plugin masters) | Canonical note templates | Holds templates, not memory; never a runtime routing target | PUT (seed) |
| `_agent/skills/active/<slug>.md` | Bryan authors/installs a skill and wants it catalogued | Skill capability entry | Catalogs a *capability*, vs `projects/` which tracks the *build effort* | PUT |
| `_agent/skills/archived/<slug>.md` | A catalogued skill is retired | Skill entry (moved from `active/`) | Terminal state of the skill catalog | PUT |
---
## Retired paths — explicitly never written
Listed so they are recognised as dead and never recreated. Any one of these appearing in a live vault is a migration miss (see `bootstrap.md` Migrations).
| Path | Status | Where it went instead |
|------|--------|-----------------------|
| `reviews/` (weekly/monthly/quarterly/annual) | Retired in schema 2 | Journal rollups → `journal/{weekly,monthly,quarterly,annual}/`; vault-health → `_agent/health/` |
| `decisions/by-project/` | Retired in schema 1 | ADR mirrored as a `[[wikilink]]` under the project's `## Key Decisions` |
| `archive/` (top-level) | Never existed | Project archival → `projects/archived/`; skill archival → `_agent/skills/archived/` |
| `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md` (in-vault) | Retired in schema 1 | All control logic lives in the plugin (`references/`), not the vault |
## Routing decision tree (the calls that get mis-made)
1. **Destination unknown right now?**`inbox/captures/`. Known? → route directly; never park a known fact in the inbox.
2. **Is it about Bryan's work over time?**`journal/` (pick the grain by cadence). **About the vault's mechanical health?**`_agent/health/`. These two look similar monthly but answer different questions.
3. **Does the effort have an end state?**`projects/` (folder = `status:`). **No finish line?**`areas/`.
4. **A fact about the world:** timeless → `semantic/`; a thing that happened → `episodic/`; needed only for now → `working/`. A fact about a *person*`resources/people/`; a fact about an *organization*`resources/companies/`.
5. **A decision:** always `decisions/by-date/`; mirror into a project only if one already exists.
6. **A capability (skill/plugin):** `_agent/skills/` catalogs the capability; `projects/` tracks building it. Both can exist for the same skill.
@@ -2,10 +2,10 @@
Session logs go in: `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md`
**Filename format is canonical and not optional.** The four-digit local-time HHMM component is what makes session filenames lex-sort in true chronological order — the loading procedure depends on it. Before PUT-ing a new session log, validate the filename matches `^\d{4}-\d{2}-\d{2}-\d{4}-[a-z0-9-]+\.md$`. Legacy session logs without HHMM may exist; do not rename them, but every new write must use the full form.
**Filename format is canonical and not optional.** The four-digit local-time HHMM component is what makes session filenames lex-sort in true chronological order — the loading procedure depends on it. Before PUT-ing a new session log, validate the filename matches `^\d{4}-\d{2}-\d{2}-\d{4}-[a-z0-9-]+\.md$`. Legacy session logs without HHMM exist in the vault; do not edit their names, but every new write must use the full form.
The slug describes what the session was about in 25 words, kebab-case.
Examples: `2026-06-07-1430-goldbrain-plugin-build.md`, `2026-05-14-0900-q1-review-prep.md`.
Examples: `2026-06-05-1430-echo-plugin-build.md`, `2026-05-14-0900-q1-review-prep.md`.
Keep logs focused. Capture the goal, what was read/done, decisions, outputs, open threads, and the next step. This matches the vault's `_agent/templates/session-log-template.md`.
@@ -17,12 +17,12 @@ Keep logs focused. Capture the goal, what was read/done, decisions, outputs, ope
---
type: session-log
status: complete
created: 2026-06-07T14:30
updated: 2026-06-07T14:30
created: 2026-06-05T14:30
updated: 2026-06-05T14:30
tags: [agent, session]
agent_written: true
source_notes: []
session_date: 2026-06-07
session_date: 2026-06-05
client: claude-code
---
@@ -65,12 +65,12 @@ One sentence: what to do first next time on this topic.
---
type: session-log
status: complete
created: 2026-06-07T14:30
updated: 2026-06-07T14:30
created: 2026-06-05T14:30
updated: 2026-06-05T14:30
tags: [agent, session, plugin]
agent_written: true
source_notes: ["resources/references/obsidian-local-rest-api.md"]
session_date: 2026-06-07
session_date: 2026-06-05
client: claude-code
---
@@ -87,7 +87,7 @@ Verified the REST API end-to-end, confirmed the scaffold copied into the live va
created missing empty folders, and built the plugin (SKILL + 4 reference files).
## Decisions Made
- Vault addressed at root (no `Projects/agents/` prefix) — goldbrain is a dedicated vault.
- Vault addressed at root — goldbrain is a dedicated vault.
- Key hardcoded in the plugin (not in the vault) — personal plugin, per the reference pattern.
## Outputs Created
@@ -1,22 +1,22 @@
# Vault Layout & Frontmatter Conventions
Mirrors the canonical conventions defined in the vault's own `STRUCTURE.md` and `BOOTSTRAP.md`. If those change, they are the source of truth.
**This document is canonical.** The goldbrain vault holds data only — there are no `CLAUDE.md` / `STRUCTURE.md` / `BOOTSTRAP.md` / `index.md` control docs in it. Layout, taxonomy, and frontmatter conventions live here in the plugin; the bootstrap procedure (`references/bootstrap.md`) builds the tree below into any empty vault.
## Folder Map (root-addressed)
```
/vault/
├── CLAUDE.md ← operating contract + session protocol
├── STRUCTURE.md ← layout, taxonomy, frontmatter standard
├── BOOTSTRAP.md ← preflight/repair manifest (read first)
├── spinup.md index.md README.md
├── README.md ← thin human signpost (NOT read for routing)
├── inbox/
│ ├── captures/ ← quick captures (inbox.md), date-prefixed lines
│ ├── imports/ ← raw imported material
│ └── processing-log/
├── journal/
├── journal/ ← one append-only time-series stream; rollups are coarser journal entries, NOT a separate reviews/ tree
│ ├── daily/ ← YYYY-MM-DD.md (has an "Agent Log" section)
│ ├── weekly/ monthly/
│ ├── weekly/ ← YYYY-Www.md (ISO week, opt-in rollup)
│ ├── monthly/ ← YYYY-MM.md (monthly rollup)
│ ├── quarterly/ ← YYYY-Qn.md (manual / on request)
│ ├── annual/ ← YYYY.md (manual / on request)
│ └── templates/
├── projects/ ← lifecycle: incubating → active → on-hold/archived
│ ├── active/ ← current work (status: active)
@@ -26,27 +26,31 @@ Mirrors the canonical conventions defined in the vault's own `STRUCTURE.md` and
│ └── project-template.md
├── areas/ ← business / personal / learning / systems
├── resources/
│ ├── concepts/ references/ meetings/ source-material/
│ ├── companies/ ← <slug>.md — organizations (clients, vendors, partners, employers)
│ ├── concepts/ references/ meetings/
│ └── people/ ← <name>.md
├── decisions/
│ ├── by-date/ ← YYYY-MM-DD-<slug>.md (ADR-style)
│ ├── by-project/ ← mirror by project
│ ├── by-date/ ← YYYY-MM-DD-<slug>.md (ADR-style) — the canonical home
│ └── decision-template.md
├── reviews/ ← weekly / monthly / quarterly / annual
├── archive/ ← notes / projects / imports
│ (decisions/by-project/ is retired and not created —
│ mirror an ADR into a project's `## Key Decisions` heading instead)
│ (reviews/ is retired — journal rollups live under journal/; vault-health audits under _agent/health/)
└── _agent/
├── goldbrain-vault.md ← bootstrap marker: schema_version + bootstrap date (plugin-owned; the "is this vault set up?" probe)
├── context/ ← current-context.md and task bundles
├── memory/
│ ├── working/ ← transient, time-boxed
│ ├── episodic/ ← what happened, when
│ └── semantic/ ← durable facts/patterns (operator-preferences.md)
├── sessions/ ← YYYY-MM-DD-HHMM-<slug>.md
├── health/ ← YYYY-MM-vault-health.md (monthly self-maintenance audit; NOT a journal entry)
├── templates/ ← canonical note templates
├── outputs/ ← briefs / drafts / summaries / synthesis
├── skills/ ← active / archived
└── heartbeat/
└── heartbeat/ ← single-line pointers (e.g. last-session.md → most-recent session log path)
```
**Heartbeat:** `_agent/heartbeat/last-session.md` is a one-line pointer (`<session-log-path> @ <ISO-timestamp>`) the **session-logging procedure writes (PUT, overwrite) at session end** and the **loading procedure reads first (Step 4)** as an O(1) shortcut to the latest session log. It is a hint, not a source of truth — fall back to the `sessions/` directory listing if it's missing or stale. Because it's PUT-overwritten, it never grows or duplicates.
**Slug rules:** kebab-case, ASCII only, truncate to ~40 chars.
---
@@ -72,6 +76,12 @@ agent-managed content from human-authored content. When appending with POST, do
not rewrite frontmatter — the append goes after existing content. To change
`updated:` or `status:`, use PATCH with `Target-Type: frontmatter`.
**Frontmatter field semantics:**
- `created:` is the **earliest known date** the entity was tracked in the vault — *not* "today". When merging notes (e.g. promoting an `on-hold/` project into `active/`), preserve the earliest `created:` from any merged source and only update `updated:`.
- `source_notes` is a **backward link** — the note(s) that triggered or supplied content for this one (e.g. the session log a project update came from). Forward links go in the `## Related` body section, never here.
- `status:` for a project MUST match its folder under `projects/` (`active`, `incubating`, `on-hold`, `archived`). Moving the file and updating `status:` are the same operation.
> **No `[[wikilinks]]` in frontmatter.** YAML parses `[[...]]` as nested lists, so wiki
> links there break and never render as clickable links in reading view. Put all
> cross-references in a **`## Related`** section in the note **body** (bulleted `[[links]]`).
@@ -81,7 +91,7 @@ not rewrite frontmatter — the append goes after existing content. To change
## Note Types
`daily-note`, `weekly-note`, `monthly-note`, `project`, `project-update`, `area`,
`concept`, `reference`, `person`, `meeting`, `decision`, `review`, `session-log`,
`concept`, `reference`, `person`, `company`, `meeting`, `decision`, `review`, `session-log`,
`working-memory`, `episodic-memory`, `semantic-memory`, `context-bundle`, `skill`,
`draft`, `inbox-item`.
@@ -95,58 +105,72 @@ The profile analog. Canonical headings:
- `## Operator` — who Bryan is (one paragraph)
- `## Fact / Pattern`**promoted, deduped rules.** No date prefix. Timeless.
- `## Observations`**timestamped raw observations.** Date-prefixed lines (`- 2026-06-07: ...`). Default landing zone for new evidence.
- `## Observations`**timestamped raw observations.** Date-prefixed lines (`- 2026-06-06: ...`). Default landing zone for new evidence.
- `## Evidence` — citations/links supporting the rules
- `## Recommendation or Implication` — how the rules should shape behavior
- `## Review Notes` — confidence / last review date
Append observed facts under `## Observations` by default. Promote to `## Fact / Pattern` (dropping the date) once a pattern stabilizes. "The operator" is Bryan; do not attribute Jason's design preferences to Bryan without evidence — Jason's preferences live in the ECHO vault.
Append observed facts under `## Observations` by default. Promote to `## Fact / Pattern` (dropping the date) once a pattern stabilizes. "The operator" is Bryan Gilliom (CEO, Message Point Media); Jason Stedwell is the vault's architect, not its day-to-day operator.
### projects/active/\<slug\>.md
Mirrors `scaffold/templates/projects/project-template.md` — keep this block in sync with that template.
```markdown
---
type: project
status: active
created: 2026-06-07
updated: 2026-06-07
tags: []
created: {{date:YYYY-MM-DD}}
updated: {{date:YYYY-MM-DD}}
tags: [project]
agent_written: false
source_notes: []
owner:
review_cycle: weekly
---
# Project Name
## Current status
One paragraph, kept fresh via PATCH replace.
## Purpose
## Decisions
- [[YYYY-MM-DD-decision-slug]] — one-line summary
## Status
One paragraph, kept fresh via PATCH replace (target `Project Name::Status`).
## Open threads
## Goals
## Current Context
## Open Loops
- [ ] unresolved thing
## Log
- 2026-06-07: observation or update
## Key Decisions
- [[YYYY-MM-DD-decision-slug]] — one-line summary (ADR mirror target)
## Related Notes
## Session History
- 2026-06-05: observation or update
## Related
- [[areas/business/business-ops]]
```
**Lifecycle / status agreement:** a project's folder under `projects/` (`active`, `incubating`, `on-hold`, `archived`) and its `status:` frontmatter MUST match — moving the file and updating `status:` are the same operation. A note in `projects/active/` with `status: on-hold` is broken state; fix it when you see it. Keep heading text ASCII (plain hyphens, no em dashes/parentheses) so headings stay PATCH-targetable.
### sessions/YYYY-MM-DD-HHMM-\<slug\>.md
See `session-log-template.md`. goldbrain uses an **HHMM time component** in the filename — this is **canonical, not optional**. The four-digit local-time component makes filenames lex-sort in true chronological order, which the loading procedure relies on. Older session logs without HHMM may exist; leave them alone, but every new one must use the full `YYYY-MM-DD-HHMM-<slug>.md` form.
See `session-log-template.md`. goldbrain uses an **HHMM time component** in the filename — this is **canonical, not optional**. The four-digit local-time component makes filenames lex-sort in true chronological order, which the loading procedure relies on. Older session logs without HHMM exist; leave them alone, but every new one must use the full `YYYY-MM-DD-HHMM-<slug>.md` form.
### decisions/by-date/YYYY-MM-DD-\<slug\>.md
ADR-style: Context → Decision → Consequences. Mirror a project-relevant ADR as a `[[wikilink]]` under that project's `## Decisions` heading, and optionally into `by-project/` per the vault's `STRUCTURE.md`. The by-date ADR is always the canonical record.
ADR-style: Context → Decision → Consequences. If the decision belongs to an existing project, PATCH-append the wikilink into that project's `## Key Decisions` heading. Don't use `decisions/by-project/` — it's legacy scaffolding that's intentionally left empty.
### people/\<name\>.md
`type: person`. Use lowercase kebab-case for the slug (e.g. `bryan-gilliom.md`).
### companies/\<slug\>.md
`type: company`. An organization Bryan works with — client, vendor, partner, or employer (e.g. `gillig.md`, `mpm.md`). Distinct from `people/` (individuals, who *belong to* companies) and `references/` (external sources). Lowercase kebab-case slug.
---
## Cross-References