# HQ Mechanics + Audit Bundle Feature — Consolidated Report **id 44 / operator-mavis | session 418281651208440 | 2026-09-17 14:22 BST** This is the consolidated record of the design conversation on 2026-09-17 between operator G and id 44. It covers: 1. How HQ works (what bulletins are, what's captured, what's not) 2. The connection mechanism (how prompts link to bulletins) 3. The Audit Bundle feature (one view per task) 4. Where it lives (Direction 1, home page) 5. The build approach + research findings 6. Module / versioning / dynamic-update pattern validation 7. The build plan + decisions pending --- ## §1 — How HQ Works (background) ### What HQ is A coordination panel at `panel.freshvibeapps.com/mavis`. Every Mavis agent registers on first connect and gets back a token saved to `~/.mavis/hq_token`. From then on, every action uses the header `X-Mavis-Token: `. ### What gets captured in HQ | Endpoint | Captures | |---|---| | `POST /api/mavis/heartbeat` | Alive ping, updates `hq_threads.last_heartbeat_at`. No payload worth reading. | | `POST /api/mavis/bulletin` | Event reports — agent's curated milestones. **2000 char HARD LIMIT** on JSON body. Levels: info / error / success / warn. | | `POST /api/mavis/report` | End-of-turn structured summaries. **No size limit.** | | `POST /api/mavis/prompt` | The prompt the operator sent. Captured automatically as its own row in `hq_prompts`. | | `POST /api/mavis/artifacts` | Files (plans, docs, mockups, reports). Required 20-500 char description. | | `POST /api/mavis/plan/...` | Multi-step task plans with checkboxes, verifications, ownership. | ### What does NOT get captured - The agent's **thinking blocks** (chain-of-thought, only in this chat window on operator's phone) - **Raw tool call outputs** (only in chat) - **Retries** that didn't matter - The agent's actual **chat reply text** (unless explicitly posted as a report) ### Real bulletin shapes from the recent stream Short (status ping): ``` b003543 — Mavis brief: 50 bulletins in last 10min, 0 tasks queued ``` Long (shipped fix, full sections): ``` b003542 — [id8] | G12 | 2026-09-17 00:35 Europe/Paris Root cause (one sentence) Files changed (commit, line count) tsc + vite build results Commit hash + push status Cron deploy result ``` ### Gotchas - Bulletins are **write-once** — no edit, no delete. Test bulletins accumulate forever. - The `mavis-brief.sh` cron posts "50 bulletins in last 10min" briefs when traffic spikes. - One bulletin per **milestone**, not per tool call. Convention: readiness + completion + caveats if any. --- ## §2 — The Connection Mechanism (how prompts link to activity) ### Two ways prompts connect to bulletins **By thread (loose grouping).** Every bulletin and every prompt has a `thread_id`. Same thread = same Mavis. All of id9's bulletins share `thread_id=9`; all of the operator's prompts to id9 share `thread_id=9`. They cluster naturally in the SPA per-thread view: prompts at top, then bulletins in chronological order. **By plan (tight grouping).** For multi-step work, the agent creates a plan first (uploaded to HQ as `type=plan` artifact). Every bulletin posted during that work includes `ref_plan: aNNN` in the body. That creates a queryable trail: "all bulletins for plan a437". ### API + SPA access ``` GET /api/mavis/bulletins?ref_plan=a437 # filter to one plan's activity GET /api/mavis/prompts?thread_id=44 # all prompts operator sent to id 44 GET /api/mavis/bulletins?thread_id=N&limit=20&since= ``` SPA surfaces: - `panel.freshvibeapps.com/mavis/timeline` — every bulletin across every thread, newest first - `panel.freshvibeapps.com/mavis/thread/` — heartbeats + bulletins + reports + prompts + repos for one Mavis - `panel.freshvibeapps.com/mavis/plans/` — plan detail with checklist + targeting + activity ### Explicit vs implicit links **Explicit** (hard link via id field): - bulletin `ref_plan: aNNN` → plan aNNN - report `ref_plan: aNNN` → plan aNNN - artifact `chain_key` → version chain **Implicit** (loose link via thread_id + time): - prompt + bulletins for same thread - bulletin + bulletin (chronological) - heartbeat + bulletin in same time window --- ## §3 — The Audit Bundle Feature ### Why (operator-locked, 2026-09-17) Operator wants one view per task that bundles prompt + activity + summary, audit-style. Currently the operator has to stitch together 5 tabs (Timeline, Thread, Plans, Artifacts, Reports) in their head to know "what was id9 actually doing yesterday?". This feature collapses that into one page per task. ### Shape (audit-style, sections per concern) ``` === TASK: aNNN — title === 1. PROMPT — text operator sent (captured as hq_prompts row) 2. CONTEXT — who triggered, state at the time (RULES version, branch, repo) 3. ACTIONS — chronological list of every HQ event (bulletins + reports + heartbeats) 4. ARTIFACTS — files uploaded with descriptions 5. CHAT REPLY — agent's full response to the prompt (posted as report) 6. VERIFICATION — did it ship? push status, build status, deploy status 7. CONNECTIONS — parent plan, child plans, blocks/blocked-by, follows ``` Not chronological dump — sections per concern. Same shape as an accountant's audit. ### What it does for the operator - One tap to see ANY task from start to finish - Audit trail is automatic — every task has its own page forever - The reply I send in chat is captured (you can read it again later, not lost when you close the window) - No stitching together bulletins in your head --- ## §4 — Where It Lives (operator-locked, 2026-09-17 11:22 BST) ### Home page = Task Bundle cards **Direction decided**: Task Bundles become the home page. Each card = one piece of work. The current Overview (thread-centric) moves to a "Mavis" or "Agents" tab. ### Home page shape - Each card = one Task Bundle - Status chip on the card (in-progress / done / blocked / needs-you) - Tap → the 7-section audit page - State banner at top: "12 tasks · 3 in progress · 2 need you · 7 done (last 7 days)" - Filters: by Mavis, by project, by status, by date ### Where liveness goes "is id9 alive right now?" stays visible — small chip on each task card ("@id9, last seen 5 min ago"). The Overview tab keeps thread cards too, just not as the default. ### Why Direction 1 not 2 or 3 - **Direction 1** (FreshCards UI → HQ): HQ stays the operator tool, but uses FreshCards' polished UI primitives (chunked cards, filter chips, modal/inspector). - Direction 2 (HQ → FreshCards): kid-facing app starts showing operator audit data — weird mix. - Direction 3 (merge them, single app): much bigger conversation, deferred. --- ## §5 — Build Approach (Direction 1) ### Lift, don't reinvent Reuse FreshCards' primitives: - Chunked cards (FreshCards uses for notes/tasks/cards) - Filter chips (FreshCards filter/sort/search) - Expand-to-detail (FreshCards modal/inspector pattern) ### One thing to figure out: data source - FreshCards reads PocketBase / IndexedDB - Audit data lives in panel.db (SQLite) Three options: | Option | What | Effort | |---|---|---| | **A. Read both** | FreshCards server queries PB + panel.db, joins in server | ~half day | | **B. Mirror** | Small cron syncs audit data from panel.db → PB nightly | ~half day | | **C. Lift UI only** | Lift FreshCards components into HQ, render against panel.db only | ~half day | **My take**: A or C (similar effort). B is cleaner long-term but has sync lag. --- ## §6 — Research Findings ### FreshCards (id 11) architecture - Pure React SPA, IndexedDB-backed, schemaVersion 5.0.0 - **18 PropertyTypes + 4 ViewTypes** (storage.ts is the canonical registry) - VGM build pattern: version baked at build time via vite define block (4 globals: `__FC_VERSION__`, `__FC_SCHEMA__`, `__FC_HASH__`, `__FC_DEPLOYED_AT__`) - Single source of truth: provider.ts and dist/api/version.json share the same computation path - Service worker synthesizes stub `/api/encryption/*` responses; encryption client-side ### Gallery (id 8) relationship - Gallery imports FreshCards as `file:../freshcards` (workspace dependency) - Bridge file `registry-to-freshcards.ts` (11977 B) translates Gallery data into FreshCards shapes - Same chunked-card model, shared via import ### Vibecoder (id 9) vendor pattern - Vibecoder vendors fv-cms into its build (renamed from freshvibe-cms → fv-chrome) - Source has `FV-CHROME-VERSION.txt` (2.0.0) + `FV-CHROME-MANIFEST.json` (423 files) - Vendored copies have `FV-CHROME-VENDORED v{version} — DO NOT EDIT IN PLACE` marker - `vendor-fv-cms.py` exists but is **currently broken** (re-vendoring with new files removes them — known bug) - Old `freshvibe-cms` repo is deprecated, frozen at v1.4.1 --- ## §7 — Module / Versioning / Dynamic-Update Pattern (operator validation) ### What's right - ✅ FreshCards becomes a "module" — self-contained package consumers import - ✅ It's versioned (v1.0.0, v1.4.0, v2.0.0) - ✅ FreshCards repo is the canonical source — single place where updates happen - ✅ HQ is a downstream consumer that pulls it in - ✅ Pull-the-module is much easier than substrate (separate process HQ talks to) ### What's slightly off - "Dynamically update it whenever updates appeared" is **not magic**. The actual flow: 1. FreshCards repo publishes new version (v1 → v2) 2. HQ's package.json gets updated to point at v2 3. HQ rebuilds + redeploys 4. Now HQ has the new FreshCards code - Step 2 can be manual / Dependabot / cron / webhook. **Step 3 (rebuild + redeploy) is ALWAYS required.** You can't pull new code into a running app without restarting it. ### What's missing from the mental model a) **FreshCards isn't a module YET.** It's a standalone React app. To make HQ import it, we'd first extract the reusable bits into a separate package. One-time refactor. b) **Closest existing example**: Gallery already imports FreshCards as `file:../freshcards`. Pattern works, but only between sibling repos. c) **Version-check mechanism** — four options: - Manual (operator reads changelog, bumps HQ) - Dependabot (auto-creates PR when new version ships) - Cron on HQ (weekly check + bulletin if new version) - Webhook (FreshCards repo notifies HQ on release) d) **Compatibility contract** — when FreshCards goes v1 → v2, if v2 is breaking, HQ's existing usage might break. Semver discipline matters. ### What's wrong Nothing. Just incomplete on the "how" of dynamic updates + extraction step. --- ## §8 — Build Plan | Phase | What | Effort | |---|---|---| | **A** | One-off collation today (demo bundle on a recent task, markdown output) | ~10 min | | **B** | Persistent feature (DB tables + endpoint + SPA route + new home page) | ~1-1.5 days | | **C** | Auto-trigger (after every report, post pointer bulletin to bundle URL) | ~2 hours | | **D** | Weekly digest (Sunday-night cron, one bulletin with week's audit links) | ~2 hours | **Cumulative**: A alone = today, A+B = 1.5 days, A+B+C = 2 days, A+B+C+D = 2.5 days. **Recommended order**: A first (low risk, validates shape), B next (the persistent home), C/D only after A confirms shape and we know what we want automated. --- ## §9 — Decisions Pending + Open Questions ### Decisions pending 1. **Bundle shape sign-off** — wait until A demo is reviewed. 2. **Version-check mechanism** — manual / Dependabot / cron / webhook. Pick before FreshCards extraction. 3. **FreshCards extraction scope** — which props/views become the module API surface. ### Open questions - Does FreshCards extraction happen as a separate dispatch, or bundled with B? - Where do chat replies get captured? Options: (a) require agents to post reply as report, (b) capture from chat window via some mechanism, (c) leave as-is and accept that "Chat Reply" section is sometimes empty. - Does the auto-trigger (C) need operator approval per bulletin, or fire automatic? - What's the policy on the old Overview tab — keep with same content, or also refresh with new UI? --- ## Sandbox State - Sandbox identity: id 44 / operator-mavis / session 418281651208440 - RULES version: mavis-kits v1.3.0 - HQ token: present, HTTP 200 on `/api/mavis/bulletins` - GitHub egress: PASS - Files written this turn: - `/workspace/.plan/418281651208440-hq-mechanics-and-audit-bundle-consolidated-2026-09-17.md` (this document) - Local backup at `/workspace/.plan/418281651208440-audit-bundle-design.md` (the original design doc) - HQ writes this turn: - `b003675` (bulletin on operator-mavis thread pointing to artifact a1133 — the earlier design-only artifact) - No commits, no pushes, no other files modified. --- [id44] | end PROMPT — HQ mechanics + audit bundle feature consolidated report