Brain Monitor
What the Brain Monitor does
The Brain Monitor is a single-page view of everything currently entering your team's brain — memories, conversations, messages, tasks, contacts, Granola transcripts. Instead of seven separate admin pages, the monitor streams all seven entity types into a unified, filterable, paginated feed scoped to one team at a time.
It is the operator console for the memory layer. You open it to see what your team is
producing right now, to flip an item's truth_level from WORKING to
VALIDATED after a peer review, to delete a piece of noise (soft delete —
recoverable for 30 days), or to drill in as a superadmin and inspect another team's brain
cross-team.
Universal truth-level contract
From Phase 11 on, every entity table written by xbrain (not just
memory_items) carries the three Brain Monitor columns: truth_level,
deleted_at, deleted_by. Adding a new entity table after Phase 11
requires these columns by default.
How to access
The Brain Monitor lives on app-site at the team-scoped URL:
urlhttps://app.grooveos.app/account/teams/brain/?team=<team-slug>
You must be signed in (GitHub OAuth via Phase 10) and you must be a member of the team. The
page reads your xbt_ token from localStorage; the API enforces
X-Team-Scope server-side, so you cannot bypass team isolation by editing the URL.
Truth levels — the 5-level epistemic ladder
Every Brain Monitor row carries a truth_level badge. The five levels form a
one-way progression: you can promote a fact forward (e.g. WORKING → VALIDATED),
but you cannot demote it without an explicit workflow.
Raw chat output, web clips, draft notes. Unverified. The default level for anything that enters xbrain without explicit classification.
In-progress knowledge actively used but not yet validated. Most team knowledge lives here.
Peer-reviewed: at least one team member has explicitly approved this fact.
The definitive answer your team has agreed on. CANONICAL facts are injected automatically in agent runs via system prompts.
Shareable outside the team. Requires explicit promotion from CANONICAL.
Editing a row inline
Each Brain Monitor row exposes a truth_level dropdown on the right. Click it,
pick a new level, the change is sent immediately as a PATCH against the underlying
entity:
bashPATCH /v1/brain/events/<entity_type>/<entity_id>
Authorization: Bearer xbt_...
X-Team-Scope: <slug>
Content-Type: application/json
{"truth_level": "VALIDATED"}
On success the row re-renders with the new badge. On 403 (you tried to edit something you didn't author, see Permissions below) a toast surfaces:
toastYou can only edit items you created. Contact a team admin to modify
items created by others.
Deleting and restoring — 30-day window
Every row has a Delete button. Confirming it issues a
DELETE /v1/brain/events/<entity_type>/<entity_id>:
- The DB row is not physically removed —
deleted_atis set to now anddeleted_byrecords who did it. - The Qdrant payload (for vector-backed entities —
memory_item,granola_note) is marked withdeleted_at_tsin the same operation, so semantic search immediately stops returning the item. - Every consuming endpoint (
/v1/memory/search,/v1/tasks,/v1/crm/contacts, etc.) excludesdeleted_at IS NOT NULLrows from now on.
Within the next 30 days the row is recoverable. In the Brain Monitor, flip the Show deleted toggle — deleted rows appear faded with a Restore button. Clicking it:
bashPOST /v1/brain/events/<entity_type>/<entity_id>/restore
Authorization: Bearer xbt_...
X-Team-Scope: <slug>
Returns 200 and deleted_at is set back to NULL. The row is fully visible again.
After 30 days — brain-janitor purges hard
A daily cron (xbrain-brain-janitor container) runs at 03:00 UTC. Rows with
deleted_at < NOW() - INTERVAL '30 days' are hard-deleted from Postgres,
Qdrant, and Neo4j in that order. After that point the row is unrecoverable.
The 7 entity types covered
entity_type |
Underlying table | Vector-backed | Has created_by |
|---|---|---|---|
memory_item |
memory_items |
Yes (Qdrant) | No (admin-only edit) |
granola_note |
memory_items (filtered on source='granola') |
Yes (Qdrant) | No (admin-only edit) |
conversation |
conversations |
No | Yes |
message |
messages |
No | No (admin-only edit) |
team_message |
team_messages |
No | Yes |
task |
tasks |
No | Yes |
contact |
contacts |
No | No (admin-only edit) |
Permissions
| Role | View team brain | Edit own items | Edit any item | Delete + restore |
|---|---|---|---|---|
| Member | Yes | Yes | No (403) | Own items only |
Team admin (team_members.role='admin') |
Yes | Yes | Yes | Yes |
Superadmin (sub in ADMIN_USER_SUBS) |
Every team (drill-down, audited) | n/a (v1 read-only) | No (v1 read-only) | No (v1 read-only) |
Why admin-only for some types
memory_items, contacts, and messages have no
created_by column in the current schema (legacy from Phase 2 / Phase 7). The
author check therefore cannot run, so a member cannot edit these — only a team admin
can. A future migration can add created_by to lift this restriction.
Live updates — 30-second polling
The Brain Monitor uses a 30-second polling cycle (not WebSockets, not SSE — locked v1
choice). Every cycle, the page calls GET /v1/brain/events?since=<last-seen-iso>
and prepends any new rows to the top of the table.
- Existing rows are never re-rendered — if you opened a row's dropdown 5 s ago, it stays open.
- Your scroll position is preserved — prepending happens above the viewport.
- The page tab being backgrounded does not stop the cycle.
Superadmin dashboard — cross-team visibility
A second page at /account/admin/ grants superadmins a
cross-team view of every team's brain. Superadmins are defined server-side by the
ADMIN_USER_SUBS env var (a comma-separated list of user subs —
e.g. google:115...,github:mrboups). Anyone whose sub is in that list can open
the dashboard.
Who is a superadmin?
Adding a new superadmin is a deliberate operator action with privacy implications. The workflow is:
- Edit
infrastructure/.envon the VM: append a sub toADMIN_USER_SUBS. docker compose restart memory-api— the gate (_is_admin()) re-reads the env at startup.- The new principal can now open
/account/admin/. There is no UI flow to add a superadmin — this is intentional (no privilege escalation path from inside the app).
The 4 sections
| Section | What it shows | Endpoint |
|---|---|---|
| Brain Overview | Per-team matrix — counts × entity_type × truth_level. Hover a cell for the per-level breakdown. | GET /v1/admin/brain/overview |
| Storage | Per-team Postgres rows + Qdrant points + MinIO bytes (human-formatted). Cells showing N/A mean Qdrant or MinIO was unreachable during this fetch — the page fails soft. | GET /v1/admin/brain/storage |
| Activity | 30-day events/day sparklines per team. Inline SVG — no chart library. | GET /v1/admin/brain/activity |
| Top Sources | Top-5 source labels per team plus an "other" bucket (LibreChat, OWUI, Granola, agent-runtime, API, etc. — discovered dynamically). | GET /v1/admin/brain/sources |
Drill-down with audit
Clicking Drill down → on any team row in Brain Overview navigates to:
urlhttps://app.grooveos.app/account/teams/brain/?team=<slug>&as_superadmin=1
The page renders a yellow banner:
Viewing as superadmin — this access is logged.
The Brain Monitor table loads exactly as it would for a team member, except:
- All Edit / Delete / Restore controls are hidden (v1 superadmin drill-down is read-only).
- Both the initial load and every 30-second poll cycle go through
GET /v1/admin/brain/events?team_slug=<slug>instead of the team-scoped endpoint. - Every call writes a synchronous
audit_logrow withaction='superadmin_brain_access'before any data is read. If the audit write fails, the server returns 500 and serves nothing — there is no unaudited read path.
No break-glass / opt-in in v1
A superadmin gets full content visibility on drill-down. Team admins are not pre-notified. The audit row is the trace, not the consent. A break-glass / opt-in approval workflow is deferred to a later phase.
Lockdown
Set ADMIN_USER_SUBS="" (empty) on the VM and restart memory-api — all five
/v1/admin/brain/* endpoints return 403 for every caller, including a principal
that was previously a superadmin. This is the kill-switch for the cross-team scope.
Deeper reading
- Memory System — the original 5-truth-level model the Brain Monitor generalises to every entity table.
- Teams & Scopes — the
X-Team-Scopeheader and team isolation rules the Brain Monitor enforces on every read and write. - API Reference — full endpoint specs for
/v1/brain/eventsand/v1/admin/brain/*.