This commit is contained in:
2026-06-07 22:41:19 -05:00
parent 392ae7bbe3
commit 8bf9871dbe
10 changed files with 1055 additions and 0 deletions
@@ -0,0 +1,221 @@
# Goldbrain — Obsidian Local REST API Reference
Server: `https://goldbrainapi.mpm.to` (reverse proxy → Obsidian Local REST API on `192.168.86.15:27124`)
Auth header: `Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8`
The endpoint has a **valid TLS certificate**`-k` is not required. Paths address the vault at its **root**.
---
## Reading Files
```bash
# Read any file by vault path
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/_agent/context/current-context.md"
```
Returns raw file content (text/markdown). On 404, the file does not exist.
```bash
# Read a specific heading's content only
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/_agent/memory/semantic/operator-preferences.md/heading/Operator"
```
Nested headings: separate levels with `::` (URL-encode spaces as `%20`):
```
/vault/path/to/note.md/heading/Work%3A%3AMeetings
```
---
## Listing Directories
```bash
# List contents of a directory (trailing slash required)
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/_agent/sessions/"
```
Returns JSON: `{ "files": [...], "folders": [...] }`.
---
## Appending Content (POST)
`POST` appends to the **end** of an existing file. Creates the file if it doesn't exist.
```bash
cat > /tmp/obs_entry.md << 'OBSEOF'
- 2026-06-02: your entry here
OBSEOF
curl -s -X POST \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_entry.md \
"https://goldbrainapi.mpm.to/vault/inbox/captures/inbox.md"
```
---
## Creating or Overwriting Files (PUT)
`PUT` creates a new file or fully overwrites an existing one. Intermediate directories are created automatically.
```bash
cat > /tmp/obs_file.md << 'OBSEOF'
---
type: session-log
status: complete
created: 2026-06-02
updated: 2026-06-02
tags: [agent, session]
agent_written: true
source_notes: []
---
# content here
## Related
- [[projects/active/some-project]]
OBSEOF
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"
```
---
## Patching a Specific Section (PATCH)
`PATCH` edits inside a file without rewriting it. Target and operation are set via headers.
### Append under a heading
**Heading targets must be the FULL heading path, `::`-delimited from the top-level heading.** A bare subheading name returns `400 invalid-target` (errorCode 40080). Example: `## Fact / Pattern` nested under `# Operator Preferences``Target: Operator Preferences::Fact / Pattern`. Percent-encode non-ASCII characters (e.g. `H%C3%A9llo`); spaces are fine.
> **Special characters in heading targets (em dashes, parentheses) — known failure.** The server matches the `Target` header against heading text only after URL-decoding it, and the matcher applies regex-special handling to characters like `(` `)` `[` `]`. A heading such as `# EarthDnD — Personal Project` targeted literally fails with `invalid-target` (40080), because the raw em dash (`—`, U+2014) rides unreliably in an HTTP header. Handle it in this priority order:
>
> 1. **Prevent — keep new headings ASCII.** When you author a heading you might later PATCH, use a plain hyphen with spaces (` - `), never an em dash/en dash, and avoid parentheses/brackets. `# EarthDnD - Personal Project` is always PATCH-safe. This is the durable fix.
> 2. **Percent-encode the offending run** when targeting an existing special-char heading: em dash `—` → `%E2%80%94`, en dash `` → `%E2%80%93`. Example fixing the bug-report case: `Target: EarthDnD %E2%80%94 Personal Project::AI Platform Roles`.
> 3. **Fallback (GET → edit → PUT)** when even encoding fails (e.g. parentheses): read the whole file, edit the section in memory, PUT it back. Atomic, not in-place — small race-condition risk on hot files, so prefer fixing the heading to ASCII.
| Character | Glyph | Percent-encoding |
|-----------|-------|------------------|
| Em dash | `—` (U+2014) | `%E2%80%94` |
| En dash | `` (U+2013) | `%E2%80%93` |
| Space | ` ` | `%20` (literal space also works) |
| `::` (nesting, in URL path only) | `::` | `%3A%3A` |
| é (example accented char) | `é` | `%C3%A9` |
```bash
cat > /tmp/obs_patch.md << 'OBSEOF'
Bryan prefers concise status updates — lead with the decision.
OBSEOF
curl -s -X PATCH \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Operation: append" \
-H "Target-Type: heading" \
-H "Target: Operator Preferences::Fact / Pattern" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_patch.md \
"https://goldbrainapi.mpm.to/vault/_agent/memory/semantic/operator-preferences.md"
```
### Discover heading / block / frontmatter targets
When unsure of the exact heading path, GET the note with the document-map Accept header:
```bash
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
-H "Accept: application/vnd.olrapi.document-map+json" \
"https://goldbrainapi.mpm.to/vault/_agent/memory/semantic/operator-preferences.md"
```
Returns `{ "headings": [...], "blocks": [...], "frontmatterFields": [...] }`. Copy the heading string verbatim into `Target`.
### Replace a heading's content entirely
Same call with `Operation: replace` — e.g. to refresh a project's `Project Name::Current status`.
### Prepend under a heading
Same call with `Operation: prepend`.
### Patch a frontmatter field
```bash
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-02"' \
"https://goldbrainapi.mpm.to/vault/projects/active/vault-foundation.md"
```
---
## Searching
```bash
curl -s -X POST \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/search/simple/?query=weekly+review"
```
Returns an array of `{ filename, score, matches: [{ context, match }] }`.
---
## Deleting Files
```bash
curl -s -X DELETE \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/archive/notes/old-note.md"
```
Only on explicit operator request. Deletion is destructive.
---
## URL-Encoding Notes
- 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.
---
## Memory Routing Map
| Situation | Vault path | Method |
|-----------|-----------|--------|
| Quick capture / unsorted | `inbox/captures/inbox.md` (date-prefixed line) | POST |
| Raw imported material | `inbox/imports/` | PUT |
| Operator preference / durable fact | `_agent/memory/semantic/operator-preferences.md` | PATCH |
| Other durable facts, patterns | `_agent/memory/semantic/<slug>.md` | PUT |
| Event record (what happened) | `_agent/memory/episodic/<slug>.md` | PUT |
| Short-lived, time-boxed state | `_agent/memory/working/<slug>.md` | PUT |
| 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 |
| Person context | `resources/people/<name>.md` | PUT / PATCH |
| Concept / reference note | `resources/concepts/` or `resources/references/` | PUT |
| Daily activity / Agent Log | `journal/daily/YYYY-MM-DD.md` | POST / PATCH |
| Periodic review | `reviews/{weekly,monthly,quarterly,annual}/` | PUT |
**Slug rules:** kebab-case, ASCII, ~40 chars max. Every file carries canonical frontmatter (see `vault-layout.md`).
@@ -0,0 +1,39 @@
# Bootstrap Procedure
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.
> **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}/`.
## Normal case — vault already bootstrapped
At session start, read the in-vault manifest:
```bash
curl -s \
-H "Authorization: Bearer fb72065a05fabb28ae87c45880cc3b7aba4fd3f58e70297934145cef974e8ed8" \
"https://goldbrainapi.mpm.to/vault/BOOTSTRAP.md"
```
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.
## Fresh-vault case — BOOTSTRAP.md returns 404
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?"
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:
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
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.
## 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.
@@ -0,0 +1,110 @@
# Session Log Template
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.
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`.
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`.
---
## Template
```markdown
---
type: session-log
status: complete
created: 2026-06-07T14:30
updated: 2026-06-07T14:30
tags: [agent, session]
agent_written: true
source_notes: []
session_date: 2026-06-07
client: claude-code
---
# Session Log
## Goal
One line — what this session set out to do.
## Notes Read
- [[note]] — why it was relevant
(omit if none)
## Actions Taken
Brief narrative or bullets of what was done.
## Decisions Made
- Decision — why
(omit section if none)
## Outputs Created
- `path/or/filename` — what it is
(omit section if none)
## Open Threads
- [ ] unresolved question or next step
(omit section if none)
## Suggested Next Step
One sentence: what to do first next time on this topic.
## Related
- [[wikilinks go here, in the body — never in frontmatter]]
```
---
## Example
```markdown
---
type: session-log
status: complete
created: 2026-06-07T14:30
updated: 2026-06-07T14:30
tags: [agent, session, plugin]
agent_written: true
source_notes: ["resources/references/obsidian-local-rest-api.md"]
session_date: 2026-06-07
client: claude-code
---
# Session Log
## Goal
Build and package the goldbrain-memory CoWork plugin against the live vault.
## Notes Read
- [[BOOTSTRAP]], [[STRUCTURE]], [[_agent/memory/semantic/operator-preferences]]
## Actions Taken
Verified the REST API end-to-end, confirmed the scaffold copied into the live vault,
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.
- Key hardcoded in the plugin (not in the vault) — personal plugin, per the reference pattern.
## Outputs Created
- `goldbrain-memory.plugin` — installable CoWork plugin
## Open Threads
- [ ] Validate Claude Code direct filesystem access to the vault host.
## Suggested Next Step
Install the plugin and run a live load/write through it to confirm the skill triggers.
## Related
- [[projects/active/vault-foundation]]
- [[resources/references/obsidian-local-rest-api]]
```
After writing the log, append a one-line entry to the daily note's **Agent Log** section.
> **Reminder:** wiki links go in the body (e.g. this `## Related` section), never in YAML
> frontmatter. `source_notes` in frontmatter holds plain relative path strings, not `[[links]]`.
@@ -0,0 +1,155 @@
# 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.
## 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
├── inbox/
│ ├── captures/ ← quick captures (inbox.md), date-prefixed lines
│ ├── imports/ ← raw imported material
│ └── processing-log/
├── journal/
│ ├── daily/ ← YYYY-MM-DD.md (has an "Agent Log" section)
│ ├── weekly/ monthly/
│ └── templates/
├── projects/ ← lifecycle: incubating → active → on-hold/archived
│ ├── active/ ← current work (status: active)
│ ├── incubating/ ← idea captured, not yet started (status: incubating)
│ ├── on-hold/ ← paused but kept (status: on-hold)
│ ├── archived/ ← done / abandoned (status: archived)
│ └── project-template.md
├── areas/ ← business / personal / learning / systems
├── resources/
│ ├── concepts/ references/ meetings/ source-material/
│ └── people/ ← <name>.md
├── decisions/
│ ├── by-date/ ← YYYY-MM-DD-<slug>.md (ADR-style)
│ ├── by-project/ ← mirror by project
│ └── decision-template.md
├── reviews/ ← weekly / monthly / quarterly / annual
├── archive/ ← notes / projects / imports
└── _agent/
├── 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
├── templates/ ← canonical note templates
├── outputs/ ← briefs / drafts / summaries / synthesis
├── skills/ ← active / archived
└── heartbeat/
```
**Slug rules:** kebab-case, ASCII only, truncate to ~40 chars.
---
## Canonical Frontmatter
Every note starts with this block. Fill what applies; leave the rest empty rather than guessing.
```yaml
---
type: # see Note Types below
status: # active | draft | done | archived | complete
created: # YYYY-MM-DD (or YYYY-MM-DDTHH:mm for sessions)
updated: # YYYY-MM-DD
tags: []
agent_written: false
source_notes: [] # plain relative paths as strings — NEVER [[wikilinks]]
---
```
`agent_written: true` + a populated `source_notes` is the key signal separating
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`.
> **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]]`).
> Frontmatter holds scalar/string metadata only; `source_notes` values are plain relative
> paths, not links.
## Note Types
`daily-note`, `weekly-note`, `monthly-note`, `project`, `project-update`, `area`,
`concept`, `reference`, `person`, `meeting`, `decision`, `review`, `session-log`,
`working-memory`, `episodic-memory`, `semantic-memory`, `context-bundle`, `skill`,
`draft`, `inbox-item`.
---
## File-Specific Conventions
### operator-preferences.md (`_agent/memory/semantic/`)
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.
- `## 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.
### projects/active/\<slug\>.md
```markdown
---
type: project
status: active
created: 2026-06-07
updated: 2026-06-07
tags: []
agent_written: false
source_notes: []
---
# Project Name
## Current status
One paragraph, kept fresh via PATCH replace.
## Decisions
- [[YYYY-MM-DD-decision-slug]] — one-line summary
## Open threads
- [ ] unresolved thing
## Log
- 2026-06-07: 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.
### 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.
### people/\<name\>.md
`type: person`. Use lowercase kebab-case for the slug (e.g. `bryan-gilliom.md`).
---
## Cross-References
Use Obsidian wiki links freely: `[[note-name]]` or `[[folder/note]]`. The REST API
doesn't resolve them, but Obsidian does when the operator browses the vault.