---
version: 0.17.0
feature_pitch:
  headline: "One brain maintenance cycle, two CLIs. `gbrain dream` delivers the README promise."
  description: |
    The README has said "the agent runs while I sleep, the dream cycle
    scans every conversation, enriches missing entities, fixes broken
    citations, consolidates memory" for a year. v0.17 makes that real
    as a first-class command (`gbrain dream`) backed by one shared
    primitive (`runCycle`). Autopilot users get lint + orphan sweep
    added to their nightly cycle automatically — no config change.
    Cron users get a single legible verb: `0 2 * * * gbrain dream`.
    Both converge on the same phase order (lint → backlinks → sync →
    extract → embed → orphans) so file fixes land in the DB the same
    night, not the next.
  recipe: null
  tiers: null
---

# v0.17.0 Migration: `gbrain dream` + unified maintenance cycle

**Audience: agents + humans upgrading from v0.16.x. There is no
mechanical migration step required — the schema migration (v16
cycle-lock table) and behavior changes all apply automatically on
upgrade. This file documents what changed, how to verify it, and
the one opt-out users may care about.**

## What changed

### New command: `gbrain dream`

The brand-promise one-liner. Runs one brain maintenance cycle and
exits. Designed for cron.

```
gbrain dream                     # full 6-phase cycle
gbrain dream --dry-run --json    # preview, agent-readable
gbrain dream --phase lint        # single-phase (fast, targeted)
gbrain dream --pull              # git pull before syncing
0 2 * * * gbrain dream --json    # nightly cron
```

See `gbrain dream --help` for the full flag reference.

### Autopilot now runs lint + orphan sweep

`gbrain autopilot --install` users: on upgrade, your daemon's cycle
gains two phases it didn't run before:

- **lint --fix** — auto-fixes LLM artifacts, placeholder dates, bad
  citations across the brain. Modifies files on disk.
- **orphan sweep** — reports (read-only) pages with no inbound
  wikilinks. Visible in `gbrain jobs list` output for each
  `autopilot-cycle` job.

No action required. The new phases run on the daemon's existing
interval.

### Shared primitive: `src/core/cycle.ts`

Three callers (dream CLI, autopilot inline path, autopilot-cycle
Minions handler) now all delegate to `runCycle(engine, opts)`. One
source of truth for what happens overnight.

### Cycle coordination via a DB lock table

`gbrain_cycle_locks` (new table, migration v16) replaces
session-scoped `pg_try_advisory_lock` which the v0.15.4
PgBouncer-transaction-pooler fix silently broke. The table has a
TTL (30 min), refreshed between phases, so crashed holders
auto-release.

## Verify after upgrade

```bash
# 1. Dream command exists:
gbrain dream --help

# 2. Run a dry cycle (safe, no writes):
gbrain dream --dry-run --json

# 3. If you run autopilot --install:
gbrain jobs list --status complete | head -5
# Each `autopilot-cycle` entry now has 6 phases in its report,
# not 4. Check a recent one with `gbrain jobs get <id>`.

# 4. Schema migration landed:
gbrain doctor  # should show no pending migrations
```

Expected `gbrain dream --dry-run` output on a healthy brain:

```
Brain is healthy. 6 phase(s) checked in 1.3s.
```

Or with `--json`:

```json
{
  "schema_version": "1",
  "status": "clean",
  "phases": [...],
  "totals": { "lint_fixes": 0, "backlinks_added": 0, ... }
}
```

## Opt-outs for autopilot-installed users

If you explicitly do NOT want autopilot's daemon modifying files
(lint + backlinks phases write to disk):

**Option 1: disable those phases in cron-dream but keep autopilot
running.** Since dream is separate, you can run just the phases
you want from cron without touching autopilot:

```bash
# e.g. only re-embed and orphan-sweep nightly, skip file mutations:
0 2 * * * gbrain dream --phase orphans
```

**Option 2: uninstall autopilot and use cron-dream only.**

```bash
gbrain autopilot --uninstall
# Then add to your crontab:
0 2 * * * gbrain dream --pull
```

**Option 3: accept the default.** The new phases are conservative:
lint only fixes known-safe artifacts (em dashes, placeholder dates),
never destructive. Back-link fills are additive. If something does
go wrong, `gbrain dream --dry-run` always tells you what WOULD
change before you run it for real.

## Troubleshooting

**"cycle_already_running" in dream output:**
Another cycle (probably autopilot's daemon) is holding the lock.
Expected behavior — dream skipped to avoid racing the daemon. The
daemon's next interval will pick up the work.

**`gbrain dream --dry-run` reports changes when you expected none:**
Check `gbrain doctor` for drift: lint issues, stale embeddings,
missing back-links. Dream's dry-run is the honest preview of what
autopilot's daemon will do on its next cycle.

**Minion `autopilot-cycle` jobs failing after upgrade:**
Open a GitHub issue with the output of `gbrain jobs get <id>` for a
failing job. The new runCycle-backed handler preserves the
partial-failure semantic (one phase failing doesn't block future
cycles), but specific phases may surface new error classes.

## What did NOT change

- `gbrain autopilot --install` machinery (launchd / systemd /
  crontab generators). Existing installs keep working.
- `~/.gbrain/autopilot.lock` daemon-singleton lockfile. Separate
  concern from the new per-cycle lock.
- `gbrain jobs` interface. `gbrain jobs get <id>` now shows a
  richer report structure (schema_version:"1"), but the surface
  API is stable.

---

*This migration file is informational only. No mechanical step is
required — all changes apply automatically on `gbrain upgrade`.*
