# Gift Graph Technical Specification > The shape of what Replit Agent built from the brief: v0.1 as deployed at gift-graph.replit.app on 2026-10-01, the v0.2 owner controls merged to main the same day, and what the development preview has added since. The concept and the full design space live in [[Concept - Gift Graph - Consent-Gated Context Between Agents]]; the reasons behind each choice live in [[Gift Graph Technical Decisions]]. ![[gift-graph-architecture-v01.png]] *The v0.1 map · each outlined group marks a separate trust boundary · the landing page is its own web artifact, and a shared proxy routes `/mcp` and `/health` to the API* **Trust:** The server receives and stores original preferences, category, vibe, and silent drops included. Owners trust its API and database with those details. The requester receives only the text its tier permits. **The idea:** Two people's agents share gift-relevant preferences through a shared MCP server. Each person controls what their agent may drop and how much detail the other side may see. The receiving agent learns only what it was given, which is enough to choose a good gift. **Parties:** An owner, whose preferences are shared. A requester, whose agent asks for gift ideas. The Gift Graph server between the two agents. ## Runtime | Layer | v0.1 | | --- | --- | | Server | TypeScript on Node, official MCP SDK, running in the app's Replit container | | Transport | One `/mcp` endpoint speaking MCP over Streamable HTTP; a fresh transport per request, session IDs disabled | | Storage | Replit PostgreSQL; all durable state lives here | | Identity | `Authorization: Bearer <token>` on every request; the server maps the token to a seeded user and takes identity only from that match | | Secrets | `ALEKS_BEARER_TOKEN` and the second user's token in Replit Secrets, read at runtime | | Deployment | Autoscale, build `npm run build`, run `npm start`, North America, 2 vCPU and 4 GiB | | Health | `GET /health` returns `{"status":"ok"}`; `GET /` names the endpoint, the health check, and bearer auth | ## Data model | Table | Holds | | --- | --- | | `users` | The two seeded people | | `connections` | requester, owner, status (pending · approved · revoked), default disclosure tier | | `drops` | owner, requester (v0.1 scopes a drop to one connection), verbatim text, owner-written category text, owner-written vibe text, tier, surprise-safe flag, timestamp | ## Disclosure tiers | Tier | The requester sees | | --- | --- | | Verbatim | The preference as written ("wants a license for Söhne") | | Category | Owner-written text naming the class of thing ("type and lettering") | | Vibe | Owner-written text giving a soft signal ("into design tools lately") | | Silent | Nothing; the drop shapes nothing in v0.1 and is reserved for later use in ranking | A drop carries one tier, snapshotted from the connection's default when the drop is created, and stores only the text its tier can reveal. The server refuses `vibeText` on a category-tier drop. The surprise-safe flag marks a drop the owner is happy to be surprised by, and the requester's agent may act on it but never reveals it, even if asked directly. ## Tools | Group | Tool | Who calls it | What it does | | --- | --- | --- | --- | | Handshake | `request_connection` | requester | Asks an owner for a connection; status pending | | Handshake | `approve_connection` | owner | Approves with a default tier | | Handshake | `revoke_connection` | owner | Revokes; pulls return nothing at once | | Settings | `set_default_tier` | owner | Changes the default for a connection | | Visibility | `list_connections` | either | Shows where each connection stands | | Sharing | `drop` | owner | Files a preference with an optional tier override and surprise-safe flag | | Sharing | `pull` | requester | Sends a prompt, receives matching preferences shaped by tier | ## The privacy filter The server checks for an approved connection before anything else. For each drop it returns only the field the tier allows and excludes silent drops. The match runs against the permitted text only, as literal word matching in v0.1, which means a requester cannot surface verbatim text by guessing words and a prompt with no overlapping word returns nothing. The filter lives in the database query, which keeps withheld text from ever leaving storage. ## Tests Twelve integration tests, run at build, covering the four promises in the brief: one user cannot act as the other, a silent drop returns nothing, a revoked connection returns nothing immediately, and a pull before approval fails. Type checking, compilation, the health check, and preview verification ran alongside. ## Deferred from v0.1 The anti-inference batcher (48-hour delay, three-drop minimum, jitter), PSI-based tombstones for revocation and purchases, the owner review screen, notifications, registration, OAuth for MCP clients, enterprise SSO, and semantic matching. Each is prioritized in [[Gift Graph Feature Backlog]]. ## Owner controls · v0.2 | Area | What v0.2 does | | --- | --- | | Dashboard | `/owner`. The owner signs in with the existing credential, which the app exchanges for a six-hour HTTP-only session and clears from the input. Sign out removes the server session. The public landing page stays public. | | Sharing | A new owner-wide preference explicitly chooses all approved connections as its audience and a ceiling. Effective disclosure is the more restrictive of the ceiling and the connection limit. The owner writes every visible lower-tier text. The dashboard shows originals, disclosures, audiences, connection limits, and withdrawal state. | | Confirmation | A tier increase returns a five-minute preview, and an explicit second owner call applies it. Edits and legacy conversion also require confirmation; audience expansion uses a separate approval. Any change to owner state invalidates outstanding previews. Decreases apply immediately. Approval and reapproval cannot bypass widening checks. | | Transition | Existing requester-scoped drops keep their single audience and snapshot disclosure. Missing lower-tier text is flagged. The owner completes the text and confirms conversion before ceiling rules apply, and conversion preserves the audience. A separate approval enables sharing with all approved connections, future approvals included. | | Withdrawal | A withdrawn preference stays out of every future pull, reapproval included. The original stays with its owner. There is no restore, no pull history, and no activity indicator. Information already received cannot be retracted. | | Migration | `schema.sql` stays for fresh setup; `pnpm --filter @workspace/api-server migrate:dev` adds owner controls without deleting or merging records. Startup runs readiness checks only. Tests create isolated schemas with synthetic data and remove them afterward. | | Production | v0.2 does not publish or change production on its own. `docs/production-v02.md` holds the separate owner-reviewed application process. | | Review gates | Milestone review gates with an audit trail sit in `package.json` and `replit.md`, and read-only synthetic checks exercise the MCP surface without writing. A second model reviews each milestone against the approved requirements; tests stay the ground truth ([[Gift Graph Technical Decisions#TDR-016]]). | | Owner tools | `list_drops`, `update_drop`, and `withdraw_drop`, callable only by the owner's own credential, beside the seven agent tools. | ## Development preview · after v0.2 In the preview and not yet in production. | Area | What the preview does | | --- | --- | | Accounts | Each account has an ID (`gg_…`). The dashboard shows it, the endpoint, the transport, and the header line, and issues the account's MCP token on request ([[Gift Graph Technical Decisions#TDR-017]]). | | Demo | `/demo`, two synthetic people, Theo and Mira, three whispers with editable tiers, four prompts, a reset. Touches no account ([[Gift Graph Technical Decisions#TDR-018]]). | | Vocabulary | The page says whispers. Tier labels read word for word, the kind of thing, a hint, kept quiet. The tool schema keeps verbatim, category, vibe, silent. Open, pending Probe 1. | | Layout | Compact layouts as a standing rule, checked at 1280x800, 1440x900, and 390x844 ([[Gift Graph Technical Decisions#TDR-020]]). | ## Clients Any MCP client over Streamable HTTP. Claude Code connects with one command per identity, `claude mcp add --transport http --scope user <name> https://gift-graph.replit.app/mcp --header "Authorization: Bearer <token>"`, and in real use each person's own agent holds only its own token. The setup guide Agent wrote lives in `docs/mcp-client.md` in the repo.