Guides
Connect your agent
The default path is the local stdio MCP server: nauro serve --stdio resolves the project store from the repo's .nauro/config.json. nauro setup and nauro adopt write that stdio entry directly into each surface's config file. A separate, optional cloud path reaches the project from surfaces without a local copy via nauro auth login, nauro link --cloud, nauro sync, and the remote connector at https://mcp.nauro.ai/mcp. As of 1.0, the stdio MCP tool contract is stable and follows semantic versioning; the cloud connector and hosted store are generally available, versioned and operated separately.
Two connection planes: local stdio vs cloud connector
Nauro has two distinct transports for the same store and payloads:
- Local. The stdio MCP server, spawned per-session by the agent client. It is canonical for any machine with a working copy.
- Cloud. The hosted HTTP connector at
https://mcp.nauro.ai/mcp, used from surfaces without a local checkout (claude.ai web) or from another machine.
stdio is the sole supported local transport; the former local FastAPI HTTP transport was retired (per the serve.py docstring). The cloud connector is HTTP and lives in a separate, private hosted server.
The stdio server resolves project context from the current directory's .nauro/config.json; there is no --project flag on serve (one source of truth, per the serve.py docstring).
Commit .nauro/config.json as the portable project-identity pointer. Client wiring is machine-local because it records an absolute executable path. Setup regenerates that wiring per machine, adds its repo-local files to a managed .gitignore block, and refuses to write a machine-local path into a file already tracked by git.
Same store and payloads on both planes: the stdio server delegates to the transport-agnostic implementations in nauro.mcp.tools, which call into nauro_core.operations.
| Local plane | Cloud plane | |
|---|---|---|
| Transport | stdio (spawned per session) | HTTP connector |
| Endpoint | nauro serve --stdio |
https://mcp.nauro.ai/mcp |
| When to use | Any machine with a working copy (canonical) | Surfaces with no local checkout, or another machine |
| Project resolution | From the cwd's .nauro/config.json |
From the authenticated cloud project |
The local stdio server registers 10 MCP tools (7 read, 3 write). The shared nauro_core.mcp_tools.ALL_TOOLS registry has 11; list_projects is remote-only because local installs auto-resolve to the single project store.
Counted the other way: 11 tools total (8 read, 3 write), with list_projects among the reads; the local-only subset is 7 read + 3 write = 10.
get_context, get_raw_file, list_decisions, get_decision,
diff_since_last_session, search_decisions, check_decision,
propose_decision, flag_question, update_state
# list_projects is remote-only (11th tool in nauro_core.mcp_tools.ALL_TOOLS)Source: serve.py; stdio_server.py (module docstring; run_stdio); tools.py (module docstring); README.md (MCP tools section).
The local stdio MCP server (nauro serve --stdio)
nauro serve --stdio calls run_stdio(), which runs a best-effort session-start pull (_pull_on_startup()), then mcp.run(transport="stdio"). The MCP client (Claude Code, Cursor, Codex) spawns this process and talks over stdin/stdout. Nauro sends no product analytics.
The --stdio flag is hidden and a no-op: it is accepted only for backward compatibility with installed client configs that spawn nauro serve --stdio. stdio is now the only transport (the serve Typer option is hidden=True with default True).
On startup, _pull_on_startup() resolves the project through the canonical two-tier waterfall: walk up to a .nauro/config.json, then try a v2 registry repo-path match. The v1 registry is not a resolution fallback.
If the project is cloud-mode with a stored token, it pulls the latest from remote (pull_before_session) before accepting tool calls. It never raises: on failure the server logs a warning and starts with local state.
Store resolution precedence inside tools is: an explicit project_id argument, else the cwd's .nauro/config.json, else the registry. When unresolved, tools return a guidance envelope (NOT_A_NAURO_REPO / WELCOME_NO_PROJECT) rather than crashing.
The FastMCP server is constructed as FastMCP("nauro", instructions=MCP_INSTRUCTIONS, log_level="WARNING").
The "nauro" name pairs with the stdio entry's command; behavioral guidance ships via MCP server instructions, not an injected CLAUDE.md block. Setup automatically strips Nauro's retired marked block if it finds one. A separate Nauro-owned two-line CLAUDE.md bridge may import @AGENTS.md so Claude Code also sees the generated shared context.
def run_stdio() -> None:
"""Run the MCP server over stdio (called by `nauro serve --stdio`)."""
_pull_on_startup()
mcp.run(transport="stdio")Source: serve.py; stdio_server.py (run_stdio, _pull_on_startup, FastMCP construction).
nauro setup [claude-code|cursor|codex|all]: what it writes
nauro setup wires the local stdio server into each surface's config by writing the file directly, not by shelling out to the client's own mcp add.
All surfaces use the same key name nauro and the same entry shape: {"command": "<validated absolute path to nauro>", "args": ["serve", "--stdio"]}. _find_nauro_command probes candidates with --version and prefers a durable absolute pipx, uv tool, system, or equivalent install. If only a working project-venv sibling is available, setup records it with a fragility warning. Otherwise it records the best path it has and warns that MCP may not work; bare nauro is the terminal fallback.
| Subcommand | Writes | Key / scope | Flags |
|---|---|---|---|
| setup claude-code | <repo>/.mcp.json per registered repo path |
mcpServers.nauro (project scope) |
--project, --remove, --with-hooks |
| setup cursor | <repo>/.cursor/mcp.json per repo |
mcpServers.nauro |
--project, --remove |
| setup codex | ~/.codex/config.toml |
[mcp_servers.nauro] (user-global) |
--remove, --with-hooks |
| setup all | Claude Code + Cursor + Codex in one call; refreshes Nauro-managed AGENTS.md | all of the above | --project, --remove, --with-subagents, --force-overwrite, --with-skills, --with-hooks |
Adopt, setup, and incidental regeneration paths preserve an unmanaged AGENTS.md and warn. nauro sync is the sole explicit overwrite path. A # Manual section survives replacement.
setup claude-code automatically removes Nauro's retired marked block from CLAUDE.md. When no CLAUDE.md exists, the shared AGENTS.md regeneration seam writes a Nauro-owned two-line bridge containing @AGENTS.md. An existing foreign CLAUDE.md is never modified: an existing live import is accepted, otherwise setup prints an advisory. Teardown removes only the validated Nauro-owned bridge. Setup also prunes a redundant user-scope HTTP nauro entry from ~/.claude.json; a user-defined stdio entry is left alone.
Standalone nauro setup codex --remove preserves the user-global entry while any Nauro project remains registered, including the current project when it is the only one. Clear it for the last project with nauro setup all --remove from that project. setup all continues across per-handler errors so partial coverage still reports progress.
--with-subagents (on setup all / adopt) installs the bundled planner, executor, reviewer, and tech-lead roles for both supported agent surfaces. Claude Code receives Markdown definitions in ~/.claude/agents/; Codex receives TOML definitions in ~/.codex/agents/. Cursor has no subagent format.
A differing Nauro-owned skill or agent definition is refreshed and its prior content is saved to a sibling .bak. --force-overwrite skips that backup and overwrites in place. Files outside Nauro's owned names are left untouched.
Claude Code's bundled definitions reference cloud tools through mcp__claude_ai_Nauro__*, so its remote connector must be named exactly Nauro. Codex renders the same role instructions in its native format and does not share that connector-name constraint.
--with-hooks wires two surface-specific integrations. Claude Code gets an advisory UserPromptSubmit hook in <repo>/.claude/settings.local.json that retrieves related decisions for each turn. Codex gets SessionStart and SubagentStart hooks in <repo>/.codex/hooks.json that inject the Nauro protocol and current L0 context.
Both hook integrations are project-scoped, idempotent, and fail open. Removal strips only Nauro-authored entries. Codex skips new or changed hooks until the user reviews and trusts them through /hooks. Cursor has no hook integration.
{
"mcpServers": {
"nauro": {
"command": "<validated absolute path to nauro>",
"args": ["serve", "--stdio"]
}
}
}[mcp_servers.nauro]
command = "<validated absolute path to nauro>"
args = ["serve", "--stdio"]$ nauro setup all --with-skills --with-subagents # complete Claude Code + Codex workflow
$ nauro setup all --with-hooks # optional Claude Code + Codex hooks
$ nauro status # diagnose integration wiring
$ nauro doctor # check store integritySource: setup.py (claude_code, cursor, codex, all_); integrations/orchestrator.py (setup_all_surfaces); integrations/agents.py (materialize_agents); integrations/claude_hooks.py; integrations/codex_hooks.py.
nauro adopt: register and wire in one shot (existing repo)
nauro adopt bootstraps a project from an existing repo. It detects the repo root (or --repo), refuses non-git directories (_is_git_repo), guards against re-adopting (an existing .nauro/config.json), and runs a same-name collision pre-check against the local v2 registry (_check_collision via find_projects_by_name_v2).
Use nauro adopt --with-skills --with-subagents for the complete Claude Code and Codex workflow. Plain nauro adopt is the minimal path: it wires MCP and installs the core nauro-adopt skill.
It then registers a v2 project (register_project_v2, mode=local), writes .nauro/config.json (save_repo_config), and scaffolds the store (scaffold_project_store), before wiring MCP and materializing skills across Claude Code, Cursor, and Codex via setup_all_surfaces.
After wiring, adopt smoke-tests the wired binary by booting <nauro> serve --stdio briefly (_smoke_test_wired_binary, default timeout 1.5s): a clean exit on stdin EOF (returncode 0) or a process still running at timeout is healthy; a non-zero exit before timeout (an import crash) prints a WARNING.
The closing message instructs the user to restart their agent and invoke /nauro-adopt in Claude Code or $nauro-adopt in Codex. Cursor uses the installed rule.
Adopt preserves an unmanaged AGENTS.md and warns.
Flags: --name, --repo, --print-prompt (mutually exclusive with all other flags; prints the canonical /nauro-adopt skill body to stdout via load_adopt_body() for pasting into chat surfaces), --no-setup-and-skills (skip MCP wiring and skill materialization), --with-subagents, --force-overwrite, --with-skills, and the teardown trio --remove / --purge-store / --yes (next paragraph).
If the repo is already adopted and the caller passes --with-subagents / --with-skills / --force-overwrite, adopt installs just those artifacts onto the existing adoption (_install_into_adopted_repo via setup_all_surfaces, registration untouched) instead of dead-ending.
nauro adopt --remove is the inverse: after a confirmation prompt (--yes skips it) it un-wires the MCP, skill, subagent, and hook entries, strips the generated AGENTS.md (a # Manual section is preserved), deletes .nauro/config.json, and deregisters the repo. Only this repo is dropped when the project spans several, and the store is kept unless --purge-store is passed on the project's last repo.
The always-installed skill set is SKILL_NAMES = ("nauro-adopt",); --with-skills additionally installs OPT_IN_SKILL_NAMES = ("nauro-ship-task", "nauro-context", "nauro-loop"). nauro-ship-task references the @nauro-* subagents and nauro-loop dispatches that chain, so passing --with-skills without --with-subagents prints SHIP_TASK_NEEDS_SUBAGENTS_NOTICE; nauro-context composes only existing MCP tools and carries no such notice.
$ cd /path/to/repo
$ nauro adopt --with-skills --with-subagents
$ nauro status
# Restart, then use /nauro-adopt in Claude Code or $nauro-adopt in CodexSource: adopt.py (adopt, _is_git_repo, _smoke_test_wired_binary, _check_collision, _install_into_adopted_repo, --print-prompt, load_adopt_body); setup.py (SKILL_NAMES, OPT_IN_SKILL_NAMES).
Cloud path: auth login → link --cloud → sync (distinct steps)
The cloud path is opt-in and reaches a project from surfaces without a local copy or from another machine. It is three separate steps.
Step 1, nauro auth login. An Auth0 Authorization Code + PKCE (S256) flow. It opens a browser, runs a localhost callback server on REDIRECT_PORT = 18457 (redirect_uri http://localhost:18457/callback), waits up to 120s for the code, exchanges it, and stores tokens in ~/.nauro/config.json under the "auth" key (with sub, sanitized_sub, user_id, access_token, refresh_token).
The public OAuth identifiers (not secrets) are DEFAULT_API_URL=https://mcp.nauro.ai, DEFAULT_AUTH0_AUDIENCE=https://mcp.nauro.ai/mcp, and AUTH0_SCOPES="openid profile email offline_access read:context write:context".
The closing message tells cloud users to add https://mcp.nauro.ai/mcp as a connector and, for Codex, to set mcp_oauth_callback_port = 8765 at the top of ~/.codex/config.toml.
Step 2, nauro link --cloud. A one-time, one-way promotion of the current repo's local-only project to cloud. It reads the local-mode .nauro/config.json, requires auth (errors with "Run 'nauro auth login' first" otherwise), calls the remote POST /projects (create_project) to mint a cloud project_id, re-keys the local store directory and v2 registry entry under the new id (rename_project_id_v2, preserving repo_paths and store contents), and rewrites .nauro/config.json to mode=cloud with server_url=https://mcp.nauro.ai (DEFAULT_API_URL).
There is no inverse "unlink to local". The re-key is the irreversible step and persists before the push; the initial push (push_changed_files) is best-effort: a transient presign/S3 failure warns and exits 0, and nauro sync retries the upload.
Step 3, nauro sync. Captures a snapshot and explicitly replaces AGENTS.md in associated repos; it is the sole overwrite path, and a # Manual section survives replacement. With cloud sync configured it does a git-style pull-then-push: pull first (_pull_via_presign: GET /sync/manifest → POST /sync/presign → S3 GETs), then push (push_store_to_cloud).
For a local-only project it captures the snapshot and reports "local-only project; nothing to upload". Flags: --message/-m, --project, --status. The MCP update_state tool records what changed; sync does not touch state_current.md.
nauro attach <project_id> is the cloud equivalent of init --add-repo: associate the current repo with an existing cloud project (membership is verified against GET /projects via list_projects before any local write), writing a cloud-mode .nauro/config.json. For a fresh start, nauro init --cloud <name> creates a cloud-scoped project up front.
After the steps, add https://mcp.nauro.ai/mcp as an MCP connector in your tool's settings. Enter the URL exactly, with no trailing slash.
$ nauro auth login
$ nauro link --cloud # one-time: promote the local project to cloud
$ nauro sync
# then add https://mcp.nauro.ai/mcp as an MCP connector (no trailing slash)Source: auth.py (login, DEFAULT_API_URL, DEFAULT_AUTH0_AUDIENCE, AUTH0_SCOPES, REDIRECT_PORT, REDIRECT_URI, closing message); link.py (link); sync.py (sync, _pull_via_presign, _pull_from_cloud); attach.py (attach); cloud_projects.py (create_project, list_projects); README.md (Cross-surface sync section).
Codex remote connector
- Add the hosted connector under a name distinct from the local
naurostdio server:codex mcp add nauro-cloud --url https://mcp.nauro.ai/mcp. - Pin the OAuth callback port at the top of
~/.codex/config.toml:mcp_oauth_callback_port = 8765. Codex's callback uses a fixed, pre-registered port; without this line Codex picks a random port and login fails. The closing message fromnauro auth loginalso surfaces this requirement. - Requires Codex 0.131.0 or newer. Enter the URL exactly as shown, with no trailing slash. If login reports a callback-port error, free port 8765.
- This is separate from
nauro setup codex, which wires the local stdio server under[mcp_servers.nauro]in the same~/.codex/config.toml. The remote connector (nauro-cloud) and the local stdio server (nauro) coexist under different names.
$ codex mcp add nauro-cloud --url https://mcp.nauro.ai/mcpmcp_oauth_callback_port = 8765Source: README.md (Codex remote connector section); auth.py (login closing message); setup.py (_configure_codex, the local stdio entry under [mcp_servers.nauro]).
Chat surfaces (Claude.ai, Perplexity)
Chat-paste mode does not create projects. First run nauro adopt --name <project> from a terminal: that registers the project, wires MCP across surfaces, and installs the skills.
Only then can the chat agent seed context.
After adoption, point the chat agent at docs/adopt-prompt.md. nauro adopt --print-prompt outputs the same canonical /nauro-adopt skill body to stdout (without the intro paragraph) for copy/paste.
Chat surfaces have no shell, so the skill operates only on content the user pastes (Step 3b) and only against an already-adopted project (verified in Step 2). The code-evidence path (Step 4) and the targeted probes (Step 6b) are unavailable; the skill skips from Step 3b directly to Step 5.
On chat surfaces the skill passes the project's id as the explicit project_id argument on every MCP call (propose_decision, update_state, flag_question, get_context, list_decisions, check_decision, get_decision).
Auto-resolve would otherwise route to the user's default project, not the one being seeded when local and cloud projects coexist.
Reaching a project from a chat surface without a local copy still requires the cloud connector (https://mcp.nauro.ai/mcp) configured in that tool's settings: the cloud path above must already be done.
$ nauro adopt --name <your-project-name> # register + wire MCP + install skills
# then in chat, follow docs/adopt-prompt.md (or: nauro adopt --print-prompt)Source: docs/adopt-prompt.md (intro, Surface modes, Step 2, Step 3b); README.md (Chat surfaces line); adopt.py (--print-prompt, load_adopt_body).
Key facts and gotchas
- The local stdio MCP entry is keyed
naurowith shape{"command": "<validated absolute path to nauro>", "args": ["serve", "--stdio"]}when a durable install is available. Resolution validates candidates, prefers durable absolute paths, warns before recording a fragile working path, and uses barenauroonly as the warned terminal fallback. - setup writes config files directly: claude-code →
<repo>/.mcp.json(project scope, per repo); cursor →<repo>/.cursor/mcp.json(per repo); codex →~/.codex/config.tomlunder[mcp_servers.nauro](user-global). - The cloud connector URL is
https://mcp.nauro.ai/mcp; enter it exactly, with no trailing slash. - Codex remote connector:
codex mcp add nauro-cloud --url https://mcp.nauro.ai/mcp; requiresmcp_oauth_callback_port = 8765at the top of~/.codex/config.toml; requires Codex 0.131.0 or newer. auth.pyconstants:DEFAULT_API_URL=https://mcp.nauro.ai,DEFAULT_AUTH0_AUDIENCE=https://mcp.nauro.ai/mcp,REDIRECT_PORT=18457,REDIRECT_URI=http://localhost:18457/callback,AUTH0_SCOPES="openid profile email offline_access read:context write:context"; tokens are stored in~/.nauro/config.jsonunder"auth"; the callback timeout is 120s.- The cloud path is three distinct steps kept separate:
nauro auth login→nauro link --cloud(one-time, one-way promotion; no inverse) →nauro sync. - The local stdio server registers 10 MCP tools (7 read, 3 write);
nauro_core.mcp_tools.ALL_TOOLShas 11 (8 read, 3 write);list_projectsis remote-only. - stdio is the only supported local transport (the FastAPI HTTP transport was retired);
--stdiois a hidden no-op kept for backward compatibility; there is no--projectflag onserve. nauro adoptregisters a v2 project (mode=local), wires all surfaces viasetup_all_surfaces, smoke-tests the binary, and installs thenauro-adoptskill. Use/nauro-adoptin Claude Code,$nauro-adoptin Codex, or the installed rule in Cursor.- Complete workflow:
nauro adopt --with-skills --with-subagents. The four roles install into~/.claude/agents/as Markdown and~/.codex/agents/as TOML. Cursor has no subagent format. - Claude Code's workflow definitions require the remote connector name
Nauroso theirmcp__claude_ai_Nauro__*tools resolve. Codex does not share that connector-name constraint. nauro setup all --with-hookswrites Claude Code's advisoryUserPromptSubmithook to<repo>/.claude/settings.local.jsonand Codex'sSessionStart/SubagentStarthooks to<repo>/.codex/hooks.json. Review new Codex hooks through/hooks.- Verification:
nauro statusdiagnoses MCP and workflow wiring;nauro doctorchecks store integrity. Start a fresh agent session for the final MCP check. - Chat surfaces: run
nauro adoptin a terminal first (chat-paste mode does not create projects), then point the agent atdocs/adopt-prompt.md; the skill passes an explicitproject_idon every MCP call. setup claude-codeprunes a redundant user-scope HTTPnauroentry from~/.claude.jsonbecause project-scope stdio is canonical and a same-name collision can resolve to the wrong store (only the HTTP/urlentry is pruned; a user-defined stdio entry is left alone).
Gotchas to watch for:
- The local stdio entry uses
command/args(nauro serve --stdio), not aurl; theurlform (https://mcp.nauro.ai/mcp) is only for the hosted/remote connector. Do not present the cloud URL as the local.mcp.jsonvalue. nauro setup codex(local stdio under[mcp_servers.nauro]) is a different thing from the Codex remote connectornauro-cloudadded viacodex mcp add --url. They coexist under different names in the same~/.codex/config.toml.link --cloudis one-way and irreversible: the re-key persists before the cloud push, and a failed push does not roll it back (it warns, exits 0, and you retry withnauro sync). There is no "unlink to local" command.- Codex's
8765port is Codex-side and unrelated to nauro's own18457auth-login callback port. - Cloud-mode projects cannot be extended with
init --add-repo; usenauro attach <project_id>instead.