Mesmer's Cursor integration exports what your agents actually did — prompts, file edits, shell commands, tool calls — over OpenTelemetry, and lands it next to delivered effort in the same AI Usage tab that already reports Claude Code spend. It installs once per machine with a single shell command.
That shapes how three different people roll it out — an individual engineer running one command, an IT team pushing it to a fleet through Rippling, and a platform engineer wiring it into a Cursor Cloud Agent Build. Each gets its own section below, followed by the part worth reading before any of them: exactly what this captures, and what it deliberately doesn't.
An individual engineer: one command, once#
Put the organisation token in the environment that runs the installer, then run the one-liner:
export MESMER_OTLP_TOKEN='<org token>'
curl -fsSL https://mesmer.co/cursor-otel/install.sh | shRestart Cursor — it reads hooks.json at startup — and check that it
worked:
~/.local/share/mesmer-cursor-otel/bin/mesmer-cursor-doctordoctor checks the runtime, the launcher, the hook registration, the
stored credential and the endpoint, and then does the check that actually
matters: whether spans have been delivered to the collector recently. It
prints remediation for whatever's wrong, and it's safe to run as often as
you like.
Requirements, current as of 2026, are deliberately thin: macOS or Linux, x64 or arm64,
/bin/sh, curl and tar. Nothing else — the release ships a vendored,
relocatable CPython, so there's nothing to install from a package manager
on the target machine. The whole runtime occupies about 51 MB on disk
after a roughly 17 MB download.
Re-running the install command later is safe: it's idempotent, upgrades in place, and keeps whatever token is already stored if you don't supply a new one.
From then on it keeps itself current: on every session start it spawns a detached background check that upgrades in place.
A fleet, through Rippling#
We support Rippling MDM. This section describes what to deploy rather than where to click — check Rippling's current documentation for the exact screen; the shape of the deployment itself doesn't change.
It's two pieces, deployed together.
A recurring script policy runs the identical one-liner, with one flag added:
curl -fsSL https://mesmer.co/cursor-otel/install.sh | sh -s -- --scope userThat's the whole policy, and it works unchanged whether Rippling happens to run it as root or as the signed-in user. If nobody is signed in, which is normal right after a machine boots, it exits cleanly without installing anything. That's exactly why the policy has to be recurring rather than one-time: a recurring policy installs the first time it runs after someone actually logs in, and on a shared or multi-account Mac, whoever is signed in when it fires gets their own install.
A configuration profile carries the organisation token, so it never
has to appear in the script, in argv, or in an MDM run-script log.
Download mesmer-cursor-otel.mobileconfig
and edit it — fill in the token and two distinct UUIDs (one for the
profile, one for the settings payload inside it; macOS rejects a profile
that reuses one) and assign it at the device level, not the user level,
since a user-scoped assignment lands somewhere the hook never reads.
| Key | Required | Meaning |
|---|---|---|
MESMER_OTLP_TOKEN | yes | The organisation token — same name as the environment variable a single-machine install uses. Ask the Mesmer team for it. |
Order doesn't matter between the two pieces: if the script runs before the profile lands, the hook is registered and simply exports nothing until it does — nothing breaks and no one is blocked in the meantime.
Cursor Cloud Agents: install during the Build#
The hook installs from the repository's own .cursor/environment.json,
during the environment's Build, with a scope flag that changes how the
file is written:
{
"install": "curl -fsSL https://mesmer.co/cursor-otel/install.sh | sh -s -- --scope cloud-agent"
}Add that after your own install steps if you have any.
The token has to be a team secret or an environment secret, never
a user secret. User secrets are only added when an agent starts, and
aren't available during Builds — which is exactly when the installer
looks for one. Get the scope wrong and the install still "succeeds": it
fails open, logs a warning, and quietly exports nothing from every agent
that boots off that snapshot. The Build log is honest about it either
way — a healthy install prints the version, the hooks path and the
endpoint; a missing token prints warning: no MESMER_OTLP_TOKEN in the environment instead.
Because the Build sequence is strictly ordered — the environment clones
the repository and runs install to completion before it ever snapshots
the disk — there's no window where an agent could load a hook
configuration out from under it.
| Individual / Rippling fleet | Cursor Cloud Agent | |
|---|---|---|
| Hooks file | ~/.cursor/hooks.json (user level) | <repo>/.cursor/hooks.json (project level) |
| Written by | install.sh (--scope user, the default) | install.sh --scope cloud-agent, during the Build |
| Written how | Merged into whatever is already there | Merged into whatever is already there |
| Lifetime | Until you uninstall | Until the next Build |
These two paths are kept deliberately disjoint. Don't commit the
.cursor/hooks.json a Build writes — it's regenerated every time, its
paths are only valid inside that VM, and committing it would make every
teammate's laptop fire the hook a second time.
What actually reaches Mesmer#
Once installed, every repository you open in Cursor is instrumented — work repositories, personal projects, a throwaway clone, all of them — because the hooks are registered once at the user level and fire for every session on the machine regardless of path. The unit of consent here is the machine, not the project.
Every content-capture control upstream exposes is on. Prompts, model
responses, model thoughts, shell commands, tool
calls, tool definitions, file reads and file edits are all exported as
text — as are MCP calls, including the server and tool name, the request
and the result. An MCP call is the one place an agent reaches outside the
repository, so whatever it sends and receives goes too. That's across
every hook event this integration registers — from sessionStart through
shell execution, file edits, tool calls and MCP calls, to stop.
Troubleshooting#
Telemetry stopped arriving. Open Cursor's Hooks output channel and
look for Invalid user config or Failed to parse user hooks configuration. Cursor silently discards an entire hooks.json if it
contains even one unrecognised event key — from any tool, not just this
one — and reports the failure nowhere else. A single bad entry added by
something unrelated disables every hook in the file, ours included.
Remove the offending entry and restart Cursor.
Nothing arrives right after installing. hooks.json is only read at
Cursor startup, so restart it, then run mesmer-cursor-doctor.
A token in your shell can win over what's stored. Credentials resolve
in this order: a managed configuration profile, then MESMER_OTLP_TOKEN
in the environment that launched Cursor, then the stored mesmer.json.
On an unmanaged machine, a MESMER_OTLP_TOKEN left exported in a shell
profile for any other reason will keep authenticating every span with
that value instead of the one you installed with. doctor reports which
source is actually in use.
doctor is the right tool for checking whether telemetry is actually
being delivered — trust its output over anything you inspect by hand.
If it doesn't resolve the issue, reach out to the Mesmer team.
Uninstalling.
~/.local/share/mesmer-cursor-otel/bin/mesmer-cursor-uninstallIt strips Mesmer's entries from hooks.json first, then removes the
install — that order matters, since the hook entries are absolute paths
into the install directory. Unrelated Cursor hooks are preserved.
