---
version: 0.10.3
feature_pitch:
  headline: "Knowledge graph layer — your brain now wires itself"
  description: |
    Auto-link on every page write creates and reconciles links automatically.
    Typed relationships (works_at, attended, invested_in, founded, advises).
    Graph-powered search boost. New `extract --source db` mode for live brains.
    Graph traversal queries via `gbrain graph-query`.
  recipe: null
  tiers: null
auto_execute:
  - cmd: gbrain init
    description: Apply schema migrations v5/v6/v7 (idempotent, safe to re-run)
  - cmd: gbrain extract links --source db
    description: Backfill typed links from existing pages (~30s for 30K pages, idempotent)
  - cmd: gbrain extract timeline --source db
    description: Backfill structured timeline entries (idempotent via UNIQUE index)
  - cmd: gbrain stats
    description: Verify links and timeline_entry_count are non-zero
---

# v0.10.3 Migration: Knowledge Graph Layer

This release turns the structured `links` and `timeline_entries` tables into a
real knowledge graph. Brains that have been accumulating page content but
showing 0 links and 0 timeline entries (because no command populated them) can
now backfill in seconds and keep the graph in sync going forward.

## What Changed

### Auto-link on every page write
Every `gbrain put` (and MCP `put_page`) now extracts entity references from the
page content and writes them to the `links` table with inferred relationship
types. Stale links (refs no longer in the page) are removed in the same call.

The MCP `put_page` response now includes an `auto_links` field:
```
{ status: "created_or_updated", chunks: 5, auto_links: { created: 3, removed: 1, errors: 0 } }
```

To disable: `gbrain config set auto_link false`. Default is on.

### Extended `gbrain extract` + new `gbrain graph-query`

- `gbrain extract links --source db` — backfill structured links by walking pages from
  the engine (works on live brains with no local checkout). FS-source still works:
  `gbrain extract links --source fs --dir <path>` walks markdown files (v0.10.1 behavior preserved).
  Includes typed link inference, within-page dedup, content-hash-based `--since` filter.
- `gbrain extract timeline --source db` — backfill structured timeline entries from page
  content via the engine. FS-source path unchanged.
- `gbrain extract all --source db` — both in one run.
- `gbrain graph-query <slug> [--type T] [--depth N] [--direction in|out|both]` —
  relationship traversal returning typed edges (GraphPath[]).

### Schema migrations (auto-applied on `gbrain init`)
- v5: `links` UNIQUE constraint widened to `(from, to, link_type)`. Same person
  can now both `works_at` AND `advises` the same company (separate rows).
- v6: `timeline_entries` gets a UNIQUE index on `(page_id, date, summary)` plus
  ON CONFLICT DO NOTHING in `addTimelineEntry`. Idempotent inserts.
- v7: Drops the trigger that updated `pages.updated_at` on every timeline insert.
  Structured timeline entries are now graph data only, not search text. The
  markdown timeline section in `pages.timeline` still feeds search via the
  pages trigger.

### Graph health metrics in `gbrain health`
- `link_coverage`: % of entity pages (person/company) with >= 1 inbound link.
- `timeline_coverage`: % of entity pages with >= 1 structured timeline entry.
- `most_connected`: top 5 entities by total link count.
- `dead_links` removed (always 0 under ON DELETE CASCADE — was a phantom metric).

### Search ranking improvement
Hybrid search now applies a small backlink boost after cosine re-scoring:
`score *= (1 + 0.05 * log(1 + backlink_count))`. Well-connected entities surface
higher in results. Works in both keyword-only and full hybrid paths.

### Graph-query MCP exposure
The existing `traverse_graph` MCP operation now accepts optional `link_type` and
`direction` params. With either set, returns `GraphPath[]` (list of typed edges)
instead of the legacy `GraphNode[]` (list of nodes with outgoing-only links).
Backward compat: zero-param calls still return GraphNode[].

## Agent Instructions

### Step 1: Apply schema migrations
```bash
gbrain init
```
Applies migrations v5/v6/v7 to existing brain. Idempotent. Existing data is
preserved (duplicates deduplicated before constraints are added).

### Step 2: Backfill links from existing pages
```bash
gbrain extract links --source db
```
Iterates every page from the engine, extracts entity references, writes typed
links. Should take ~30 seconds for a 30K-page brain. Run with `--dry-run --json`
first to preview (JSON-lines output, agent-parseable).

If you have a local markdown checkout you'd rather walk: `gbrain extract links
--source fs --dir <brain-dir>` (v0.10.1 behavior preserved).

### Step 3: Backfill timeline entries from page content
```bash
gbrain extract timeline --source db
```
Parses `- **YYYY-MM-DD** | summary` lines from page content and writes them
as structured rows. Same scale and timing as links extraction.

### Step 4: Verify the graph populated
```bash
gbrain stats
```
Both `link_count` and `timeline_entry_count` should now be non-zero.

### Step 5: Try a graph traversal
```bash
gbrain graph-query <any-person-slug> --depth 2
```
Should show connected entities with their typed relationships. Useful slugs to
probe: a known YC partner, a well-connected founder, a frequently-attended meeting.

### Step 6: Available link types
- `attended` — meeting page references a person attendee
- `works_at` — context like "CEO of", "works at", "VP at"
- `invested_in` — context like "invested in", "backed by", "funding from"
- `founded` — context like "founded", "co-founded"
- `advises` — context like "advises", "advisor to", "board member"
- `source` — frontmatter `source:` field
- `mentions` — default for any reference that doesn't match the above

Use `gbrain graph-query <slug> --type <link_type>` to filter.

### Step 7: Auto-link is on by default
No action needed. Every future `gbrain put` automatically updates the graph.
To disable: `gbrain config set auto_link false`.

### Step 8: Record completion
```bash
mkdir -p ~/.gbrain/migrations
echo '{"version":"0.10.3","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","status":"complete"}' >> ~/.gbrain/migrations/completed.jsonl
```
