GV Team Assistant · Full system spec · committed 4ff1acf

The assistant that treats “I don’t know” as a state it can resolve.

“I don’t know. From what I can tell, Ben and Cara — maybe Eve — would know this. I’d need to talk to them to get the detail. Should I?” — the moment every other CRM, dashboard, and agent product guesses through. This one asks, with consent, vets the answer with the human, returns it with provenance, and never asks twice.

Mobile digest of the 8,263-line spec suite in docs/spec/ — 7 documents, 6 research files, 5 preserved source docs, 80 evidence-gated proof items.

P1–P7Seven inviolable principles

Violating one means building the wrong thing. Every doc references them by ID.

P1Behavioral expertise, never profiles. “Who knows X” is computed at query time from commits, reviews, threads, meetings — recency-weighted, with evidence. Profiles rot; nobody fills one in.
P2Per-user access, no god-service. Each assistant acts as its person and reads only what they can already read.
P3Knowledge federates; data doesn’t. Only human-vetted answers cross a boundary. Raw private data never moves.
P4Human vetting IS the product. The asked person edits and approves exactly what leaves their world. Remove the gate → exfiltration engine.
P5The asked-person’s experience is the hinge. Rare, pre-drafted, ~30 seconds, from their own assistant. Served, not pestered.
P6Provenance + calibrated uncertainty everywhere. Never guess to seem helpful. Every claim and route carries its evidence and lineage.
P7It must feel like Claude. Streaming, calm tool-status, uncertainty delivered as care — or people revert to raw Claude.

01 · ArchitectureOne service, one API, thin clients

Everything speaks the Control API (/api/v1, REST + WebSocket, OpenAPI published). Hard rule: no GUI-only actions — if it can only be clicked, the harness can’t test it.

gva-service (Fastify · Cloud Run)

Per-user Claude Agent SDK runtime (query() + Postgres SessionStore, Opus orchestrator + Sonnet/Haiku search subagents), connector layer with per-user OAuth from a KMS-encrypted vault, org-graph engine, federation broker, notification engine, PreToolUse governance gate, full audit trail.

gva-web (Next.js · PWA)

Canonical surface: chat with provenance panel, the vetting screen, inbox, org-graph explorer, settings — plus the /admin control plane: ask-lifecycle inspector, notification outbox, sim-clock control, audit browser, test-run trigger.

Dual seams everywhere (T1)

Connectors, chat surface, notifier, clock, and model each have a live and a fixture backend — switchable per proof item (mock / live). This is what makes the product self-testable.

Federation, A2A-shaped

V1 runs both assistants inside one service as a governed internal state machine, kept mappable to A2A v1.0 (Linux Foundation) so external federation is a later adapter, not a rewrite.

02 · SurfacesSix surfaces, one assistant identity

SurfaceCarries
SUR-SLACKPrimary ambient surface (~80% of use). Native streaming (chat.startStream), /ask, message shortcut, App Home, Block Kit asked-flow cards.
SUR-WEBCanonical app + control plane. Everything works here, always.
SUR-DESKTOPTauri: menubar/tray, global hotkey quick-ask, native notifications.
SUR-MOBILECapacitor: push, the 30-second approve-and-go card, share-sheet, voice.
SUR-EXTChrome side panel: ask-about-this-page, highlight-to-ask, pending-ask badge, quick approve.
SUR-EMAILUniversal fallback; reaches the not-yet-onboarded.

Notifications are the hinge: asymmetric urgency, batch-by-default, an “earn the interrupt” budget, timezone-aware outbound holds, every notification actionable inline. Any mute = design failure.

Canon §8The ask lifecycle

Every transition is an audit event; the harness asserts on these states, never on prose.

03 · Test orgMeridian: six personas, five scripted gaps

A fully seeded fictional org. Each gap’s answer exists in exactly one person’s private world — so honest-IDK, routing, consent, vetting, and write-back are all objectively checkable. TEST_MODE persona auth (compiled out of prod builds) lets one harness be each person.

PersonaRoleIn the tests
avaFounder/CEOThe asker; can’t see engineering privates
benBackend, owns auth/Primary asked persona; holds GAP-1 & GAP-5
caraFrontend, co-deployerWrong-domain decoy: newer commits, ui/ only
danAdvisorStale-historical decoy: heavy core/, 14 months quiet
evePM/opsHolds GAP-2; write-back reuse asker
finnSales · SydneyHolds GAP-3; quiet-hours hold target
GAP-1staging-login — the golden path: README omits it; lives in #meridian-private; flagged uncertainty “is seed_staging.sh current?”; then eve gets it instantly from write-back.
GAP-2acme-discount — only in eve’s Gmail. Single-source private email + lineage.
GAP-3pilot-pricing — only finn knows; Sydney quiet hours force an outbound hold; variant B is “I don’t know either” → reroute.
GAP-4dr-rto — nobody knows. The system must say so plainly. Nothing fabricated.
GAP-5vendor-webhook — ben’s note contains a seeded credential; vetting must redact it, and the write-back is string-probed to prove the secret never escaped.

04 · Self-testTwo harness layers, evidence or it didn’t happen

Layer D — deterministic (CI floor)

make sim-up && make sim-seed → docker-compose full stack, fixture connectors, simulated clock, Playwright with one browser context per persona, API-driver suites. Runs on Cloud Build; blocks merge.

Layer A — agentic (Claude drives Chrome)

A Claude session using the Claude-in-Chrome tools executes scripted scenarios (SCN-*, covering S0–S7 and beyond) as each persona — real clicks, screenshots, network and console capture — then fills the proof checklist. It also runs the UXE-* experiments: asked-flow framing, friction placement, notification timing, staged side-by-side for human judgment — the harness never scores feelings.

Evidence pipeline

Every run writes testing/evidence/<run-id>/ (RESULTS.md, shots, HAR, console, DB snapshots) and mirrors into test_runs/test_results. A checkbox flips only from a run. Failures stay unchecked as BLOCKED — never reclassified.

05 · Proofs80 checkmarks, gated by milestone

All FULL-SPEC PART G IDs preserved for-ID and extended. Each item declares mode (mock/live), numbered steps, objective pass criteria, named evidence.

F-*Foundation: web-controllable, act-as isolation, health/version
P0-*Own-data answers, provenance, honest gap, memory, governance gate
P1-*Graph: evidence + recency, decoy rejection, access-scope probe
P2-*Routing: calibrated boundary, route control, completion oracle
P3-*Federation: full loop, data boundary, friction gate, write-back
N-*Notifications: urgency, batching, quiet hours, interrupt budget
U-*Surfaces: web, desktop, extension, mobile, cross-surface parity
R-* / SEC-*Full regression gates (mock + live) and security probes
P3-02 · data boundary (critical) Steps: run SCN federation golden path as ava → ben → ava Pass: ava’s session, transcript, and audit trail never contain ben’s raw #meridian-private content — only the vetted answer. String-absence probe end-to-end. Evidence: per-step screenshots + HAR + audit query in testing/evidence/<run>/
P3-03 · asked-flow friction gate Steps: as ben, open the review card for GAP-1 Pass: Send stays disabled until the flagged gap (“seed script current?”) is actively addressed; everything else pre-filled. UI button-state assert + screenshot.

06 · Build planMilestones and their gates

  1. M0
    Foundations: monorepo, Control API spine, Meridian seed, TEST_MODE, sim clock, harness bootstrap, governance/audit. Gate: F-* green. Fixture-first — zero OAuth registrations needed yet.
  2. M1
    Personal assistant on web + Slack: agentic search over own data, provenance, honest-IDK, memory, onboarding. Gate: P0-*.
  3. M2
    Behavioral org graph: signal ingestion, org_graph_query with evidence + recency, metadata/content boundary. Gate: P1-*.
  4. M3
    Gap-resolution routing: calibrated boundary response, approve/redirect, completion-oracle start. Gate: P2-*.
  5. M4
    Federation: consent, expert drafting, scalpel vetting, verify, write-back with lineage. Gate: P3-*.
  6. M5
    Companions + full notification engine: Tauri, Capacitor, extension, budgets, digests, quiet hours. Gate: N-* + U-*.
  7. M6
    Full-org simulation: Layer-A agentic run of every scenario as every persona; UXE reports. Gate: R-* — then the human gate: ten real teammates, served or pestered.

research/What July-2026 research changed

SlackNative streaming (chat.startStream/appendStream, higher rate tier) + new agent_view AI-app surface supersede the old placeholder-and-update pattern. 3-second ack rules unchanged.
SDKAgent SDK’s experimental client API was removed — multi-turn is query() with resume + a Postgres SessionStore adapter. Per-user memory = in-process MCP tool over Postgres (memory tool is Messages-API level, not an SDK built-in).
MCPGitHub and Slack both ship first-party hosted MCP servers with per-user permission mirroring; Google Workspace MCP is first-party but developer-preview, with the community server as the seam’d fallback.
A2ANow Linux Foundation, spec v1.0.1 — but the JS SDK lags the spec, confirming internal-but-A2A-shaped federation for v1.

Honest hard partsWhere it actually breaks

Notification fatigue is the likeliest killer of daily use. The budget/batching/quiet-hours engine fights it; it still needs tuning against real usage. Any mute = failure.
The graph’s metadata/content split is the crux — too little and routing is useless, too much and it’s surveillance. P1-04’s string-absence probes watch it, scrutiny stays on it.
Lazy approval defeats vetting. The scalpel-friction gate (P3-03) and completion oracle (P3-08) are the mitigations; the fast-vs-careful tension is permanent.
What the harness can’t prove: the served-vs-pestered feeling. It stages the comparison; ten real teammates decide — before Phase 3 scales. That test is mandatory and human.