@codemesh-app/cli
v0.1.0
Published
CodeMesh from the terminal: a live graph of your codebase for Claude Code, Codex, Opencode and any MCP agent. No editor required.
Maintainers
Readme
@codemesh-app/cli
CodeMesh from the terminal. No editor required.
CodeMesh builds a live knowledge graph of your real codebase: its structure, its git history and its current working tree. It serves that graph to your AI agents over MCP. When an agent asks a question it gets back only the small pieces that matter, instead of grepping and reading whole files. That is the difference between thousands of tokens per question and dozens.
This package is for people whose agents live in a terminal: Claude Code, Codex, Opencode, Cursor, Devin. Everything the VS Code extension does for setup, this does from a shell.
Contents
- Install
- Quick start
- Accounts: sign up, sign in, sign out
- Repositories and syncing
- Connecting AI agents
- The tool guard
- Asking questions directly
- Analytics: tokens, cost and time
- Scope: what an agent may read
- Support
- Diagnosis and teardown
- Command reference
- Where state lives
- Environment variables
- Troubleshooting
Install
npm install -g @codemesh-app/cliRequires Node 18.17 or newer.
The codemesh-sync daemon and the codemesh engine binary ship as per-platform
optional dependencies, the same pattern esbuild and swc use. npm installs only
the one matching your machine. There is no build step, no cargo, and no
postinstall script that reaches the network, so npm ci --ignore-scripts still
produces a working install.
| Platform | Status | |---|---| | Linux x64 | supported | | macOS arm64 (Apple silicon) | supported | | macOS x64 (Intel) | supported | | Windows x64 | supported | | Linux arm64 | not yet |
On any platform without a published binary, npm installs the CLI itself and
simply omits the binary package rather than failing. codemesh doctor then says
exactly what is missing and why. You can still use CodeMesh by building the
engine yourself and pointing CODEMESH_SYNC_BINARY at it.
Quick start
codemesh login # sign in or create an account, in your browser
cd ~/your/repo
codemesh sync # register this repo and run the first ingest
codemesh connect # wire up every AI agent on this machineRestart your agent so it picks up its new MCP entry, then ask it something about your codebase. It will use CodeMesh instead of trawling files.
If anything looks wrong, codemesh doctor checks every layer and prints the one
command that fixes the first problem it finds.
Accounts
Signing up
There is no separate codemesh signup. Account creation happens inside the
sign-in flow, so codemesh login is the entry point whether or not you already
have an account.
codemesh loginWhat happens, step by step:
- The CLI generates a PKCE challenge and starts a callback server on an
ephemeral port on
127.0.0.1. - It opens (or prints) a URL at
https://codemesh.cloud/oauth/authorize. - If you are not signed in, that page sends you to
/login, which offers "No account? Create one". The sign-up link carries your pending authorization with it, so creating an account continues the CLI sign-in rather than stranding you on a dashboard. - A new account must verify its email before it can authorize anything. You are
diverted to
/verify-email, not refused, and entering the code resumes the sign-in automatically. - You approve the consent screen.
- The browser redirects back to the CLI's callback, which exchanges the code.
The CLI then mints a long-lived cm_sk_ API key and stores that. This matters:
the OAuth access token lives about an hour, and the daemon, the engine binary and
the MCP bridge all need credentials that outlive it. Everything downstream reads
the API key.
Signing in over SSH
The redirect goes to 127.0.0.1 on the machine running codemesh. If your
browser is on a different machine, that address is your laptop's own loopback
with nothing listening, and the redirect dead-ends. codemesh login detects an
SSH session and warns before it starts.
Forward the port. This is the supported way, and the only one that works:
codemesh login --no-browser- It prints the authorization URL instead of opening a browser.
- Read the port out of that URL.
- From the machine that has the browser:
ssh -L <port>:127.0.0.1:<port> <the-remote-host> - Open the printed URL there.
The redirect stays on 127.0.0.1 throughout, which is what makes it acceptable
to the authorization server.
--callback-hostdoes not work with a routable address, on any deployment. An authorization code sent over plainhttp://to a non-loopback host would cross the network in the clear, so the authorization server acceptshttp://only for127.0.0.1,localhostand[::1]. Passing anything else is refused before the browser opens, with these instructions. The flag remains only for the loopback aliases.
Checking and ending a session
codemesh status # gateway, API key present, org, plan, graph readiness
codemesh logout # pause syncing and stop the daemonlogout leaves your graph in the cloud and your repos registered. It stops this
machine from syncing. codemesh login again resumes.
Pointing at a different deployment
codemesh login --api-url https://codemesh.cloud
codemesh status --api-url https://your-gateway.example.comThe default is https://codemesh.cloud. Once signed in, the gateway recorded in
your credentials wins over the compiled-in default, so a machine signed in
against a private deployment never silently talks to production.
Repositories and syncing
Registering and ingesting
codemesh sync # the repo containing the working directory
codemesh sync ~/a ~/b # specific repos
codemesh sync --here # every repo directly below this foldersync is idempotent. On each run it:
- Registers the repo if it is new. The repository id is issued by the server, keyed on the normalized git remote, never chosen locally. That is what stops two checkouts sharing a directory name from merging into one graph, and what makes the same repo on a second machine converge instead of forking.
- Health-checks the daemon and starts it detached if it is down.
- Installs chain-preserving git hooks into
.git/hooks, so commits, checkouts and merges wake the daemon. - Queues a catch-up.
Nothing is ever written inside your repository except those git hooks.
Keeping it running
codemesh sync --watch # supervision loop, every 30s
codemesh sync --watch --interval 10 # every 10s--watch is the loop the editor extension used to provide. Each tick keeps the
daemon alive and repairs agent configurations that have gone stale. It is
deliberately not a progress display and prints little. Ctrl-C stops watching;
the daemon keeps running.
Forcing a re-scan
codemesh catchup # this repo
codemesh catchup --here # every repo below this folderUse this after something external changed the tree, or when you suspect drift.
Ingest options
codemesh sync --include-ignored # also ingest gitignored files
codemesh sync --sync-git-state # also sync working tree, stash, reflog, remotes--include-ignored is off by default and should usually stay off: it pulls
in node_modules, build output and anything else your .gitignore excludes,
which costs storage and dilutes results.
Listing and managing repos
codemesh repos # registered on this machine
codemesh repos --all # every repo your organization has
codemesh repos --json
codemesh repos add owner/name # clone and register one you don't have
codemesh repos add owner/name --branch developcodemesh repo enable [path] # resume syncing
codemesh repo disable [path] # stop syncing, keep the data
codemesh repo set --include-ignored # change ingest options for one repo
codemesh repo set --include-ignored --all # for every repo
codemesh repo delete-data [path] # schedule permanent deletion of its graph
codemesh repo delete-data --yes # skip the confirmationdisable is enforced server-side as well as locally: the ingest endpoint rejects
a push for a disabled repo regardless of what the local daemon believes.
delete-data is the only destructive command here. It schedules permanent
deletion of that repository's graph data and disables its syncing. Your local
files are never touched.
Watching a sync happen
codemesh status --watch # live, repaints every 5 seconds
codemesh status --watch --interval 2 # fasterA single screen that redraws in place, showing every repository with its state, how long ago it last synced, and how many elements it has pushed, plus a summary line. Ctrl-C leaves your scrollback exactly as it was.
codemesh status --watch every 5s · Ctrl-C to stop
daemon 13 repo(s) tracked
REPO STATE LAST SYNC ELEMENTS
• /home/you/api syncing, 40 queued 12s ago 1,204
/home/you/web idle 4m ago 35,917
/home/you/old-service missing on disk - -
syncing 1 · 1 missing on disk · idle 11It polls only the local daemon on 127.0.0.1:7077, which is free and
instant. Nothing in the loop touches the CodeMesh app, which is what makes a
5-second cadence reasonable.
Piping it (codemesh status --watch > log) prints one snapshot and exits rather
than emitting escape codes forever.
The other levels of detail, when you need them:
codemesh status # the same table, printed once
tail -f ~/.codemesh/logs/daemon.log # the running trace
curl -s 127.0.0.1:7077/status | python3 -m json.toolThe daemon's own /status is the richest source. Per repo it carries a history
array with elements, nodes_created, relationships_created, deletes,
batches, duration_ms, started_at, finished_at, ok, plus whether the
working tree is dirty.
Connecting AI agents
codemesh connect # every detected agent
codemesh connect claude-code # one
codemesh connect claude-code opencodeAgent ids: claude-code, cursor, windsurf, opencode, codex.
Restart the agent afterwards. MCP entries are read at startup.
What connect writes
| Agent | MCP configuration | Instructions file |
|---|---|---|
| Claude Code | ~/.claude.json | ~/.claude/CLAUDE.md |
| Cursor | ~/.cursor/mcp.json | none, see below |
| Opencode | ~/.config/opencode/opencode.json | ~/.config/opencode/AGENTS.md |
| Codex | ~/.codex/config.toml | ~/.codex/AGENTS.md |
| Devin (Windsurf) | ~/.codeium/windsurf/mcp_config.json | ~/.codeium/windsurf/memories/global_rules.md |
The MCP entry launches the engine binary as codemesh mcp-stdio. It inherits the
agent's working directory, which is what lets scope follow the folder the agent
runs in.
Cursor receives no instructions block. Its global rules live in application
settings rather than a documented file on disk, so connect cursor writes the
MCP entry only. If you want Cursor bound by the same rules, paste the block into
Cursor Settings, Rules, by hand.
Hard rules are written by default
By default, and with no flag, connect appends an instructions block telling the
agent it must use CodeMesh instead of local file traversal for any search or
file read in that codebase, and to keep retrying before falling back. It also
states the escape hatch: after 3 consecutive failures on the same question, local
search is allowed for that question.
Those are instructions. They are advisory, and an agent can ignore them. The component that actually enforces them is the guard, and in this CLI the guard is opt in. See below.
Agents that cannot speak MCP
codemesh connect --no-mcpWrites the rules but no MCP entry. The agent is told to run
codemesh context "<question>" instead of grep. With --guard as well, an
intercepted search is answered by CodeMesh directly and the result handed back,
with no MCP server involved.
Which variant an agent gets is read from that agent's own configuration at run time, not chosen at install time, so the extension and this CLI always compute the same bytes for the same agent.
Sharing a machine with the VS Code extension
Both can be installed and neither disturbs the other.
They share what must be shared: one credential store, one repository registry,
one machine id, one daemon. They do not share agents. Each agent is managed
by whichever client connected it first, recorded in ~/.codemesh/agent-owners.json.
The other client reads its state but never writes it, so a codemesh guard off
here is not undone by the editor's next repair sweep.
codemesh connect claude-code --take-over # claim an agent the editor manages
codemesh disconnect claude-code # give the claim backDisconnecting
codemesh disconnect # every agent this CLI manages
codemesh disconnect claude-codeRemoves the instructions block and the guard. It deliberately leaves the MCP entry in place, so signing back in later is a no-op rather than a re-setup.
Seeing what is wired
codemesh agents # installed, and connected / needs reconnect / not connected
codemesh info # raw endpoints, for any MCP client not in the table aboveneeds reconnect means an entry exists but points somewhere stale, which is a
different problem from never having been connected.
The tool guard
An agent told to prefer CodeMesh will still reach for grep when it feels like
it, and that is where the token savings leak away. The guard is a hook that
denies search-shaped commands inside synced repositories and points the agent at
CodeMesh instead.
It is off by default in this CLI. Installing a package from npm is not
consent for your shell's grep to start failing. The VS Code extension installs
it by default; this does not.
codemesh connect --guard # at connect time
codemesh guard on # any time after
codemesh guard status
codemesh guard offWhat it does and does not touch
- Always intercepted:
grep,rg,find,fd,ack,ag, and each agent's native search or glob tool. Trawling a tree is exactly what CodeMesh replaces. - Never intercepted by default:
cat,head,tail,ls. The agent already knows the path, so a round trip only adds latency. - Only inside synced repositories. Outside them CodeMesh has no answer, so the guard stays out of the way.
- A
grepafter a pipe is filtering, not searching, and is left alone. - It always yields. After 3 consecutive CodeMesh failures on the same question, local search unlocks for that question automatically. You cannot get stuck.
- It fails open. A broken or unreadable guard allows the command through rather than locking an agent out.
Options
codemesh guard on --intercept-file-reads # also intercept cat/head/tail
codemesh guard on --scope everywhere # not just synced repos
codemesh guard on --scope off
codemesh guard on --exclude vendor --exclude distcodemesh guard status shows what is actually armed on this machine, including a
guard the VS Code extension installed.
Asking questions directly
Any subcommand the wrapper does not recognise is handed to the engine, which owns the read surface:
codemesh ontology # how the graph is laid out; read this first
codemesh context "where is auth handled"
codemesh answer "why does ingest retry"
codemesh search "resolveCliBinary"
codemesh fetch --path src/a.ts --start-line 20 --end-line 60
codemesh query 'MATCH (f:CodeFile) WHERE f.org_id = $org_id RETURN f.path LIMIT 10'Pick by the shape of the question:
| You want | Use |
|---|---|
| A value, a definition, "what is X" | context |
| A finished, cited answer | answer |
| One exact string or symbol | search |
| A span of a known file | fetch |
| A path, a chain, "what calls X" | query with a graph traversal |
| To know what any of this means | ontology |
These run against whatever repository your working directory is in.
Analytics
codemesh usage # calls, tokens, cost, time, storage, quota
codemesh graph # what is actually in the graph
codemesh activity # recent tool calls, with the queries
codemesh models # per-agent model, which is what makes cost priceablecodemesh usage
Reports six things:
Usage. Total calls, and total time spent inside CodeMesh calls.
Tokens. When the server has measured a baseline, three numbers: what CodeMesh returned, what reading the cited files would have cost, and the difference. The footnote says how many of your calls carry a baseline, because the saving is measured over those and not over all traffic. Without a measured baseline it falls back to a chars/4 estimate and says so rather than implying a saving it cannot support.
Cost. The token counts priced at each agent's own model input rate, as with / without / saved. CodeMesh results arrive as input to the calling agent, so the input rate is the one that applies. Agents with no configured model are priced at a fallback rate and flagged.
Agent run time. Measured wall-clock for complete agent runs that used
CodeMesh, read from local agent transcripts, plus a derived comparison. Only the
"with" figure is measured; "without" is 1.18x that sum plus 4 seconds per run.
The command says so on screen. This is the same derivation the VS Code sidebar
uses, so the two never disagree about the same machine.
Storage. Bytes ingested against your plan cap, with a warning past 90%.
Today's quota. Calls used against the daily cap, or a note that the plan has no cap.
Pricing cost correctly
codemesh models # what is set now
codemesh models set claude claude-opus-5
codemesh models set cursor gpt-5.4
codemesh models unset claudeModel ids are matched by pattern, not by exact string, so vendor prefixes
(us.anthropic.claude-...) and date or tier suffixes still match. codemesh
models shows which pricing family your id resolved to, so you can confirm it hit
what you expected. An unrecognised id is priced at a fallback rate and clearly
labelled rather than silently guessed.
codemesh graph
Total nodes and relationships, then a breakdown by node type and by relationship type. The breakdown is the useful part: it is how you tell a real ingest from one that wrote files and no functions.
This query aggregates over the whole graph, so it is allowed a longer budget than other calls. On a very large graph it can still take some seconds.
codemesh activity
The recent tool calls with their real arguments, row counts and durations. This is the fastest way to confirm an agent is actually using CodeMesh, and to spot slow queries.
codemesh activity --limit 50
codemesh activity --jsonEvery analytics command accepts --json for scripting.
Scope
Scope controls which repositories an agent launched from a given directory is allowed to read.
codemesh scope show
codemesh scope add ~/other-repo
codemesh scope add repo-name
codemesh scope remove ~/other-repoBy default an agent launched in a repository sees that repository only. Granting another one is explicit. This is why the MCP entry launches a local bridge rather than pointing at a remote URL: a remote URL cannot carry the caller's location.
Support
codemesh support # list your tickets
codemesh support new "description" # raise one, with diagnostics attached
codemesh support new "..." --category billing --severity high
codemesh support show <id>
codemesh support reply <id> "more detail"Diagnostics are attached automatically so you do not have to describe your setup.
Diagnosis and teardown
codemesh doctor
The first thing to run when something is wrong. It checks every layer in order: engine binaries, sign-in, account and plan, the daemon, repositories, agents, and whether an agent has actually asked anything yet. It prints the single command that fixes the first problem it finds, marked with an arrow.
codemesh doctor
codemesh doctor --jsonIt also catches version skew between the daemon and the engine bridge, which otherwise fails in confusing ways.
codemesh status
One screen: account, binaries, daemon, repositories, agents, guard. --json for
scripting.
Removing CodeMesh
codemesh logout # stop syncing; keep everything
codemesh disconnect # unwire agents; keep the account
codemesh purge # remove every trace from this machine
codemesh purge --yes # skip the confirmation
npm uninstall -g @codemesh-app/clipurge removes the daemon process, ~/.codemesh (account, credentials, ingest
state, managed clones), agent MCP entries and instruction blocks, git hooks
(restoring any preserved .local originals), and MCP logs.
purge does not touch your code, and does not delete your graph in the cloud.
Command reference
Account
| Command | What it does |
|---|---|
| codemesh login | Browser sign-in or sign-up. Mints a stable API key. |
| codemesh login --no-browser | Print the URL instead of opening a browser. |
| codemesh login --callback-host <host> | Loopback aliases only. A routable address is refused, see Signing in over SSH. |
| codemesh logout | Pause syncing and stop the daemon. |
Repositories
| Command | What it does |
|---|---|
| codemesh sync [path...] | Register and ingest. Defaults to the repo containing the cwd. |
| codemesh sync --watch | Keep the daemon alive and agent configs current. |
| codemesh sync --interval <s> | Watch tick interval. Default 30s, minimum 5s. |
| codemesh sync --here | Every repo directly below this folder. |
| codemesh sync --include-ignored | Also ingest gitignored files. |
| codemesh sync --sync-git-state | Also sync working tree, stash, reflog, remotes. |
| codemesh catchup [path...] | Force a full re-scan. |
| codemesh repos [--all] [--json] | Registered here, or everything your org has. |
| codemesh repos add <owner/name> [--branch <b>] | Clone and register a repo you do not have. |
| codemesh repo enable\|disable [path] | Turn syncing on or off for one repo. |
| codemesh repo set --include-ignored [--all] | Change ingest options. |
| codemesh repo delete-data [path] [--yes] | Schedule permanent deletion of a repo's graph data. |
Agents
| Command | What it does |
|---|---|
| codemesh connect [agent...] | Write the MCP entry and instructions block. |
| codemesh connect --guard | Also install the tool guard. |
| codemesh connect --no-mcp | Instructions only, no MCP entry. |
| codemesh connect --mcp | Force the MCP entry back on. |
| codemesh connect --take-over | Manage an agent the extension owns. |
| codemesh disconnect [agent...] | Remove instructions and guard. Leaves MCP entries. |
| codemesh agents | What is installed and what state it is in. |
| codemesh info [--json] | Endpoints, for any other MCP client. |
Guard
| Command | What it does |
|---|---|
| codemesh guard on | Enforce CodeMesh over local search. |
| codemesh guard on --intercept-file-reads | Also intercept cat, head, tail. |
| codemesh guard on --scope <synced-repos\|everywhere\|off> | Where it applies. |
| codemesh guard on --exclude <path> | Exempt a path. Repeatable. |
| codemesh guard off | Disarm. |
| codemesh guard status | What is actually armed, including the extension's. |
Insight
| Command | What it does |
|---|---|
| codemesh status [--json] | Account, binaries, daemon, repos, agents, guard. |
| codemesh status --watch [--interval <s>] | Live repo sync, repainting every 5s. Local daemon only. |
| codemesh doctor [--json] | Every layer, and the command that fixes the first fault. |
| codemesh graph [--json] | Node and relationship counts, by type. |
| codemesh usage [--json] | Calls, tokens, cost, time, storage, quota. |
| codemesh activity [--limit N] [--json] | Recent tool calls, with the queries. |
| codemesh models [set <agent> <model>\|unset <agent>] | Per-agent model, for pricing. |
| codemesh scope show\|add\|remove [path] | Which repos agents launched here may read. |
Support and teardown
| Command | What it does |
|---|---|
| codemesh support [list] | Your tickets. |
| codemesh support new "<text>" [--category C] [--severity S] | Raise one. |
| codemesh support show <id> | Read one. |
| codemesh support reply <id> "<text>" | Add to one. |
| codemesh purge [--yes] | Remove every trace from this machine. |
Engine pass-through
| Command | What it does |
|---|---|
| codemesh ontology | How the graph is laid out. Read this first. |
| codemesh context "<question>" | One-call answer with the matching source lines. |
| codemesh answer "<question>" | A finished, cited answer. |
| codemesh search "<text>" | Exact text or symbol. |
| codemesh fetch --path F --start-line N --end-line M | Read a span. |
| codemesh query "<cypher>" | Structural query over the graph. |
| codemesh mcp-stdio | The MCP bridge itself. Agents launch this. |
Global flags
| Flag | Applies to |
|---|---|
| --api-url <url> | Any command that talks to the app. |
| --json | Where machine-readable output makes sense. |
| --yes | Skips confirmation on destructive commands. |
Where state lives
Everything is under ~/.codemesh/, shared with the VS Code extension and the
daemon. Nothing is written inside your repositories except git hooks.
| File | Contents |
|---|---|
| credentials.json | The machine's one credential copy, mode 0600. Rotated by the daemon. |
| sync-repos.json | Which checkouts are registered. |
| connect-defaults.json | Non-secret defaults new registrations inherit. |
| guard-config.json | Guard settings, re-read on every tool call. |
| cli-config.json | This CLI's preferences. |
| agent-owners.json | Which client manages which agent. |
| agent-models.json | Per-agent model, shared with the extension's picker. |
| machine-id | Stable machine identifier. |
| hook-state/ | Per-session guard state, 48h TTL. |
| logs/daemon.log | The daemon's running trace. |
| *-guard.cjs | The generated hook scripts. |
If you also use the VS Code extension, the two share all of it. Signing in with either signs in both.
Environment variables
| Variable | Effect |
|---|---|
| CODEMESH_API_URL | Gateway to talk to. Overrides the compiled-in default, overridden by --api-url. |
| CODEMESH_SYNC_BINARY | Absolute path to a codemesh-sync you built yourself. The engine binary is found beside it. |
| CODEMESH_DAEMON_URL | Where to reach the daemon. Defaults to http://127.0.0.1:7077. |
| CODEMESH_SCOPE_ROOT | Pins the scope root for a launched bridge. Set by connect. |
Troubleshooting
Run codemesh doctor first. It names the one thing to fix.
| Symptom | Cause and fix |
|---|---|
| no CodeMesh binary package is installed for <platform> | Unsupported platform, or a partial install. Reinstall, or set CODEMESH_SYNC_BINARY. |
| daemon and bridge come from different builds | Two binaries from different installs. Reinstall so both come from one. |
| sync daemon not reachable | Run codemesh sync. |
| Sign-in redirect never completes | You are on SSH. Use --no-browser and forward the port. |
| --callback-host ... cannot be used | Expected for a routable address. Forward the port instead. |
| Agent still greps instead of asking | The rules are advisory. Turn on enforcement with codemesh guard on. |
| needs reconnect on an agent | Its MCP entry points somewhere stale. codemesh connect <agent>. |
| Cost shows as a fallback rate | No model set for that agent. codemesh models set <agent> <model-id>. |
| An agent is managed by the editor | codemesh connect <agent> --take-over. |
| A repo shows idle but never syncs | Check it still exists on disk, and that it is not disabled. |
Development
npm install
npm run typecheck # this package and the shared core
npm test # unit plus real-subprocess guard behaviour
npm run compile # bundle to out/main.js
npm run platform-packages -- --from <dir> # stage the per-platform binary packages--from <dir> expects <dir>/<platform>-<arch>/{codemesh,codemesh-sync}. Every
binary is verified before staging: it must exist, be non-empty, be executable,
and its architecture is read from the ELF, Mach-O or PE header and checked
against the package it is going into. A byte-grep on a binary is not a freshness
test.
Note that npm install -g <directory> creates symlinks, which changes module
resolution enough that the per-platform binary package becomes invisible. Install
from a npm pack tarball when testing a real install.
License
Proprietary. See LICENSE.
Copyright (c) 2026 Cognochain India Inc. All rights reserved.
