Skip to content

ctx init

Creates the .contexo/ knowledge tree for a project and connects the AI coding agents on your machine to it.

Once per project, from the repository root, before anything else. It needs no login and never contacts a Contexo server — every step is a local file write — so it is safe to run while you are still deciding whether you want Contexo at all (ctx detach reverses it).

Two things trip people up. First, ctx init does not log you in or attach a remote repo; straight after it you have a local knowledge base and nothing else, which is exactly what ctx status reports below. Second, everything is written relative to the current directory (or --root), so running it from a subdirectory quietly gives you a second, useless .contexo/. Run it where your .git is.

Re-running is safe. It is idempotent by design: existing config, seed files, MCP entries and hooks are left alone, so ctx init is a reasonable way to pick up an agent you installed after the fact (though ctx mcp install and ctx hooks install are the targeted tools for that).

Terminal window
ctx init
ctx init --root path/to/project
ctx init --no-gitignore
ctx init --no-mcp --no-hooks
FlagTypeDefaultDescription
--no-cursorboolfalseskip auto-wiring Cursor (.cursor/mcp.json) even when Cursor is detected
--no-gitignoreboolfalseskip adding .contexo/ to .gitignore
--no-hooksboolfalseskip registering the Claude Code Stop hook for per-turn capture
--no-mcpboolfalseskip wiring the MCP server into agent configs (.mcp.json, .cursor/mcp.json)
FlagTypeDefaultDescription
--rootstringproject root directory (default: current directory)

A few of these do less — or more — than their one-liners suggest:

  • --no-cursor only skips Cursor’s MCP entry. Cursor’s capture hooks are governed by --no-hooks, not by --no-cursor, so ctx init --no-cursor on a machine with Cursor installed still writes .cursor/hooks.json. Use --no-hooks as well if you want no .cursor/ directory at all.
  • --no-hooks skips all three capture integrations, not just Claude Code’s: no Stop hook in .claude/settings.json, no .codex/hooks.json, no .cursor/hooks.json.
  • --no-mcp implies no Cursor MCP entry, and also suppresses the “Codex detected” hint. It does not affect hooks.
  • --root is a global flag and is resolved before anything is created; every path on this page is relative to it.
Terminal window
ctx init
ctx init
  Wired Claude Code (.mcp.json) — restart your agent to load the contexo server
  Cursor detected — wired .cursor/mcp.json
  Created .gitignore with .contexo/
Installed Contexo capture Stop-hook in .claude/settings.json
Restart Claude Code (or open a new session) so the hook is picked up.
Installed Cursor capture hooks (.cursor/hooks.json: beforeSubmitPrompt + afterAgentResponse)
Initialized .contexo in ~/projects/acme-api

Agent integrations for this project:

  AGENT        MCP SERVER                CAPTURE (STOP HOOK)
  Claude Code  wired (.mcp.json)         installed
  Cursor       wired (.cursor/mcp.json)  installed
  Codex        not installed             not installed

Add Contexo to another agent or harness
---------------------------------------
Contexo's MCP server is a standard stdio server:  command "ctx", args ["mcp"].
Add that to the agent's own MCP config — same server everywhere; only the
file and format differ:

  AGENT        CONFIG                               FORMAT / HOW
  Claude Code  ./.mcp.json                          JSON mcpServers   — ctx mcp install --tool=claude
  Cursor       ./.cursor/mcp.json                   JSON mcpServers   — ctx mcp install --tool=cursor
  Codex        ~/.codex/config.toml                 TOML [mcp_servers.contexo]   — ctx mcp install --tool=codex
  Windsurf     ~/.codeium/windsurf/mcp_config.json  JSON mcpServers
  OpenCode     ./opencode.json                      JSON  mcp: { contexo: { type: "local", command: ["ctx","mcp"] } }
  Hermes       config.yaml                          YAML  mcp_servers: { contexo: { command: ctx, args: [mcp] } }
  OpenClaw     (CLI-managed)                        run the `openclaw mcp` command

  JSON mcpServers entry:   "contexo": { "command": "ctx", "args": ["mcp"] }
  Any other MCP client: add the same server; see its docs for the exact path.

Capture (the Stop hook): Claude Code, Codex, and Cursor are supported —
  ctx hooks install --tool=claude|codex|cursor|all
Claude parses its transcript; Codex and Cursor pair their prompt + response
hooks inline. Other MCP-capable harnesses get the tools now; capture as they
expose a stop/turn-end hook.

The per-file lines come first, then the summary: where .contexo/ landed, an integration table for this project, and the guide for agents Contexo does not wire itself. This run was in a fresh git repo with Cursor installed and no Codex on PATH.

Terminal window
ctx status
ctx status
Initialized: yes
Server: (none — run 'ctx remote set <url>')
Repo: (none — run 'ctx remote set-repo <id>')
Authenticated: no
Local pages: 0
Last pull: (never)
Pages never pushed: 0

No server, no repo, not authenticated. ctx init is local-only; wiring up the remote is ctx login followed by ctx remote set-repo.

Terminal window
ctx mcp status
ctx mcp status
Agent integrations for this project:

  AGENT        MCP SERVER                CAPTURE (STOP HOOK)
  Claude Code  wired (.mcp.json)         installed
  Cursor       wired (.cursor/mcp.json)  installed
  Codex        not installed             not installed

Add another agent (Windsurf, OpenCode, Hermes, ...)? Run `ctx mcp guide`.

This is the same table ctx init prints at the end, on demand. Useful after you install a new agent, or when an agent claims it cannot see the contexo server.

Everything below is a local file write. ctx init contacts no Contexo server and makes no git commit. The only network traffic it can produce is the update nudge every ctx command runs after it succeeds — an at-most-once-per-24h GitHub releases lookup, skipped when stdout is not a TTY or when CONTEXO_NO_UPDATE_CHECK or CI is set.

Path What ctx init does Skipped by
.contexo/, .contexo/wiki/concepts/, .contexo/wiki/entities/, .contexo/wiki/analyses/, .contexo/raw/sessions/ created (mkdir -p, mode 0755) never
.contexo/config.json written as {"version": 1}only if absent never
.contexo/index.md, .contexo/tags.md seeded with empty-section placeholders — only if absent never
.mcp.json merges mcpServers.contexo = {"command": "ctx", "args": ["mcp"]} --no-mcp
.cursor/mcp.json same entry, only when Cursor is detected --no-mcp, --no-cursor
.gitignore created (or appended to) with a comment header plus .contexo/, only when <root>/.git exists --no-gitignore
.claude/settings.json appends a Stop hook group running ctx capture turn, tagged _contexo: contexo-capture-turn --no-hooks
.codex/hooks.json Stop + UserPromptSubmit hooks running ctx capture turn --agent codex, only when Codex is detected --no-hooks
.cursor/hooks.json beforeSubmitPrompt + afterAgentResponse hooks running ctx capture turn --agent cursor (adds "version": 1), only when Cursor is detected --no-hooks

Merging, not overwriting. The JSON writers load whatever is already there and add only the contexo key, so other MCP servers and other hooks survive. If the contexo MCP entry is present and identical, nothing is written at all and init says so. The .gitignore edit is skipped entirely when a line already reads .contexo/ or .contexo.

Detection is deliberately asymmetric. Cursor counts as installed if ~/.cursor exists or cursor is on PATH — wiring it only writes harmless project-local files. Codex must have its binary on PATH; a bare ~/.codex directory is not enough, because other tools create that directory and wiring Codex means shelling out to codex mcp add.

Codex’s MCP server is never wired by init. It lives in Codex’s global ~/.codex/config.toml, so init only prints a one-line hint and leaves the decision to you:

Terminal window
ctx mcp install --tool=codex

Hook failures are non-fatal. If the Stop hook cannot be installed, init prints Warning: could not install Claude Stop hook: … (run 'ctx hooks install' later) and carries on; the knowledge directory is the load-bearing part. The Codex and Cursor capture hooks warn the same way (Warning: could not install Codex capture hooks: …).

Why the seed files matter. .contexo/index.md and .contexo/tags.md are what the ctx://index and ctx://tags MCP resources read; the index is advertised to agents with priority 1.0. Seeding them means the very first session gets a valid (if empty) index instead of a read error. They are rebuilt from your pages whenever an agent writes a page (ctx_write_page) and on every ctx pull.

init: write .mcp.json: agentwire: parse …: invalid character … — an existing .mcp.json (or .cursor/mcp.json) is not valid JSON. Init refuses to guess and aborts. The .contexo/ tree was created first and survives; the .gitignore line and the hooks come after MCP wiring and never ran. Fix the file, or run ctx init --no-mcp and wire the agent afterwards with ctx mcp install.

init: create …: permission denied — the project root is not writable. Directory creation is the very first step, so nothing else has been touched.

No .gitignore line and no message about one — the directory has no .git, so the step is skipped silently. Run git init first, then ctx init again (it is idempotent), or add .contexo/ yourself.

Agent shows contexo with zero tools — the agent is running ctx mcp outside a Contexo project. Outside a .contexo/ directory the MCP server starts in dormant mode with no tools rather than failing. Check that the agent’s working directory is the project root you ran ctx init in.

  • ctx detach — reverse everything on this page
  • ctx mcp — wire, unwire, and inspect agent MCP configs on their own
  • ctx hooks — install or remove the capture hooks on their own
  • ctx login — the next step: authenticate and attach a remote repo