oa-chatA ChatGPT-like AI chat app that implements unlinkable inference — AI inference where every request is verifiably decoupled from each other, and from your identity. Built by The Open Anonymity Project.
Everything runs in the browser with no server backend. Each session uses a fresh ephemeral access key obtained via blind signatures, so no party — including the OA system and the inference provider — can link your identity to your inference activity or link sessions to each other.
.docx), and audio attachments.bash
npm installbash
npm run dev
# visit http://localhost:8080
npm run dev now initializes the nanomem submodule first, so a clone
without --recurse-submodules fails fast instead of serving a browser-side
GET /nanomem/browser.js 404.Production build + preview:
npm run build
npm run preview
# visit http://localhost:8080
index.html bootstraps Tailwind, Marked, KaTeX, then loads ES modules.app.js coordinates state, components, streaming, and CRUD through chatDB.services/inference/ selects the inference backend; api.js handles OpenRouter calls (fetch models, stream completions).db.js provides an IndexedDB wrapper for sessions/messages/settings (exported as chatDB).components/ contain UI pieces (sidebar, chat area, input, model picker, right panel, templates, message navigation).services/ provide logging, key storage, file utilities, ticket/key flows, provider icons, and theme management.local_inference/, embeddings/, and vector/ are standalone modules for local/auxiliary inference and memory search (in development).chat/vendor/privacypass-ts/privacypass-ts.min.js provides blind signature operations via @cloudflare/privacypass-ts (open-source, Apache-2.0).For a deeper breakdown, see AGENTS.md.
Unlinkable inference: No party — including the OA system and the inference provider — can link a user's identity to their inference activity. Blind signatures ensure the station cannot correlate ticket issuance (blind signing) to ticket redemption (ephemeral API key request). The ephemeral API key carries no user identity — the model provider sees anonymous inference from an ephemeral key with no way to identify the user behind it. Each session uses a different ephemeral key, so sessions cannot be linked to each other.
This is much stronger than pseudonymity — there is no stable alias on your data. The adversary observing requests cannot tell if 100 requests came from 100 people with 1 request each, or 1 person with 100 requests, or anything in between.
What OA does NOT claim: OA does not claim that prompts are hidden from the inference provider. Prompts must reach the model for inference to work. The claim is that prompts are unlinkable to your identity and to each other — the provider sees anonymous requests from ephemeral keys with no way to know who sent them or link them across sessions.
Zero trust on OA infrastructure: Users need not trust any OA-operated component (org, stations, verifier operators). The verifier runs in a hardware-attested enclave (AMD SEV-SNP) with open-source auditable code. Station compliance (privacy toggles, key ownership) is enforced using the provider's own APIs as evidence. Even a compromised OA operator cannot deanonymize users because no OA component possesses user identity in the first place.
For the detailed privacy model, see docs/PRIVACY_MODEL.md and the blog post Unlinkable Inference as a User Privacy Architecture.
chat/ and can be served directly in dev; production builds bundle and minify output into dist/.DEBUG flag in chat/config.js).This project is licensed under the MIT License.
$ claude mcp add oa-chat \
-- python -m otcore.mcp_server <graph>