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
@@ -1,13 +1,13 @@
---
name: goldbrain-memory
description: Use the goldbrain Obsidian vault as Bryan's persistent memory across Claude/CoWork sessions. Use whenever the operator asks to remember, save, note, log, or capture anything durable — facts, preferences, decisions, schedule changes, commitments — or asks what Claude knows about them, what was discussed or decided before, to check their notes, load their memory/profile/context, add to their inbox, or to track a new project. Trigger even without memory phrasing when the request implies recalling or persisting state across sessions ("pick up where we left off", "anything on X before my meeting?"). Also use proactively at the start of substantive work sessions to load context and at the end to log outcomes. Do NOT use for Jason's ECHO vault, Obsidian/REST-API development questions, "memory" meaning RAM, timed reminders, email or local-file lookups, or generic second-brain advice.
description: Use the goldbrain Obsidian vault as Bryan's persistent memory across Claude/CoWork sessions. Use whenever Bryan asks to remember, save, note, log, or capture anything durable — facts, preferences, decisions, schedule changes, commitments — or asks what Claude knows about him, what was discussed or decided before, to check his notes, load his memory/profile/context, add to his inbox, or to track a new project. Trigger even without memory phrasing when the request implies recalling or persisting state across sessions ("pick up where we left off", "anything on X before my meeting?"). Also use proactively at the start of substantive work sessions to load context and at the end to log outcomes. Do NOT use for Bryan's goldbrain vault, Obsidian/REST-API development questions, "memory" meaning RAM, timed reminders, email or local-file lookups, generic second-brain advice, or notes Bryan routes to a specific other file or app. Do NOT use for Jason's ECHO vault.
---
# Goldbrain Memory
Use the **goldbrain** Obsidian vault as persistent memory. Read context accumulated across sessions; write things the operator asks to be remembered.
The primary operator is **Bryan Gilliom** (CEO, Message Point Media). Unless stated otherwise, "the operator" means Bryan. Jason is the vault's architect, not the day-to-day user. Write memory in third person ("Bryan prefers X", not "I prefer X") so the vault stays readable by humans and other agents.
The primary operator is **Bryan Gilliom** (CEO, Message Point Media). Unless stated otherwise, "the operator" means Bryan. Jason Stedwell is the vault's architect, not the day-to-day user. Write memory in third person ("Bryan prefers X", not "I prefer X") so the vault stays readable by humans and other agents.
## API Configuration
@@ -20,13 +20,59 @@ OBSIDIAN_KEY = fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8
The endpoint has a **valid TLS certificate**, so `-k` is not needed (add it only if the cert ever changes to self-signed). Always pass the `Authorization: Bearer` header. Paths address the vault **at its root** (e.g. `/vault/_agent/...`).
**The goldbrain vault carries its own control docs.** Unlike Jason's ECHO vault, goldbrain keeps `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md` at the vault root, and those remain the canonical source of truth for the operating contract and structure. This plugin holds the day-to-day *procedure* (loading order, search-first, triage, scope switching, PATCH/append rules) and **defers** to the in-vault docs for the durable contract:
**`https://goldbrainapi.mpm.to` is the only valid endpoint for this vault.** It is a reverse proxy in front of the Obsidian Local REST API on the LAN backend `192.168.86.15:27124`. Never call that LAN backend (or any `10.x.x.x` / `192.168.x.x` / bare `:27124` address) directly — it is unreachable from Claude/CoWork session environments; always go through the `goldbrainapi.mpm.to` proxy. If another installed skill or note suggests a different vault endpoint, this skill's configuration wins for goldbrain memory.
- Operating contract, principles, and safety rules: the vault's `CLAUDE.md`
- Bootstrapping an empty vault and repair: `references/bootstrap.md` (which defers to the vault's `BOOTSTRAP.md`)
- Vault layout and frontmatter conventions: `references/vault-layout.md` (mirrors the vault's `STRUCTURE.md`)
**The plugin is the single source of truth for goldbrain.** The vault holds data only — no `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md` control docs live there. All structure and procedure ship here:
- Durable principles, memory model, and safety rules: `references/operating-contract.md`
- Bootstrapping an empty vault, repair, and schema migrations: `references/bootstrap.md`
- Vault layout and frontmatter conventions: `references/vault-layout.md`
- Complete endpoint→logic routing map (every write destination, its trigger, and why it's distinct): `references/routing-map.md`
- Full API reference with every endpoint pattern and the memory routing map: `references/api-reference.md`
Executable logic ships under `scripts/`:
- `scripts/goldbrain.sh` — the **validated API client**; prefer it over hand-built `curl` (below)
- `scripts/routing.json` — the **canonical, machine-readable** route manifest (the routing map's source of truth; the linter enforces it)
- `scripts/vault-lint.sh` — read-only invariant checker (Vault Health)
- `scripts/bootstrap.sh` / `scripts/migrate.sh` — deterministic vault setup/repair and schema migration
## Bundled Tooling (prefer over raw curl)
All paths below are under `${CLAUDE_PLUGIN_ROOT}/skills/goldbrain-memory/`.
**`scripts/goldbrain.sh` — use this for every read/write.** It centralizes auth, **HTTP-status checking** (a failed write exits non-zero instead of looking like success), one bounded retry on 5xx/connection errors, idempotent append, correct `::` heading targets, and frontmatter patches. The raw `curl` recipes later in this file are the underlying mechanics / fallback — reach for them only if `goldbrain.sh` is unavailable, and if you do, **check the HTTP status yourself** (the PATCH-heading `400 invalid-target` failure silently loses writes otherwise).
```bash
GB="${CLAUDE_PLUGIN_ROOT}/skills/goldbrain-memory/scripts/goldbrain.sh"
"$GB" get <path> # 404 -> exit 44
"$GB" ls <dir> ; "$GB" map <path> # listing / document-map
"$GB" search <terms...>
"$GB" put <path> <file> # create/overwrite (read-back verified)
"$GB" append <path> "<line>" # idempotent: skips if the exact line exists
"$GB" patch <path> append heading "<H1::Sub>" <file>
"$GB" fm <path> updated '"2026-06-19"' ; "$GB" bump <path> # frontmatter
"$GB" lock <session-id> ; "$GB" unlock <session-id>
```
**Bootstrap / migrate** are scripts now, not hand-run curl loops: `scripts/bootstrap.sh [--dry-run]` (idempotent, probe-before-write, never overwrites) and `scripts/migrate.sh [--apply]` (reads the marker's `schema_version` and applies migrations; dry-run by default). See `references/bootstrap.md`.
### Concurrency — the vault is shared, so coordinate writes
goldbrain is read/written by multiple clients (Claude Code **and** CoWork sessions). The single-line files (`heartbeat/last-session.md`, `current-context.md::Scope`, `inbox.md`) assume a single writer at a time. Before a burst of writes in a session that may overlap another, take the **advisory lock**, and release it at session end:
```bash
"$GB" lock "cc-$(date +%s)" # exit 75 if another session holds a fresh lock
# ... do the writes ...
"$GB" unlock "cc-$(date +%s)"
```
The lock is cooperative (a stale lock past `GB_LOCK_TTL`, default 15 min, is reclaimable) and lives at `_agent/locks/vault.lock`. It is a courtesy, not a hard mutex — if you can't take it, tell Bryan another session may be active rather than racing it.
### Slash commands
`/gb-load` (cold-start read), `/gb-save <text>` (route + persist), `/gb-triage` (drain the inbox), `/gb-health` (run the linter). These are explicit entry points to the procedures below.
## Operating Contract & Safety
The vault is the **system of record** for long-term memory, not a scratchpad. Default to **additive updates, explicit status changes, and traceable summaries**. Keep agent-managed content (`agent_written: true` + `source_notes`) separable from human-authored content. Non-negotiable safety rules:
@@ -36,27 +82,35 @@ The vault is the **system of record** for long-term memory, not a scratchpad. De
- Do not delete notes unless deletion is explicitly requested and clearly safe.
- Never store secrets or API keys inside a vault note.
Full contract lives in the vault's `CLAUDE.md`.
Full contract (principles, agent role, memory model): `references/operating-contract.md`.
## When to Load Memory
Load at the start of any substantive conversation — anything beyond a single quick factual question. The signal: the operator is starting work, planning, asking for help with something that has state, or referencing prior discussions.
Load at the start of any substantive conversation — anything beyond a single quick factual question. The signal: Bryan is starting work, planning, asking for help with something that has state, or referencing prior discussions.
### Loading procedure
The cold-start reads are independent — **issue them in parallel** (one batch of 45 GETs), not sequentially. Parallel loading is ~3× faster wall-clock for the same call count.
The cold-start reads are independent — **issue them in parallel** (one batch of 56 GETs), not sequentially. Parallel loading is ~3× faster wall-clock for the same call count.
| # | GET | Notes |
|---|-----|-------|
| 1 | `/vault/BOOTSTRAP.md` | The in-vault preflight/repair manifest. 404 → vault not set up; follow `references/bootstrap.md`. 200 → proceed (skim its checklist only if a structural path 404s later). |
| 1 | `/vault/_agent/goldbrain-vault.md` | The bootstrap marker. 404 → vault not set up; follow `references/bootstrap.md`. 200 → check its `schema_version` and migrate if older. |
| 2 | `/vault/_agent/memory/semantic/operator-preferences.md` | Bryan's profile |
| 3 | `/vault/_agent/context/current-context.md` | Active scope + Scope History |
| 4 | `/vault/_agent/sessions/` (listing) | Pick the ~5 most recent by reverse lex sort (filenames `YYYY-MM-DD-HHMM-<slug>.md`, so lex == chrono); only read the ones whose slugs look relevant |
| 4 | `/vault/_agent/heartbeat/last-session.md` → then `/vault/_agent/sessions/` | **Read the heartbeat first** — a one-line pointer (`<session-log-path> @ <ISO-timestamp>`) written at the end of the previous session. It's an O(1) jump to the latest log, so you can skip or shortcut the full listing. Fall back to the `sessions/` listing only if the pointer is missing or looks stale; then pick the ~5 most recent by reverse lex sort (filenames `YYYY-MM-DD-HHMM-<slug>.md`, so lex == chrono) and read only the relevant ones. |
| 5 | `/vault/journal/daily/YYYY-MM-DD.md` | Today's note; 404 is fine — it's created on first agent activity |
| 6 | `/vault/inbox/captures/inbox.md` | Inbox depth probe — feeds the load-time reconcile below. 404 is fine (empty inbox). |
Do not read every session log — older sessions are reachable via `POST /search/simple/?query=...` when needed.
**If a specific project is in play**, follow up with a **search across all lifecycle subfolders** (`active/`, `incubating/`, `on-hold/`, `archived/`) — searching one folder at a time misses notes filed elsewhere. Search by **both the slug AND any human title** the operator used in this conversation:
**Reconcile at load (do this every cold start, after the batch returns).** The batch already fetched everything needed for a cheap self-check — run it before diving into the work so memory maintains itself instead of drifting:
1. **Inbox depth (Inbox Triage).** If `inbox/captures/inbox.md` (GET #6) holds dated capture lines older than ~7 days that were never routed, surface the count once and offer to triage — see **Inbox Triage** below. This is the load-time trigger that makes triage self-firing rather than something you only run when asked.
2. **Scope drift (state it, don't just check it).** Scope is the most churn-prone state — Bryan runs several sessions a day across different topics, so the recorded `## Scope` is frequently stale at load. **Silently working under a stale scope is the default failure mode.** To prevent it, at load read the active scope and its freshness in one call — `goldbrain.sh scope show` (prints `## Scope`, `scope_updated`, and how many sessions have been logged since) — and form a one-line judgment: *does this session's request match the recorded scope?* If it diverges, switch **before** doing the work via `goldbrain.sh scope set "<new scope>"` (see **Scope Switching**). If `scope show` reports several sessions logged since the last switch, treat the recorded scope as suspect and confirm with Bryan rather than trusting it.
Keep the reconcile to a single short line to Bryan (e.g. "3 inbox captures from last week are still un-routed — triage now?"); don't let it crowd out the actual request.
**If a specific project is in play**, follow up with a **search across all lifecycle subfolders** (`active/`, `incubating/`, `on-hold/`, `archived/`) — searching one folder at a time misses notes filed elsewhere. Search by **both the slug AND any human title** Bryan used in this conversation:
```bash
# slug
@@ -106,7 +160,7 @@ Projects move through four folders under `projects/`. The folder name and the `s
## When to Write Memory
Write when the operator:
Write when Bryan:
- States a fact, preference, or commitment worth keeping ("I prefer X", "we use uv not pip", "standup is Tuesday at 10")
- Makes a non-obvious decision worth recording
@@ -130,7 +184,7 @@ If a match is found:
- In the same folder you intended to write: **update in place** (PATCH or merged PUT). Never silently overwrite — fold the existing content in first.
- Elsewhere (e.g. a stale duplicate under `resources/`): tell Bryan and ask which should be canonical before writing.
**Search both the slug AND any human title** the operator used (e.g. slug `goldbrain-memory` and title `goldbrain plugin`). Slug-only searches miss notes filed under a different naming scheme. Two cheap `POST /search/simple/?query=...` calls beat one expensive cleanup pass later.
**Search both the slug AND any human title** Bryan used (e.g. slug `goldbrain-memory` and title `goldbrain plugin`). Slug-only searches miss notes filed under a different naming scheme. Two cheap `POST /search/simple/?query=...` calls beat one expensive cleanup pass later.
Only after the search comes back empty (or you've decided to merge) is it safe to create a new note. This rule prevents the most common duplication bug: a note exists in `on-hold/` but the agent only checked `active/` and created a parallel record.
@@ -152,7 +206,7 @@ Write content to a temp file first to handle multi-line markdown cleanly, then P
```bash
cat > /tmp/obs_entry.md << 'OBSEOF'
- 2026-06-07: <your entry here>
- 2026-06-05: <your entry here>
OBSEOF
curl -s -X POST \
@@ -166,7 +220,7 @@ POST appends to the end of a file (creating it if absent). Use it for inbox capt
### Patch a specific heading (targeted update)
**Heading targets use the FULL heading path, `::`-delimited from the top-level heading** — a bare subheading name fails with `400 invalid-target` (errorCode 40080) and the write is lost. For example, `## Fact / Pattern` under the `# Operator Preferences` H1 is targeted as `Operator Preferences::Fact / Pattern`.
**Heading targets use the FULL heading path, `::`-delimited from the top-level heading** — a bare subheading name fails with `400 invalid-target` and the write is lost. For example, `## Fact / Pattern` under the `# Operator Preferences` H1 is targeted as `Operator Preferences::Fact / Pattern`.
**Default: GET the document map first** (every first PATCH to a file in a session — cache the result mentally for subsequent PATCHes to the same file). This eliminates the most common failure mode of PATCH:
@@ -195,7 +249,7 @@ curl -s -X PATCH \
"https://goldbrainapi.mpm.to/vault/_agent/memory/semantic/operator-preferences.md"
```
Use `Operation: replace` to overwrite a section entirely (e.g. a project's `Project Name::Current status`).
Use `Operation: replace` to overwrite a section entirely (e.g. a project's `Project Name::Status`). Percent-encode non-ASCII characters in the `Target` header; spaces are fine.
#### Special characters in heading targets — em dashes, parentheses (KNOWN BUG)
@@ -229,7 +283,7 @@ When a PATCH or PUT changes meaningful content (status update, decision recorded
curl -s -X PATCH \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Operation: replace" -H "Target-Type: frontmatter" -H "Target: updated" \
-H "Content-Type: application/json" --data '"2026-06-07"' \
-H "Content-Type: application/json" --data '"2026-06-06"' \
"https://goldbrainapi.mpm.to/vault/projects/active/<slug>.md"
```
@@ -242,8 +296,8 @@ cat > /tmp/obs_file.md << 'OBSEOF'
---
type: project
status: active
created: 2026-06-07
updated: 2026-06-07
created: 2026-06-05
updated: 2026-06-05
tags: []
agent_written: true
source_notes: []
@@ -251,11 +305,11 @@ source_notes: []
# Project Name
## Current status
## Status
...
## Related
- [[journal/daily/2026-06-07]]
- [[journal/daily/2026-06-05]]
OBSEOF
curl -s -X PUT \
@@ -277,28 +331,60 @@ curl -s -X POST \
## Scope Switching (`current-context.md`)
`_agent/context/current-context.md` tracks a single active scope. The operator routinely shifts scope within a day (a project → MPM ops → something else).
`_agent/context/current-context.md` tracks a single active scope. Bryan routinely shifts scope within a day (echo plugin → MPM brand → WISP docs), so this is high-churn — switch deliberately, every time the work changes topic.
When scope changes:
**Preferred — one command:**
1. PATCH `prepend` a dated bullet to `## Scope History` capturing the **prior** scope (one line: `- 2026-06-07: <prior scope summary>`). If `## Scope History` doesn't exist yet, POST the heading first, same pattern as the daily-note Agent Log.
2. PATCH `replace` `## Scope` with the new scope.
3. PATCH the frontmatter `updated:` field.
```bash
"$GB" scope set "<new scope summary>"
```
`scope set` does the whole switch atomically and correctly: it archives the **prior** scope to `## Scope History` (dated, truncated), replaces `## Scope` with the new text, and stamps the `scope_updated:` frontmatter timestamp. That timestamp is the **freshness signal** — it's what `goldbrain.sh scope show` and the `vault-lint.sh` drift check read to tell whether the recorded scope still reflects current work. Always switch through `scope set` so `scope_updated` stays honest; a hand-edited `## Scope` that skips the stamp reintroduces silent drift.
**Manual fallback** (only if `goldbrain.sh` is unavailable): PATCH `prepend` the prior scope to `## Scope History`, PATCH `replace` `## Scope`, then PATCH the frontmatter `scope_updated:` (and `updated:`) to today. Note `scope_updated` must already exist in frontmatter — a `PATCH replace` on a missing field returns `400 invalid-target`; run `bootstrap.sh` repair to add it.
This keeps a rolling trail of recent scopes in one file instead of spawning separate stash notes. Trim Scope History to the last ~10 entries when it grows past that.
**Drift backstop:** `vault-lint.sh` flags when ≥ `SCOPE_STALE_SESSIONS` (default 3) session logs are dated after `scope_updated` — i.e. work happened without a scope switch. It's advisory (surfaced in Vault Health / `/gb-health`), the mechanical safety net under the load-time judgment above.
## Journal Rollups (the journal is one continuum)
The journal is a single append-only chronological stream. Rollups are just coarser-grained journal entries over the same timeline, so they **all live under `journal/`** — there is no separate `reviews/` tree. One place to read the whole time-series story, daily through annual.
| Cadence | Path | Trigger | Type |
|---------|------|---------|------|
| Daily | `journal/daily/YYYY-MM-DD.md` | first agent activity that day | `daily-note` |
| Weekly | `journal/weekly/YYYY-Www.md` (e.g. `2026-W24.md`) | first substantive session of a new ISO week — **opt-in**, offer first | `weekly-note` |
| Monthly | `journal/monthly/YYYY-MM.md` | first substantive session of a new calendar month — offer alongside the Vault Health pass | `monthly-note` |
| Quarterly | `journal/quarterly/YYYY-Qn.md` | **manual / on request only** | `review` |
| Annual | `journal/annual/YYYY.md` | **manual / on request only** | `review` |
All filenames lex-sort chronologically. Detect the weekly trigger with `date +%G-W%V` and check whether that week's note already exists; monthly with `date +%Y-%m`.
A weekly/monthly rollup is a **light digest** — open threads across `projects/active/`, inbox items aging past ~7 days, and the period's `## Scope History` changes from `current-context.md`. It is *not* a vault-health audit (that's an agent-maintenance artifact — see below).
## Vault Health (monthly)
On the first substantive session of a calendar month, run a quick health pass and write findings to `reviews/monthly/YYYY-MM-vault-health.md`. Don't auto-fix without asking.
On the first substantive session of a calendar month, run a quick health pass and write findings to `_agent/health/YYYY-MM-vault-health.md`. This is **agent self-maintenance, not a journal entry** — it lives under `_agent/` because it's about the vault's mechanical integrity, not Bryan's work narrative. Don't auto-fix without asking.
Checks:
Run the bundled linter first — it mechanically checks the invariants below so you don't eyeball them. **Pass `GB_TODAY` = the conversation's `currentDate`** so stale/aging math uses the same clock you write with (not the runner's machine date):
```bash
GB_TODAY=<currentDate> "${CLAUDE_PLUGIN_ROOT}/skills/goldbrain-memory/scripts/vault-lint.sh"
```
Exit codes: `0` clean · `1` violations · `2` unreachable · `3` not bootstrapped. Checks (the linter asserts each and prints violations):
1. **Stale active projects** — for each note in `projects/active/`, check `updated:` >30 days. Likely belongs in `on-hold/`.
2. **Unprocessed inbox** — GET `inbox/captures/inbox.md`. List items older than 14 days that never moved through the triage protocol.
3. **Duplicate slugs across lifecycle folders** — any slug appearing in more than one of `active/`, `incubating/`, `on-hold/`, `archived/` is broken state.
4. **Broken-heading risk** — sample 23 frequently-PATCHed files; confirm `## Agent Log`, `## Scope`, `## Fact / Pattern`, `## Observations` headings still exist, and that no heading has acquired an em dash or parentheses that would break PATCH targeting.
4. **Folder ↔ `status:` mismatch** — any `projects/<lifecycle>/` note whose `status:` frontmatter disagrees with its folder.
5. **Wikilinks in frontmatter** — any `[[...]]` inside a YAML frontmatter block (breaks Obsidian reading view), swept across all folders.
6. **Duplicate `## Agent Log` headings** — any daily note with more than one.
7. **Unknown / retired paths** — any vault file that matches no route in `scripts/routing.json` (or sits at a retired path).
8. **Frontmatter integrity** — missing required fields, `updated` < `created`, future `updated`, and `[[wikilinks]]` leaking into `source_notes`.
The pass is cheap (a few searches + a directory listing) and pays for itself by catching drift before it requires a reorg.
The pass is cheap and pays for itself by catching drift before it requires a reorg. Write the findings as a digest; act on them only with Bryan's go-ahead.
## Daily Note — Agent Log
@@ -358,12 +444,28 @@ curl -s -X PATCH -H "$AUTH" \
| Task-scoped context / focus | `_agent/context/current-context.md` | PATCH / PUT |
| Working session ended with substance | `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md` | PUT |
| Long-running project state | `projects/<lifecycle>/<slug>.md` (see Project Lifecycle) | PUT + PATCH |
| 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` (see mirror note below) | 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 the build work) | `_agent/skills/active/<slug>.md` (→ `_agent/skills/archived/` when retired) | PUT |
| Daily activity / Agent Log | `journal/daily/YYYY-MM-DD.md` — see **Daily Note — Agent Log** above | PATCH (with auto-create) |
| Weekly / monthly rollup | `journal/weekly/YYYY-Www.md` · `journal/monthly/YYYY-MM.md` — see **Journal Rollups** | PUT |
| Quarterly / annual review | `journal/quarterly/YYYY-Qn.md` · `journal/annual/YYYY.md` (manual / on request) | PUT |
| Vault-health audit (agent self-maintenance) | `_agent/health/YYYY-MM-vault-health.md` — see **Vault Health** | PUT |
| Session-end orientation pointer | `_agent/heartbeat/last-session.md` (one line: `<session-log-path> @ <ISO-timestamp>`) | PUT |
**Decision mirrors:** mirror a project-relevant ADR as a `[[wikilink]]` under that project's `## Decisions` heading (PATCH), and optionally into `decisions/by-project/` per the vault's `STRUCTURE.md`. The by-date ADR is always the canonical record.
> **The complete, audited routing map lives in `references/routing-map.md`** — every write destination with its trigger, what lands there, and why it's distinct from its neighbors. This table is the quick-reference; the map is the authority. If a path isn't in the map, it shouldn't be written to.
**Decision mirrors:** if the decision belongs to an existing note in `projects/active/`, add a `[[wikilink]]` to the ADR under that project's `## Key Decisions` heading (PATCH). If no matching project note exists, skip the mirror — the by-date ADR is sufficient; do not invent topical mirror files in `decisions/by-project/`.
**Routing triggers — areas / meetings / skills:**
- **Area** (`areas/`): a standing responsibility Bryan maintains with no finish line. Decision rule: has an end state → `projects/`; never "done" → `areas/`. Subfolder is the domain (`business`/`personal`/`learning`/`systems`); create it on first write. `type: area`.
- **Meeting** (`resources/meetings/`): notes, recaps, or action items tied to a specific meeting or call. Mirror decisions to `decisions/by-date/` and commitments to the relevant project. `type: meeting`.
- **Skill** (`_agent/skills/`): Bryan authors, installs, or retires a skill/plugin and wants it tracked as a capability — distinct from `projects/`, which tracks the build effort. Active entries in `active/`, retired ones in `archived/`. `type: skill`.
Never delete files unless Bryan explicitly asks. Memory is append-friendly; deletion is destructive.
@@ -371,7 +473,7 @@ Never delete files unless Bryan explicitly asks. Memory is append-friendly; dele
At the end of substantive conversations (ones that produced decisions, artifacts, or commitments), create a session log. Ask once if unsure: "Want me to log a session note for this?"
**Filename format is canonical: `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md`.** Always include the four-digit local-time HHMM component — it makes filenames lexically sort in true chronological order, which is what Step 3 of loading relies on. Older session logs without the HHMM part may exist; leave them alone, but every new one must use the full form.
**Filename format is canonical: `_agent/sessions/YYYY-MM-DD-HHMM-<slug>.md`.** Always include the four-digit local-time HHMM component — it makes filenames lexically sort in true chronological order, which is what Step 3 of loading relies on. Older session logs without the HHMM part exist; leave them alone, but every new one must use the full form.
See `references/session-log-template.md` for the body format.
@@ -384,11 +486,23 @@ curl -s -X PUT \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_session.md \
"https://goldbrainapi.mpm.to/vault/_agent/sessions/2026-06-07-1430-my-session.md"
"https://goldbrainapi.mpm.to/vault/_agent/sessions/2026-06-05-1430-my-session.md"
```
Then add a one-line entry to today's daily note via the **Daily Note — Agent Log** procedure above.
Finally, update the heartbeat pointer so the next session can orient in one GET (this is what closes the loop with loading-procedure Step 4 — a pointer nobody writes is a pointer nobody can read):
```bash
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
printf '%s @ %s\n' "_agent/sessions/${SESSION_FILENAME}" "$NOW" \
| curl -s -X PUT -H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Content-Type: text/markdown" --data-binary @- \
"https://goldbrainapi.mpm.to/vault/_agent/heartbeat/last-session.md"
```
`last-session.md` is a single-line pointer overwritten (PUT) each session end — never appended, so it can't grow or duplicate.
## Vault Unreachable
If the API returns a connection error, timeout, or `502`, tell Bryan once that the memory vault is unreachable (a `502` usually means Obsidian/the REST plugin is not running on the backend), then proceed without memory. Do not retry repeatedly.
@@ -396,16 +510,16 @@ If the API returns a connection error, timeout, or `502`, tell Bryan once that t
## Style Rules
- Write in third person about Bryan: "Bryan prefers X", not "I prefer X".
- Do not attribute Jason's design preferences to Bryan — capture Bryan's preferences only from observed interactions. Jason's preferences belong in the ECHO vault, Bryan's belong here.
- Do not attribute Jason's design preferences to Bryan — capture Bryan's preferences only from observed interactions. Jason is the architect of this vault, not its operator. Jason's preferences belong in his ECHO vault; Bryan's belong here. Do not cross-write between the two.
- **Keep heading text ASCII** so it stays PATCH-targetable — plain hyphens with spaces (` - `), never em dashes or parentheses in headings (see the special-characters note under PATCH).
- **Anchor relative dates on the conversation's `currentDate`** before writing. "Today" → `currentDate`. "Thursday" / "next week" → resolve to an absolute `YYYY-MM-DD`. Never guess from training-data knowledge of the current year.
- **Keep heading text ASCII** so it stays PATCH-targetable — plain hyphens, no em dashes or parentheses in headings (see the special-characters note under PATCH).
- Every memory file has canonical YAML frontmatter — see `references/vault-layout.md`.
- Set `agent_written: true` on agent-generated notes and list `source_notes` (plain relative paths, not links).
- **`created:` is the earliest known date the entity was tracked anywhere in the vault, not "today".** When merging notes (e.g. promoting `on-hold/` → `active/`), preserve the earliest `created:` and only bump `updated:`.
- **`source_notes` lists the note(s) that *triggered* or *supplied content for* this one** — e.g. the session log that produced a project update, or the daily note where a captured fact originated. It is a *backward* link to inputs. Forward links (this note → other notes it references) belong in the `## Related` section in the note body, never in frontmatter.
- **Never put `[[wikilinks]]` in frontmatter** — YAML parses them as nested lists and the links break in Obsidian's reading view. Put all cross-references in a `## Related` section in the note **body** as a bulleted list of `[[links]]`.
- Use Obsidian wiki links (`[[note name]]`) freely in the note **body** for cross-references.
- Keep entries short and focused. Fewer, sharper entries beat many noisy ones.
- Keep entries short and focused. Fewer, sharper entries beat many noisy ones — Bryan explicitly prefers concision.
- About to write something large or sensitive? Show Bryan the content first and confirm.
## operator-preferences.md — Rules vs Observations
@@ -413,7 +527,7 @@ If the API returns a connection error, timeout, or `502`, tell Bryan once that t
`_agent/memory/semantic/operator-preferences.md` separates two kinds of content:
- `## Fact / Pattern` — **promoted, deduped rules.** No date prefix. These are timeless: "Bryan prefers concise communication." Append here only when a rule is stable.
- `## Observations` — **timestamped raw observations.** Date-prefixed: `- 2026-06-07: Bryan chose X over Y because Z.` This is where new evidence goes by default.
- `## Observations` — **timestamped raw observations.** Date-prefixed: `- 2026-06-06: Bryan chose X over Y because Z.` This is where new evidence goes by default.
During monthly Vault Health or when an observation stabilizes, promote it from `## Observations` into `## Fact / Pattern` (drop the date) and remove the duplicate from Observations. Trim Observations to the last ~30 entries when it grows past that — the rest live in session logs.