# Gift Graph Technical Specification
> The shape of Gift Graph as it runs, from v0.1 as Replit Agent built it on 2026-10-01 through v0.6.2, published 2026-10-07 at giftgraph.aleksandar.app. The canonical spec is `docs/spec.md` in the repo. The concept and the full design space live in [[Concept - Gift Graph - Consent-Gated Context Between Agents]]; the reasons behind each choice live in [[Project - Gift Graph/Build & Iterate/Technical Decisions|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 each secret as written, with its hint and labels, Silent secrets included. Owners trust its API and database with those details. A person who hears receives only what the stricter of the secret's level and the connection's level allows. The database holds a keyed hash of each verified sign-in email and no address.
**The idea:** Two people's agents share gift-relevant preferences through a shared MCP server. Each person controls what their agent may whisper and how much the other side hears. 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 |
## Levels
| Level | A person who hears it receives |
| --- | --- |
| Secret | The secret as written ("wants a license for Söhne") |
| Hint | A line on the feeling, the origin, and the occasion, with up to two labels from sixty-three kinds ("typefaces") |
| Silent | Nothing |
A secret carries a level, and a connection carries a level, the most that person hears. What travels is the stricter of the two. The server checks the hint line against the secret for its distinctive words and for numbers before anyone hears it, and a widening previews and waits for the owner's yes. The four tiers of v0.1, verbatim, category, vibe, and silent, mapped onto these on 2026-10-03, with category and vibe becoming the hint ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-021|Technical Decisions > TDR-021]]).
## Tools
| Group | Tool | Who calls it | What it does |
| --- | --- | --- | --- |
| Secrets | `whisper` | owner | Saves a secret at a level, with a hint and labels, after a preview |
| Secrets | `list_secrets` · `update_secret` · `hush_secret` | owner | Reviews, edits, hushes, and restores secrets |
| Hearing | `hear` | requester | Returns everything the person may hear from one owner, ranked by an optional question |
| Connections | `request_connection` | requester | Asks to hear an owner, by account ID or by email |
| Connections | `approve_connection` · `set_level` · `decline_connection` · `pause_connection` · `resume_connection` · `remove_connection` | owner; either side removes | The connection lifecycle |
| Connections | `list_connections` | either | Shows where each connection stands |
| Invites | `create_invite` · `list_invites` · `revoke_invite` · `accept_invite` | owner, then the invitee | Single-use links at a level |
| Guidance | `help` | any | The flows and the consent rules, with three prompts for the same flows |
The seven tools of v0.1 were `request_connection`, `approve_connection`, `revoke_connection`, `set_default_tier`, `list_connections`, `drop`, and `pull`, renamed on 2026-10-07 ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-035|Technical Decisions > TDR-035]]).
## The privacy filter
The server checks for an approved connection before anything else. One function projects each secret to what this person may hear, and ranking reads only that projection, which means a question naming a hidden word surfaces nothing hidden. Silent and hushed secrets stay in the database on a read. A removed or paused connection returns an empty list at once.
## Tests
85 API tests, 26 web tests, and 21 routing tests on 2026-10-07, run against isolated schemas on a local Docker Postgres. A judge drives real agents through seven scenarios and scores the transcripts, and a daily synthetic check lists the published server's tools. The four promises of the brief hold among them: one user cannot act as the other, a Silent secret returns nothing, a removed connection returns nothing at once, and hearing before approval fails.
## Deferred from v0.1
The anti-inference batcher (48-hour delay, three-secret minimum, jitter), PSI-based tombstones for hushing and purchases, notifications, enterprise SSO, and embeddings stay deferred. The owner review screen, registration, OAuth for MCP clients, and ranked hearing have shipped since. Each open item is prioritized in [[Project - Gift Graph/Build & Iterate/Feature Backlog|Feature Backlog]].
## Owner controls · v0.2, as built then
| 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 ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-016\|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 · 2026-10-02
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 ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-017\|Technical Decisions > TDR-017]]). |
| Demo | `/demo`, two synthetic people, Theo and Mira, three whispers with editable tiers, four prompts, a reset. Touches no account ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-018\|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 ([[Project - Gift Graph/Build & Iterate/Technical Decisions#TDR-020\|Technical Decisions > TDR-020]]). |
## Since v0.2 · through v0.6.2
| Release | What it added |
| --- | --- |
| v0.3 and v0.4 · 2026-10-03 | Three levels with labels, ranked hearing, the connection lifecycle, invites, and a server that migrates itself at start |
| v0.5 · 2026-10-05 | Vocabulary version 2, the web app from the design handoff, and Secret as the noun |
| v0.6 · 2026-10-05 | OAuth with Gift Graph as its own authorization server, Your agents, Hush and the Silent drawer, a new link for a lost one, and the agent's guidance in `next` |
| v0.6.1 · with v0.6.2 | The nudge to connect, API keys for apps like Muse, the account line at connect, one direction per connection card, and the page for agents |
| v0.6.2 · 2026-10-07 | The seeded identities retired, one vocabulary in plain technical English, `help` and three prompts, requests by email, removal closing named links, Teal ember, and two indexes from the audit |
## Clients
Any MCP client over Streamable HTTP, at `https://gift-graph.replit.app/mcp`. The custom domain joins it once [[Project - Gift Graph/Build & Iterate/Bug Tracker#BUG-023|Bug Tracker > BUG-023]] is fixed, since a sign-in there reaches a second, empty account. A client that supports sign-in adds the URL and signs in through the consent page; Claude Code does it with `claude mcp add --transport http gift-graph <url>`. An app that asks for an API key, like Muse, takes a token of its own from Your agents. Each person's agent holds only its own credential. The setup guide lives in `docs/mcp-client.md` in the repo.