Developer setup

For terminal-first users, MCP integrators, and anyone who wants Cotext profiles outside the browser. If you just want to react on AI sites and have your preferences applied, the non-developer guide is what you want.

This page covers:

  • Installing the cotext CLI and cotext-mcp MCP server
  • Two source modes: a local folder synced by the browser extension, or a direct API token against cotext.io
  • Pushing a profile from the terminal (no extension required)
  • Wiring MCP into Claude Code / Codex
  • Running the headless daemon for fully-CLI workflows

For the full command reference, see CLI & MCP.


1. Install the CLI

From npm (eventually)

npm install -g cotext

This installs two binaries: cotext (the CLI) and cotext-mcp (the stdio MCP server).

The npm package isn't published yet — use the from-source path below until it is. Watch the GitHub repo for the release tag.

From source

git clone https://github.com/cotext-io/cotext
cd cotext/packages/cli
npm install
npm run build
npm link

npm link makes the binaries available on your PATH from anywhere. Verify:

cotext --help
cotext-mcp --help

2. Pick a source

The CLI reads profiles from one of two places:

SourceWhen to useWhat it needs
FolderYou also run the browser extension and want the CLI to read the same dataA folder the extension is syncing to
CloudYou don't run the extension; you want to push directly to cotext.io from the terminalAn API token from cotext.io/settings

Both work the same from the CLI's perspective — every command is written against a Source abstraction. Switch by setting environment variables; nothing to reconfigure inside the CLI.

Resolution priority

When multiple sources are configured, the CLI picks the first one it finds, in order:

1. --folder <path>            (CLI flag)
2. COTEXT_FOLDER              (env)
3. ~/.config/cotext/config.json   (saved by `cotext init`)
4. COTEXT_API_TOKEN           (cloud fallback)

Folder always wins when both are configured.


3a. Folder source (paired with the extension)

If you're running the browser extension and want the CLI to read its data:

# Make sure the extension is syncing to a folder
# (popup → ".cotext Folder" → Connect folder)

# Point the CLI at the same folder
cotext init                    # interactive — saves to ~/.config/cotext/config.json

# Verify
cotext status

Expected output:

Source:    folder (/Users/you/cotext-sync)
Profiles:  3
Active:    code-review

Reading a profile

cotext list                       # show all profiles
cotext pull                       # active prompt to stdout
cotext pull --profile code-review # specific profile
cotext cat code-review            # full markdown including header

A common pattern — refresh CLAUDE.md from your active profile:

cotext pull > CLAUDE.md

Writing feedback signals

The CLI can write feedback signals into the folder's inbox/ directory; the extension picks them up on next popup open.

cotext signal "be more concise" --type dislike
cotext signal --type dislike --tag too-verbose
cotext signal "this format works" --type like \
  --response "$(cat /tmp/last-claude-output.txt)"

See CLI & MCP for the full flag set.


3b. Cloud source (no extension needed)

This is the path for "I never want to open a browser, I just want to push profiles from the terminal."

# 1. Sign in at cotext.io and generate an API token at /settings
# 2. Export it:
export COTEXT_API_TOKEN="ctx_<your-token>"

# 3. Verify the CLI sees the cloud source
cotext status

Expected:

Source:    cloud (https://cotext.io)
Profiles:  0
Active:    (none yet)

Create a profile from the terminal

cotext profile create "Code review" --starter code-review --activate

This:

  1. Builds the profile JSON locally from the starter pack
  2. POSTs it to https://cotext.io/api/push
  3. Activates it as your current profile

Visible immediately at https://cotext.io/@<your-username>/code-review.

profile create flags

FlagPurpose
--context <text>Free-form descriptor of what this profile is for. Appears in the synthesized prompt and biases LLM passes. e.g. coding, "code review at a 50-person startup". Default: general.
--category <slug>Curated category for the /explore listing on cotext.io. One of: general, coding, writing, research, creative, learning, business, productivity, analysis, support. Defaults to derive from --context.
--starter <pack>Seed entries + metrics from a starter pack
--description <text>Free-form note kept as customInstructions
--activateMake this the active profile after creation

See CLI & MCP reference for the difference between --context (free-form, shapes the prompt) and --category (curated, shapes the public listing).

Starter pack ids: code-review, email-writing, research, daily-driver, tutor, patient-explainer, strategic, creative-writing, brainstorm, sprint-planner, data-analyst, support-helper.

Sending signals against the cloud

Same syntax as folder mode — the CLI routes through /api/signals instead of dropping into inbox/:

cotext signal "be more concise" --type dislike

Cloud-side signals are stored until a local drainer (the browser extension or cotext daemon on your machine) picks them up, runs interpretation locally, and applies the resulting rule.


4. Wire MCP into Claude Code / Codex

The MCP server exposes your active profile to any MCP-aware client.

One-command install

cotext mcp-install

Registers cotext-mcp with both Claude Code (~/.claude.json) and Codex (~/.codex/config.toml) in one shot. Idempotent — re-running is a no-op if the entry already exists.

cotext mcp-install --claude         # only Claude Code
cotext mcp-install --codex          # only Codex
cotext mcp-install --print-only     # show the config snippets, don't write

Restart your AI client (Claude Code, Codex) after this.

Teach the agent when to use it

Pipe the canonical snippet into your CLAUDE.md (or AGENTS.md for Codex):

cotext mcp-prompt >> ~/.claude/CLAUDE.md
# or scoped to a single project:
cotext mcp-prompt >> ./CLAUDE.md

The snippet tells the agent to call get_preferences at session start and record_signal whenever you express a preference inline ("be more concise", "this format is perfect").

What MCP exposes

URIDescription
cotext://preferences/activeActive profile's prompt
cotext://profilesJSON summary of all profiles
cotext://profiles/{slug}One specific profile
ToolWhat it does
get_preferencesReturns the current prompt
list_profilesLists all profiles
record_signalDrops a feedback signal into the inbox or /api/signals

5. Headless mode: cotext daemon

If you want to run Cotext entirely without the browser extension — on a server, in a headless workflow, or just on principle — the daemon command does what the extension normally does.

The daemon supports three providers — Ollama (local), Anthropic Claude (cloud), and OpenAI (cloud). Pick whichever fits.

# Default — Ollama running locally
ollama serve &
ollama pull qwen3.5:4b
cotext init
cotext daemon

# Anthropic Claude — no Ollama install needed
export COTEXT_ANTHROPIC_KEY=sk-ant-...
cotext daemon --provider anthropic

# OpenAI
export COTEXT_OPENAI_KEY=sk-...
cotext daemon --provider openai

The daemon polls the folder's inbox/ every 1.5s, interprets each new signal via the chosen provider, appends rules to the active profile, runs the fact-extraction pass to pick up user-stated values (name, role, default language, …), and re-renders the prompt markdown. Every Nth appended entry (default 3, configurable via --synth-every) it runs the full library + prose synthesis to dedupe and rewrite the polished prompt — same output as the extension.

In another terminal:

cotext signal "be more concise" --type dislike \
  --response "$(cat /tmp/claude-output.txt)"

Within seconds, the daemon's stdout shows the new rule landing on the active profile. After a few signals the synthesis line will print too, e.g. synthesis: 5 → 4 entries on "daily" (Direct & Decisive).

For users on cloud providers who want tighter spend control:

cotext daemon --synth-every 0    # disable cadence — run cotext synth manually
cotext daemon --synth-every 10   # synthesize every 10 entries
cotext synth                     # one-off pass, any time

Cloud-only daemon (no folder, no extension)

If you only have COTEXT_API_TOKEN and no folder, the daemon polls /api/signals/pending against cotext.io instead of a local inbox/. Same loop — just over HTTP.

Important: don't run the daemon AND the extension at the same time

Both watch the same folder. The race on inbox file deletion is harmless, but two writers to the profile JSON can clobber each other. Pick one mode and stick with it.

Running as a service

The daemon is a foreground process. To run it under launchd (macOS) or systemd (Linux), see the CLI & MCP reference.


Where the CLI fits in

flowchart LR
Ext(["Browser extension"]):::primary
Folder[(".cotext folder<br/><i>*.json &middot; *.md &middot; inbox/</i>")]:::store
CLI["cotext CLI<br/>cotext-mcp"]:::dep
Cloud[("cotext.io")]:::store

Ext -- "writes profiles" --> Folder
CLI -- "reads profiles" --> Folder
CLI -- "writes signals to inbox/" --> Folder
Folder -. "publish (opt-in)" .-> Cloud
CLI -. "fallback when no folder" .-> Cloud

classDef primary fill:#0c111f,stroke:#5A96FF,stroke-width:2px,color:#ffffff
classDef store fill:#050810,stroke:#0038A8,color:#d9d9d9
classDef dep fill:#0a0e1a,stroke:#1f2a45,color:#c0c8db

The folder is the system's interop seam. The browser extension is the only writer of profile artifacts; the CLI / MCP / local server only WRITE signals (into inbox/) and READ profiles. This is why the CLI doesn't need a daemon or socket to coexist with the extension — the file system IS the protocol.

For the full architecture write-up, see Architecture.


Next steps