git for your AI
preferences.
Cotext synthesizes a personal preference prompt from your reactions to AI responses, then exposes it everywhere — browser, terminal, MCP client, HTTP. One profile, every tool.
$ cotext status source: folder (~/.cotext) active: Coding · v12 · 42 signals $ cotext pull > CLAUDE.md $ cotext signal "be terser" --type dislike ✓ recorded · 2f4a-c901
Three surfaces, one profile
The browser extension is the only writer. Everything else reads from a folder it syncs to (or from cotext.io via API token).
Browser extension
Chrome / Chromium today. Captures reactions on Claude, ChatGPT, Gemini, Grok, Perplexity, Mistral, Copilot. Synthesizes via local Ollama.
CLI + MCP
cotext for terminals; cotext-mcp for any MCP client. Reads profiles, writes feedback signals, refreshes CLAUDE.md from the active prompt.
HTTP server
Tiny loopback server on :7337 — drop-in for Claude Code hooks or any tool that talks HTTP. Same data, different transport.
Your profile, in your shell
Read your active profile, list all profiles, drop feedback signals from the terminal. The signal you record from your shell flows back through the same interpretation pipeline as a browser reaction.
Source priority: --folder → COTEXT_FOLDER → saved config → COTEXT_API_TOKEN. Folder always wins.
# Install npm install -g cotext # One-time cotext init # Refresh CLAUDE.md from the active profile cotext pull > CLAUDE.md # Drop a feedback signal cotext signal "be terser" --type dislike
First-class for AI clients
cotext-mcp is a stdio MCP server. Wire it into Claude Desktop, Claude Code, or any compatible client and the assistant gets first-class access to your preferences — plus a record_signal tool to close the feedback loop from inside the assistant.
cotext://preferences/activecotext://profilescotext://profiles/{slug}get_preferenceslist_profilesrecord_signal# Claude Desktop config { "mcpServers": { "cotext": { "command": "cotext-mcp" } } } # Claude Code claude mcp add cotext cotext-mcp
Content-addressed publishing
Every published profile is a blob keyed by SHA-256 of its canonical JSON — same idea as a git object. The URL never changes meaning. Edit, publish again, get a new URL. The old one still works for everyone who already had it.
Account-scoped pushes (@user/slug) are mutable pointers — the latest hash plus an immutable @user/slug@hash for any pinned version. Version history rendered in the viewer.
The folder is the protocol
The extension syncs to a folder of your choice via Chrome's File System Access API. Every reader (CLI, MCP, server) speaks the same on-disk layout. No daemon, no socket, no IPC.
Folder protocol spec →# Folder layout <folder>/ active.txt # name of the active profile <slug>.json # full profile (entries, dimensions, metrics) <slug>.md # synthesized prompt as markdown <slug>.history.jsonl # per-profile version log signals.jsonl # flat signal log inbox/ # CLI / MCP drop signals here
Self-host the whole thing
Both the extension and the website are open source. Run the website on your own infrastructure if you want a private hub for your team — Postgres + Vercel Blob (or any S3-compatible store).
Try it locally — Load Unpacked
The extension is in Chrome Web Store review. Devs don't need to wait — clone, build, load.
# Clone + build git clone https://github.com/cotext-io/cotext cd cotext npm install npm run build # Load into Chrome # 1. Open chrome://extensions # 2. Toggle "Developer mode" (top right) # 3. Click "Load unpacked" # 4. Pick the dist/ folder
Need the local AI too. Install Ollama (ollama.com), run ollama pull qwen3.5:4b, leave it running. The extension picks it up on localhost:11434.
Use npm run watch while developing — esbuild rebuilds on save, then click the reload button on the extension card to pick up changes.
Connect a folder from the popup so the CLI / MCP / local server can read your profile from disk.
Ready to wire it up?
Install the extension to seed your profile. The CLI and MCP server read straight from the folder it syncs to.