# Gift Graph Technical Specification (v0.1)
> The shape of what Replit Agent built from the brief, as deployed at gift-graph.replit.app on 2026-10-01. 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]].
**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]].
## 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.