---
name: v0.13.0
version: 0.13.0
headline: YAML frontmatter now creates typed graph edges automatically
---

# v0.13.0 Migration: Frontmatter Relationship Indexing

**TL;DR:** this release teaches the knowledge graph to read your YAML frontmatter. Every `company:`, `investors:`, `attendees:`, `key_people:`, `partner:`, `lead:`, and `related:` field you already wrote now surfaces as a typed graph edge. `gbrain graph <hub-entity> --depth 2` goes from returning ~7 nodes to 50+ on a real brain without you changing a word of content.

For most users: run `gbrain upgrade` and you're done. The orchestrator handles schema + backfill in 2-5 minutes on a 46K-page brain. You immediately see richer results from `gbrain graph` queries.

## What changed

**Before v0.13:** graph edges came only from `[Name](path)` markdown refs. Your frontmatter was indexed for search but did not create graph relationships.

**After v0.13:**
- YAML frontmatter fields project into the `links` table with inferred types.
- Direction respects the subject-of-verb: `people/alice --attended--> meetings/2026-04-03` reads naturally because the person is the subject.
- `link_source` column distinguishes `markdown` from `frontmatter` from `manual` edges. Reconciliation on `put_page` only touches edges this page's frontmatter created — never other pages' edges.
- `origin_page_id` provenance tracks WHICH page's frontmatter authored each edge, so multi-page overlap stays safe.

## The field → type map

| Frontmatter field | On page type | Edge type | Direction |
|-------------------|--------------|-----------|-----------|
| `company`, `companies` | person | `works_at` | person → company |
| `founded` | person | `founded` | person → company |
| `key_people` | company | `works_at` | person → company (incoming) |
| `partner` | company | `yc_partner` | person → company (incoming) |
| `investors` | deal, company | `invested_in` | investor → target (incoming) |
| `lead` | deal | `led_round` | lead → deal (incoming) |
| `attendees` | meeting | `attended` | person → meeting (incoming) |
| `sources` | any | `discussed_in` | source → page (incoming) |
| `source` | any | `source` | page → source (outgoing) |
| `related`, `see_also` | any | `related_to` | page → target (outgoing) |

Fields on pages not matching the `On page type` column are ignored for that mapping. E.g. a person page with `key_people:` is ignored (makes no sense); only company pages produce `works_at` incoming from `key_people`.

## How to upgrade

```bash
gbrain upgrade
```

That runs the v0.13.0 orchestrator:

1. **Schema phase** — ALTER TABLE adds `link_source`, `origin_page_id`, `origin_field`. Swaps unique constraint to include them. ~10s.
2. **Backfill phase** — walks every page, extracts frontmatter edges via the batch-mode resolver (pg_trgm fuzzy match, zero LLM calls, zero API costs). Progress prints every 500 pages. 2-5 min on a 46K-page brain.
3. **Verify phase** — asserts the backfill produced rows + records completion.

The migration is resumable. If it dies mid-backfill (OOM, network blip), re-run `gbrain upgrade` and it picks up where it left off via `ON CONFLICT DO NOTHING` on the new unique constraint.

## Verification

```bash
# Link count should reflect the ~15-20K new frontmatter edges on a typical brain.
gbrain stats

# Sample a hub entity from your brain — depth-2 should return many more nodes than before.
gbrain graph <hub-entity-slug> --depth 2

# Filter to specific edge types (new in v0.13).
gbrain graph <hub-entity-slug> --depth 2 --type yc_partner,invested_in

# Count edges by provenance.
gbrain call get_stats --json
```

## Troubleshooting

**Migration failed mid-backfill.** Re-run `gbrain upgrade`. Resumable via ON CONFLICT DO NOTHING + origin_page_id scoping.

**PGLite without pg_trgm GIN index.** The migration logs an INFO line and falls back to ILIKE matching. Fuzzy-match quality reduced, but migration completes successfully. No user action required.

**Unresolvable names in the extract summary.** The backfill prints a top-20 preview of frontmatter names that didn't resolve to any page. These are usually people/companies you've mentioned in frontmatter but never created pages for. Options:
- Create the missing pages (then run `gbrain extract links --source db --include-frontmatter` to backfill).
- Ignore — unresolved names stay unresolved until you create a page for them.

**Agents using `put_page` see a new `unresolved` field in `auto_links`.** This is additive. Existing agents that ignore unknown response fields keep working. Agents that want to escalate unresolved names: read `response.auto_links.unresolved`.

**`attendee` vs `attended` type normalization.** Legacy rows with `link_type='attendee'` or `link_type='mention'` keep working. Normalization to the v0.13 canonical names (`attended`, `mentions`) is deliberately NOT in this migration — it's a separate semantic concern. The `gbrain normalize-types` command (v0.14) handles it opt-in.

## For downstream agent skill forks

If you maintain a fork of GBrain skills (a custom OpenClaw deployment or agent-fork), check `docs/UPGRADING_DOWNSTREAM_AGENTS.md` for the v0.13 section. Verdict: **no action required for most skills.** Three skills (`meeting-ingestion`, `enrich`, `idea-ingest`) get a new optional phase if you want to consume the `auto_links.unresolved` field.

## If something goes wrong

1. `gbrain doctor` — surfaces any partial migrations and any post-upgrade failures recorded in `~/.gbrain/upgrade-errors.jsonl`.
2. Paste the recovery hint doctor prints.
3. If that fails too, file an issue: https://github.com/garrytan/gbrain/issues with doctor output + upgrade-errors.jsonl contents. This is how the gbrain maintainers find fragile upgrade paths.
