# Project export: Bander

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: The OpenClaw I'd actually give my parents.
- Devpost: https://devpost.com/software/bander
- GitHub: https://github.com/gowtham0992/bander
- Demo: https://gowtham0992.github.io/bander
- Video: https://www.youtube.com/embed/z7OrvquejvQ?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Gowtham (61 commits)

## Devpost submission (written by the team)

### Inspiration

I have been running OpenClaw for a while, and I love it. Somewhere in the middle of that, I kept thinking about my mom. She is exactly the person who would benefit from an assistant like this. She juggles appointments and emails from doctors' offices, and she would rather ask a question in one chat than open five apps. She has told me more than once that she never knows what message these AI tools are going to send. She wishes they would simply show her what they are going to do before doing it. That sentence stuck with me. It is basically the whole product. The creator of OpenClaw has written that the real goal is an agent even his mum could use, and that getting there requires much more thought about safety. My mom was asking for the same thing in her own words. Build Week felt like the right week to attempt the safety part. I could not actually give her my setup. I was not comfortable letting the same process hold access to her real accounts, make a change, and then tell her whether it worked. Build Week therefore became one question. What would an assistant have to look like for me to genuinely hand it to my parents?

### What it does

Maya talks naturally with a real OpenClaw assistant in Telegram. It can answer bounded questions about her calendar and inbox without making her approve harmless reads. OpenClaw never receives her Google Calendar, Gmail, or family messaging credentials. Those live in a separate process called Bander, which also has its own visible Telegram identity. When something real should happen, such as moving an appointment, replying to the doctor's office, or notifying a family member, Bander shows one Card containing exactly what will happen. That includes the Calendar change, email recipient and reply, or sentence the family member will receive. Nothing happens until Maya taps yes. Approval is not a blank check. Bander pins the deal to the state Maya saw. If the Calendar event or email thread changes before execution, Bander refuses rather than acting on stale information. If a provider's response is lost and the outcome cannot be confirmed, Bander says exactly that. It performs no blind retry and never turns uncertainty into a false success. OpenClaw already has useful approvals, and I did not want to pretend otherwise. The difference is where the keys live. With Bander, the assistant can ask for something, but it cannot hold the Google credentials, rewrite the approved action, or speak as the system that carried it out. The family destination and the text sent to it also belong to Bander, not the model. The Sol variant of GPT 5.6 solved the language problem. It understood requests such as moving a dentist appointment and letting a son know as one bounded request. Bander still owned every identity, parameter, credential, and decision about whether anything could happen. How I built it Codex was my implementation and verification partner throughout Build Week. We worked in a loop I became slightly obsessed with. Write the test for a safety property, observe it fail, implement the smallest correct behavior, and then deliberately break the guard to prove the test could catch the real defect. That process is recorded in BUILD_WITH_CODEX.md. It includes the failures, live discoveries, deliberate mutations, and the evidence after each fix. Codex helped me move much faster across the broker, integrations, tests, setup flow, sandbox, and documentation. I still made the calls that shaped the product. Reads would remain easy. Real consequences would require an exact deal. Credentials and outcomes would stay outside the assistant. If an API could not support honest recovery, I would not build that feature. The stack combines OpenClaw and GPT 5.6 Sol for conversation and bounded tool selection with a TypeScript broker holding separate Google Calendar, Gmail, and Telegram credentials behind five bounded MCP tools. The hosted browser experience runs the same authority engine against clearly disclosed seeded data. Judges can experience its approval, refusal, replay, and uncertainty behavior without creating accounts. The complete source, setup guide, evaluator paths, and evidence are in the public repository. Challenges I ran into My assumptions kept being wrong, and the test first loop kept catching them. I originally designed Gmail recovery around caller supplied message identifiers. The first live test showed that Gmail rewrites them. The recovery design was dead on arrival. We rebuilt it around an opaque Bander header bound into the approved email. Recovery now performs one bounded search of Sent mail. It either finds an exact match or reports the result as unconfirmed. The first live compound approval also exposed a state lock deadlock after the user approved a Calendar change and family update. The design looked sound in isolation. The continuous real path proved otherwise. We fixed it and added a permanent regression test. Another review caught Bander about to report that nothing changed in a case where Google might actually have committed the operation. That one scared me. The entire product is supposed to tell the truth about what happened, and it nearly shipped with a lie. We changed the outcome model so an unconfirmed result stays unconfirmed, including on replay. Bander now tells the parent to check instead of turning missing evidence into a confident answer. Accomplishments that I am proud of The Google, Gmail, and Telegram behavior shown in the film is real. The Calendar changes against a dedicated Google account. Gmail places the approved reply in Sent. A second phone shows the exact family update Maya approved. The changed world refusal also runs against real Calendar state. Bander moves nothing and sends no family message. The published product matrix contains 535 functional cases plus 26 adversarial cases. The evidence ledger records the critical properties we observed failing before their fixes. It also records deliberate mutations that prove the corresponding regression tests can fail. There is also a hosted browser experience that runs the shared authority engine against explicitly seeded data. It lets a judge experience all 27 deterministic outcomes, including decline, replay, changed world refusal, and truthful uncertainty, without trusting Bander with an account. What I learned The thing I did not expect is that truthfulness decides which features you are allowed to build. Calendar and Gmail made the cut because their APIs let Bander pin identity and inspect what actually happened. Restaurant reservations, smart home control, calling the clinic, and several other ideas did not. I wanted all of them, but I cut them because I could not make their recovery stories honest. Saying no to features became part of the design. I also learned that writing for my mom is harder than writing code. A technical precondition failure became a plain sentence explaining that her Calendar had changed since she asked, so Bander moved nothing and sent nothing. That rewrite required as much care as the logic underneath it. What is next for Bander Today Bander is a product that a technical family member sets up once for someone they love. Setup takes about 45 minutes, is reversible, and runs through an isolated OpenClaw profile without modifying an existing installation. Next is reducing that setup friction without weakening the boundary. That means guided onboarding, hosted setup, durable authority for actions already in progress, and additional domains only when their APIs permit honest recovery. Next I want to put Bander in front of a parent, stay quiet, and watch where they hesitate. If they misunderstand who can act, what approval means, or what the family member sees, I will treat that as a problem with Bander rather than a problem with the person using it.

## README (from the GitHub repository)

<p align="center">
  <img src="docs/assets/bander-mark.svg" width="140" alt="Bander logo: a red claw protected by a teal band">
</p>

# Bander

**The OpenClaw I’d actually give my parents.**

Your assistant can read your calendar and mail and talk like a person. Bander holds the keys—calendar changes, email replies, and family messages happen only as exact deals you approve, and Bander reports only what it can prove.

### [▶ Try Bander in your browser — no accounts, nothing real can happen](https://gowtham0992.github.io/bander/)

The browser is a deterministic, seeded product experience. It cannot contact Google, Gmail, Telegram, OpenAI, OpenClaw, or your accounts.

## Demo

<p align="center">
  <a href="https://www.youtube.com/watch?v=z7OrvquejvQ">
    <img src="https://img.youtube.com/vi/z7OrvquejvQ/hqdefault.jpg" alt="Watch the Bander product demo" width="640" />
  </a>
</p>

- Watch: https://www.youtube.com/watch?v=z7OrvquejvQ
- Try: https://gowtham0992.github.io/bander/
- Source: https://github.com/gowtham0992/bander

## Judge quickstart

```bash
npm ci && npm run demo
# Open http://127.0.0.1:4310 — 27 deterministic outcomes

npm run verify:demo
# Verifies all 27 outcomes without accounts or credentials
```

The supported Node floor is 22.12.0; CI and the repository-pinned runtime use Node 24. In the clean-clone verifier, both measured warm-cache runs completed in 13 seconds on the development machine. Package and network download speed are the main variables, so this is measured evidence rather than a fixed-time promise. Expected output ends with `27 of 27 demo outcomes passed`. No shared judge account is provided because shared credentials would contradict Bander’s trust model.

## For Build Week judges

**Category:** Apps for Your Life

- [Hosted Pages sandbox](https://gowtham0992.github.io/bander/)
- [Three evaluator paths](#evaluator-paths)
- [Real installation and setup](SETUP.md)

The required `/feedback` Codex Session ID is supplied through Devpost.

## The 30-second story

1. **Mum asks what is coming up tomorrow.** OpenClaw answers conversationally. No Card and no approval toll.
2. **She asks to reply to an email.** Bander shows the recipient and exact email reply before anything is sent.
3. **She approves once.** Bander sends only those stored bytes.
4. **She asks to add the appointment and tell a connected family member.** One Card shows the Calendar change and the exact sentence Bander may send them.
5. **After approval, Bander changes the Calendar first, then sends that family member precisely the sentence Mum approved. If the Calendar or email changes before approval, Bander stops.**

## Real product, fictional data

The browser experience uses seeded data and cannot contact real services. Bander’s real Telegram, Google Calendar, Gmail, OpenClaw, and GPT‑5.6 integration using fictional test data was exercised end to end. The evidence ledger records the corresponding live runs and failure-first verification.

## Why not just native approvals?

OpenClaw’s approvals are useful, and Bander does not replace them. They gate what a credential-holding process may do. Bander moves the credentials themselves—Calendar, Gmail, and its Telegram identity—outside the reasoning agent.

Every approval binds to rechecked world state, such as a Calendar ETag or the newest message in an email thread. Bander executes the stored bytes and reports only observed results from an identity the model cannot speak through.

When Gmail’s response to a send was lost, Bander reported the result as unconfirmed and provably did not send again. That behavior—not the approval button—is the product.

This boundary applies to the dedicated Bander-protected OpenClaw profile. It does not protect a machine already compromised at the operating-system or user-account level, and it does not restrict the owner’s other agents or applications.

## Two identities, one clear boundary

OpenClaw is the conversational assistant. It can answer bounded schedule and inbox questions and ask Bander to prepare a deal. Bander is the separate guardian identity: it holds the Google and Telegram credentials, shows the exact human approval surface, performs the stored action, and reports the observed outcome. OpenClaw cannot speak through Bander.

```mermaid
flowchart LR
    P["Parent in Telegram"] --> O["OpenClaw<br/>conversation"]
    O -->|"5 bounded tools"| B["Bander<br/>keys + exact deal"]
    B -->|"minimal status"| O
    B -->|"Card + outcome"| P
    B -->|"conditional action"| G["Google Calendar / Gmail"]
    B -->|"exact approved update"| F["One paired family member"]
```

## What a parent can do

- Ask what is on the calendar without approving a read.
- Read one matching email without approving a read.
- Add, move, or remove one narrowly eligible Calendar event.
- Approve one exact plain-text reply to a resolved email thread.
- Approve an exact family update to one consented family member.
- Say **Not now** or receive a truthful stop when the world changed.
- See an unconfirmed result described honestly, without a blind repeat.

<details>
<summary><strong>Full implemented boundary and qualifiers</strong></summary>

The real product currently supports ordinary OpenClaw conversation; bounded primary-Calendar reads of at most 31 days and 50 sanitized events; bounded Gmail inbox reads; one timed default Calendar creation with a disclosed 60-minute default or explicit 15-minute-to-12-hour duration; one exact eligible-event reschedule or cancellation under its ETag; one exact plain-text Gmail reply; and one deterministic Telegram family update bound to the single active consented contact.

Writable Calendar events must be on `primary`, timed, non-recurring, `default` type, owner-organized, attendee-free, and exactly resolved. Creation adds no attendees, recurrence, location, description, conferencing, attachments, custom reminders, or reservation. Gmail excludes spam/trash and never adds recipients, reply-all, forwarding, attachments, or arbitrary outbound threads. Bander does not make reservations, purchases, medical decisions, transportation changes, or smart-home changes. Standing autonomy is demonstrated only in the deterministic sandbox.

The real protected OpenClaw profile exposes exactly five tools:

- `bander__list_capabilities`
- `bander__read_schedule`
- `bander__read_inbox`
- `bander__propose_action`
- `bander__get_receipt`

`gpt-5.6-sol` may extract bounded language hints. Deterministic Bander code chooses identities, versions, final intervals, recipients, routing, rendered messages, MIME, execution parameters, authority, and outcomes.

</details>

## How Codex and GPT‑5.6 Sol were used

**Codex was the primary implementation and verification partner.** The build proceeded in bounded slices: observe the load-bearing behavior fail, implement the narrow fix, then deliberately mutate critical guards to prove the regression tests could catch the real defect. Codex accelerated the authority engine, Google and Telegram integrations, browser sandbox, repository-local setup flow, tests, and documentation. The [evidence ledger](BUILD_WITH_CODEX.md) names the properties actually observed red; it does not claim every static test failed first.

**The human chose the product boundary.** Credentials and outcomes remain outside the reasoning agent. Reads are toll-free; consequential effects become exact approved deals. OpenClaw and Bander are visibly separate Telegram speakers. Eligibility stays narrow. Standing authority remains sandbox-only. Bander refuses to fake reservations, smart-home actions, or scam detection. Every public capability claim was reviewed against observed behavior.

**Iteration changed the product.** Live work showed that Gmail rewrote the caller-supplied `Message-ID`; the first compound approval exposed a state-lock deadlock; and an ambiguous Calendar execution was initially about to be described as “nothing changed.” The setup path and public sandbox were repeatedly

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 162 recognized source files, 1717 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 181)

```
.env.example
.github/workflows/pages.yml
.gitignore
apps/broker/package.json
apps/broker/src/app.test.ts
apps/broker/src/app.ts
apps/broker/src/calendar-cancel.test.ts
apps/broker/src/calendar-create.test.ts
apps/broker/src/checkpoint-6a.test.ts
apps/broker/src/compiler.test.ts
apps/broker/src/compiler.ts
apps/broker/src/compound-action.test.ts
apps/broker/src/compound-action.ts
apps/broker/src/compound-intent.test.ts
apps/broker/src/compound-intent.ts
apps/broker/src/direct-family.test.ts
apps/broker/src/family-contact-spike.test.ts
apps/broker/src/family-contact-spike.ts
apps/broker/src/family-contact.test.ts
apps/broker/src/family-contact.ts
apps/broker/src/family-notification.test.ts
apps/broker/src/family-notification.ts
apps/broker/src/fixtures.ts
apps/broker/src/gmail-read.test.ts
apps/broker/src/gmail-read.ts
apps/broker/src/gmail-reply.test.ts
apps/broker/src/gmail.ts
apps/broker/src/google-calendar.test.ts
apps/broker/src/google-calendar.ts
apps/broker/src/google-gmail-oauth.ts
apps/broker/src/google-gmail.test.ts
apps/broker/src/google-gmail.ts
apps/broker/src/google-oauth.test.ts
apps/broker/src/google-oauth.ts
apps/broker/src/google-schedule-read.test.ts
apps/broker/src/mcp.ts
apps/broker/src/mock-client.ts
apps/broker/src/product-compiler.test.ts
apps/broker/src/product-compiler.ts
apps/broker/src/read-schedule.test.ts
apps/broker/src/read-schedule.ts
apps/broker/src/real-calendar-compiler.test.ts
apps/broker/src/runtime-config.test.ts
apps/broker/src/runtime-config.ts
apps/broker/src/server.ts
apps/broker/src/telegram-service.test.ts
apps/broker/src/telegram-service.ts
apps/mock-services/package.json
apps/mock-services/src/app.test.ts
apps/mock-services/src/app.ts
apps/mock-services/src/fixtures.ts
apps/mock-services/src/server.ts
apps/web/index.html
apps/web/package.json
apps/web/src/App.tsx
apps/web/src/approval-recovery.test.ts
apps/web/src/backend/browser-parity.test.ts
apps/web/src/backend/browser.ts
apps/web/src/backend/http.ts
apps/web/src/backend/index.ts
apps/web/src/backend/types.ts
apps/web/src/checkpoint-9-red.test.ts
apps/web/src/family-thread-glyphs.tsx
apps/web/src/family-thread-presentation.test.ts
apps/web/src/family-thread-r2.test.ts
apps/web/src/family-thread-r3-r4.test.ts
apps/web/src/family-thread-r5-r6.test.ts
apps/web/src/family-thread-state.test.ts
apps/web/src/family-thread-state.ts
apps/web/src/family-thread-surface-view.tsx
apps/web/src/family-thread-surfaces.ts
apps/web/src/main.tsx
apps/web/src/sandbox-microcopy.test.ts
apps/web/src/styles.css
apps/web/src/vite-env.d.ts
apps/web/tsconfig.json
apps/web/vite.config.ts
attack/authority.test.ts
attack/gmail-and-family.test.ts
attack/rendering.test.tsx
BUILD_WITH_CODEX.md
docs/architecture.md
docs/assets/screenshots/manifest.json
docs/parent-test.md
docs/recording-plan.md
docs/submission-checklist.md
docs/telegram-privacy-spike.md
fixtures/v1/calendar.json
fixtures/v1/drafts.json
fixtures/v1/people.json
LICENSE
openclaw/real-product.openclaw.json
openclaw/reference.openclaw.json
package.json
packages/contracts/package.json
packages/contracts/src/index.ts
packages/core/package.json
packages/core/src/authority.test.ts
packages/core/src/authority.ts
packages/core/src/canonical.ts
packages/core/src/card.ts
packages/core/src/checkpoint12-copy.test.ts
packages/core/src/index.ts
packages/core/src/lock.ts
packages/core/src/platform-browser.ts
packages/core/src/platform-node.ts
packages/core/src/platform-types.ts
packages/core/src/platform.test.ts
packages/core/src/store.ts
packages/demo-sandbox/package.json
packages/demo-sandbox/src/fixtures.ts
packages/demo-sandbox/src/index.ts
packages/demo-sandbox/src/runtime.ts
README.md
scripts/authorize-calendar.ts
scripts/authorize-gmail.ts
scripts/build-pages.ts
scripts/checkpoint10-docs.test.ts
scripts/checkpoint11-judge-surface.test.ts
scripts/checkpoint12-presentation.test.ts
[61 more files omitted for size]
```

### Dependencies

- apps/broker/package.json: @bander/contracts@*, @bander/core@*, @bander/demo-sandbox@*, @fastify/static@10.1.0, @modelcontextprotocol/sdk@1.29.0, fastify@5.10.0, googleapis@^173.0.0, openai@^6.46.0, zod@4.3.6
- apps/mock-services/package.json: @bander/contracts@*, fastify@5.10.0
- apps/web/package.json: @bander/contracts@*, @bander/core@*, @bander/demo-sandbox@*, @types/react@19.2.17, @types/react-dom@19.2.3, @vitejs/plugin-react@6.0.3, react@19.2.4, react-dom@19.2.4, vite@8.1.4
- package.json: @types/node@26.1.1, axe-core@^4.10.3, node@24.15.0, openclaw@2026.7.1, tsx@4.23.1, typescript@7.0.2, vitest@4.1.10
- packages/core/package.json: @bander/contracts@*, @noble/hashes@2.2.0
- packages/demo-sandbox/package.json: @bander/contracts@*, @bander/core@*

### Recent commits (newest first)

- Synchronize final submission documents
- Record final submission verification
- Retire internal build plan
- Polish README demo presentation
- Finalize submission safety checks
- Fix compound proposals and refresh real evidence
- Show Telegram GIF once, in the evidence section
- Rename Telegram GIF to bust image cache
- Use full-thread captures for the Telegram flow GIF
- Add product GIFs, gallery-ratio variants, and README media
- GPT‑5.6 Sol Implementation record
- Add full-thread story captures and manifest entries
- Add story-column screenshot crops with privacy manifest entries
- Finish the Family Thread product surface
- feat(pages): add proof drawer and evaluator journey
- Add Cross Return Hold Pages journey
- Redesign Pages around the Family Thread
- Polish final judge surfaces
- fix: finalize Pages judge checks
- Update LICENSE

## Key source files (fetched from GitHub, selected and truncated for size)

### SETUP.md

```markdown
# Set up Bander for a parent or family member

This guide is for the person setting up Bander on a computer for a parent or family member. When setup is complete, the parent can ask OpenClaw about their real Google Calendar and bounded Gmail inbox, approve exact Calendar changes or one exact Gmail reply, and optionally approve one exact message to a connected family member.

## Keep the three participants straight

| Participant | What they do |
| --- | --- |
| **Setup computer** | Holds the Bander bot token, Google OAuth files, local state, and starts Bander/OpenClaw. |
| **Parent/owner phone** | Talks to OpenClaw in the protected group and approves or declines Bander Cards. |
| **Family-contact phone** | Privately accepts an invitation and can receive only an exact update the parent approved. It stays outside the protected group. |

## What becomes real

- The parent can ask what is coming up on their connected primary Calendar.
- The parent may approve a real move of one narrowly eligible Calendar event.
- The parent may approve one timed Calendar event after seeing its exact title and complete interval; Bander uses a disclosed 60-minute default unless the parent states a duration.
- One connected family member may receive only the deterministic appointment update shown on the same approval Card.
- The parent can read one bounded matching Gmail message and approve one exact plain-text reply in its existing thread.
- The parent can approve one exact plain-text message to the connected family member.

Bander does not provide new outbound email threads, reply-all, forwarding, attachments, arbitrary recipients, purchases, reservations, payments, smart-home control, or general Calendar editing.

## Fast judge sandbox: no accounts or keys

```bash
git clone https://github.com/gowtham0992/bander.git
cd bander
npm ci
npm run demo
```

Open <http://127.0.0.1:4310>. This is a deterministic, seeded sandbox. It does not connect to Google, Telegram, or OpenAI and must not be presented as evidence of a live account mutation. It exercises the same Card, approval, outcome, and replay rules as the real product, including secondary add and remove journeys.

On the development machine, both completed clean-clone runs took 13 seconds with a warm npm cache (observed range: 13–13 seconds). A cold network/package download can take materially longer; Bander does not promise a fixed five-minute install time.

## Real setup

`npm run setup` is a repository-local setup guide and verifier, not an installer. It never reads or modifies `~/.openclaw` or an existing OpenClaw. It creates an ignored 0600 `.env` template when needed, asks you to edit it in a local editor, and records only versioned milestones, configuration digests, and names of template keys it created. It never collects, prints, or stores secret values and never overwrites a differing existing value.

### 1. Prepare the setup computer

Current verified environment:

- macOS on Apple Silicon;
- Node.js 22.12 o
[truncated — 13271 more characters]
```

### docs/parent-test.md

```markdown
# Parent comprehension test

Status: **planned, not yet performed**.

Use the real product with fictional Calendar data and the invited family contact. Stage one eligible event to move, one to remove, and leave space for one created event. Do not teach internal vocabulary or provide a magic sentence. Ask the participant to think aloud. The moderator may restate the task, but must not supply wording, identify which bot should respond, or explain a Card during the attempt.

## Tasks

1. Say hello, then ask what is on the Calendar tomorrow. Explain why no Bander Card appeared.
2. Ask what Ruth said about lunch. Explain why the bounded inbox answer had no Card, then prepare an exact reply and identify its recipient, subject, and full text before approving.
3. Ask to add lunch with a named person on a supplied day and time. Before approving, identify the title, complete interval, and what is explicitly not included. Approve and verify the new Calendar event.
4. Ask to book a restaurant table. Explain Bander's limitation, then—without coaching—ask only to add the dinner to the Calendar.
5. Ask to move one eligible appointment and let Gil know. Before approving, explain both effects, the complete before/after interval, and the exact text Gil would receive.
6. Approve the compound move. Explain separately how they know the Calendar changed, Telegram accepted the update, and why that does not prove Gil read it.
7. Prepare another request and choose **Not now**. Explain whether anything happened and whether the old Card can still be used.
8. Ask to cancel a fictional dentist appointment. Explain whether approval removes only the Calendar event or also contacts the clinic. Use **Change it**, return to the same deal, then approve the removal.
9. Prepare a second removal Card, change the event outside Bander, then approve. Explain why Bander stopped and whether anyone was contacted.
10. Ask for an unsupported grocery order. Identify the safe next step without being told a magic sentence.
11. Send one exact independent message to Gil, then disconnect Gil. Explain what Bander can and cannot do afterward.

## Success criteria

- The participant distinguishes OpenClaw conversation from Bander approval and outcome messages.
- They understand schedule reading needs no approval because it changes nothing.
- They understand bounded email reading discloses sanitized email facts to the assistant, while an email reply requires an exact Card and cannot add recipients, reply-all, forward, or attach files.
- They distinguish a deterministic Calendar update from an independent family message derived from their own request and shown exactly before approval.
- They understand a create Card discloses the default or requested duration and does not imply an invitation, recurrence, or reservation.
- They identify both effects and the complete before/after time before approving.
- They understand **Do exactly this** applies once and **Not now** changes nothing.
- They understand *
[truncated — 1116 more characters]
```

### package.json

```
{
  "name": "bander",
  "version": "0.1.0",
  "private": true,
  "license": "MIT",
  "type": "module",
  "engines": {
    "node": ">=22.12.0"
  },
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "build": "npm run build --workspaces --if-present",
    "check": "npm run typecheck && npm test",
    "test": "vitest run",
    "test:watch": "vitest",
    "typecheck": "tsc --noEmit",
    "attack": "vitest run --config vitest.attack.config.ts",
    "dev": "tsx scripts/dev.ts",
    "doctor": "node --import tsx scripts/doctor.ts",
    "setup": "node --import tsx scripts/setup.ts",
    "reset:pairing": "node --import tsx scripts/reset-pairing.ts",
    "reauthorize:google": "node --import tsx scripts/reauthorize-google.ts",
    "uninstall:local": "node --import tsx scripts/uninstall-local.ts",
    "oauth:gmail": "tsx scripts/authorize-gmail.ts",
    "demo": "npm run build && tsx scripts/demo.ts",
    "hero": "npm run build && tsx scripts/hero.ts",
    "pair:real": "BANDER_RUNTIME_MODE=real node --env-file=.env --import tsx apps/broker/src/server.ts",
    "pair:family": "tsx scripts/pair-family.ts",
    "revoke:family": "tsx scripts/revoke-family.ts",
    "real": "tsx scripts/real.ts",
    "openclaw": "./node_modules/node/bin/node scripts/openclaw.mjs",
    "verify:demo": "tsx scripts/verify-demo.ts",
    "build:pages": "node --import tsx scripts/build-pages.ts",
    "verify:pages": "npm run build:pages && npm run verify:pages:artifact && npm run verify:pages:parity",
    "verify:pages:artifact": "node --import tsx scripts/verify-pages.ts",
    "verify:pages:parity": "vitest run apps/web/src/backend/browser-parity.test.ts",
    "verify:pages:browser": "node --import tsx scripts/verify-pages-browser.ts",
    "verify:recovery": "tsx scripts/verify-http-recovery.ts",
    "verify:standing-recovery": "tsx scripts/verify-standing-recovery.ts",
    "verify:google-calendar": "tsx scripts/verify-google-calendar.ts",
    "verify:gpt-sol": "tsx scripts/verify-gpt-sol.ts",
    "verify:compound-sol": "tsx scripts/verify-compound-sol.ts",
    "verify:create-sol": "tsx scripts/verify-create-sol.ts",
    "verify:create-live": "tsx scripts/verify-create-live.ts",
    "verify:cancel-sol": "tsx scripts/verify-cancel-sol.ts",
    "verify:cancel-live": "tsx scripts/verify-cancel-live.ts",
    "verify:read-sol": "tsx scripts/verify-read-sol.ts",
    "verify:gmail-sol": "tsx scripts/verify-gmail-sol.ts",
    "verify:family-notification": "tsx scripts/verify-family-notification.ts",
    "verify:clean-clone": "node --import tsx scripts/verify-clean-clone.ts",
    "spike:family-contact": "tsx scripts/spike-family-contact.ts",
    "verify:openclaw": "npm run build && tsx scripts/verify-openclaw.ts",
    "verify:telegram-privacy": "tsx scripts/verify-telegram-service.ts",
    "verify:telegram-conflict": "BANDER_TELEGRAM_VERIFY_SCENARIO=conflict tsx scripts/verify-telegram-service.ts",
    "verify:telegram-standing": "BANDER_TELEGRAM_VERIFY_SCENARIO=standing tsx scripts/verify-telegram-service.ts"
  },
  "devDependencies": {
    "@types/node": "26.1.1",
    "axe-core": "^4.10.3",
    "node": "24.15.0",
    "openclaw": "2026.7.1",
    "tsx": "4.23.1",
    "typescript": "7.0.2",
    "vitest": "4.1.10"
  }
}

```

### packages/contracts/package.json

```
{
  "name": "@bander/contracts",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "exports": "./src/index.ts"
}

```

### packages/demo-sandbox/package.json

```
{
  "name": "@bander/demo-sandbox",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "exports": "./src/index.ts",
  "dependencies": {
    "@bander/contracts": "*",
    "@bander/core": "*"
  }
}

```

### apps/mock-services/package.json

```
{
  "name": "@bander/mock-services",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "start": "tsx src/server.ts",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@bander/contracts": "*",
    "fastify": "5.10.0"
  }
}

```

### packages/core/package.json

```
{
  "name": "@bander/core",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "imports": {
    "#bander/platform": {
      "browser": "./src/platform-browser.ts",
      "default": "./src/platform-node.ts"
    }
  },
  "exports": "./src/index.ts",
  "dependencies": {
    "@bander/contracts": "*",
    "@noble/hashes": "2.2.0"
  }
}

```

### apps/broker/package.json

```
{
  "name": "@bander/broker",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "start": "tsx src/server.ts",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@bander/contracts": "*",
    "@bander/core": "*",
    "@bander/demo-sandbox": "*",
    "@fastify/static": "10.1.0",
    "@modelcontextprotocol/sdk": "1.29.0",
    "fastify": "5.10.0",
    "googleapis": "^173.0.0",
    "openai": "^6.46.0",
    "zod": "4.3.6"
  }
}

```

### apps/web/package.json

```
{
  "name": "@bander/web",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite --host 127.0.0.1 --port 4312",
    "build": "vite build",
    "build:pages": "BANDER_PAGES_BUILD=1 VITE_BANDER_BACKEND=browser vite build",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@bander/contracts": "*",
    "@bander/core": "*",
    "@bander/demo-sandbox": "*",
    "react": "19.2.4",
    "react-dom": "19.2.4"
  },
  "devDependencies": {
    "@types/react": "19.2.17",
    "@types/react-dom": "19.2.3",
    "@vitejs/plugin-react": "6.0.3",
    "vite": "8.1.4"
  }
}

```

### packages/demo-sandbox/src/index.ts

```typescript
export * from "./fixtures.js";
export * from "./runtime.js";

```

[152 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]