← back to George Token Broker

README.md

55 lines

# george-token-broker

A **health-watchdog** for the local George Gmail agent (`com.steve.george-gmail`,
`http://127.0.0.1:9850`). It does **not** re-mint tokens — minting a *user* OAuth
refresh token requires interactive Google consent, so a headless re-minter is
impossible. This is the "self-healing" piece of the Officer Idea Council's #1 idea
(2026-06-29), reframed to what's actually buildable.

## What it does (`poll.mjs`)
Each run probes two layers and takes the **correct action per failure mode**:

| Layer | Endpoint | Proves |
|-------|----------|--------|
| process liveness | `GET /health` (public) | George is up |
| token liveness | `GET /api/profile?account=X` (auth) | the refresh token still works |

- **process down / unreachable** → restart the launchd job + alert.
- **token dead (`invalid_grant`)** → **alert only**. A restart reloads the *same*
  dead token; the fix is interactive re-consent (and the real cure is publishing the
  OAuth app to production — see the memo below).
- **all ok** → quiet; records state.

Writes `data/latest.json` (consumed by the meta-watchdog) and appends `data/poll.log`.

## Safety — DRY_RUN by default
`poll.mjs` defaults to **`DRY_RUN=true`**: it polls, classifies, and writes
`latest.json`, but only **logs** `WOULD restart…` / `WOULD alert…` — it changes
nothing live. The launchd plist is shipped **unloaded**. Nothing runs or acts until
you choose to.

```sh
# one dry-run poll (safe — default):
node poll.mjs

# arm live alerts + restart:
DRY_RUN=0 node poll.mjs

# load the 15-min watchdog (still DRY_RUN unless you add DRY_RUN=0 to the plist):
launchctl bootstrap gui/$(id -u) ~/Projects/george-token-broker/com.steve.george-token-broker.plist
launchctl bootout   gui/$(id -u) com.steve.george-token-broker   # disable
tail -f /tmp/george-token-broker.log
```

## The real root fix (gated — not in this repo's scope)
This watchdog makes the next break **loud, not silent**. It does **not** fix the
root cause — the ~weekly refresh-token expiry from the OAuth app being in Google
"Testing" mode. That cure is one Google Cloud console change (publish app to "In
production"), documented with full plan + officer sign-off in:

`~/.claude/yolo-queue/pending-approval/george-oauth-durable-fix-2026-06-29.md`

## Alert channel
Fallback that does **not** depend on George (George may be the thing down): CNCP
parking-lot `POST 127.0.0.1:3333/api/parking-lot`. Extend in `alert()` as needed.