Connect reference
What Connect writes and runs on a machine, for security review and fleet
operations. Connect runs per user, without privilege, and installs nothing system-wide:
no CA certificates, no machine-wide proxy, no DNS changes, no kernel extension, no system
daemon, no root (outside the managed --write fleet command). Nothing sits in the request
path: tools call the gateway directly, so Connect never sees their method, path, body, or
response.
What lands on the machine
Everything Connect owns lives in one directory, ~/.anyray/ (override the root with
$ANYRAY_HOME), created mode 0700; the two files holding credentials are written 0600.
| Path | What it is |
|---|---|
bin/anyray-connect | The managed standalone binary. Every hook, MCP registration, and service points at this one stable launcher. |
versions/<version>/ | Previously installed versions, kept so an update can roll back. |
connect.json | This machine's profile: gateway address, your name and team, which tools are configured. Mode 0600. |
dev-key.pem | The device private key that proves this machine's identity when renewing your gateway key. Mode 0600, never logged or printed. |
logs/connect-refresh.log | Captured output from scheduled key renewal, where installed. Error names only, no request data. macOS only; Linux logs to journald. |
vscode-extension/, vscode-receipts/ | The bundled Anyray VS Code extension and a receipt per applied install. |
openclaw-plugin/ | The OpenClaw plugin. The Anyray repository is private, so Connect is its distribution channel. |
hook-tee/ | Untrimmed copies of tool output the PostToolUse hook trimmed, so the full output: Read … footer it wrote still resolves. Owner-only, never uploaded, kept 30 days after the last reference, 90 days at the outside, and 128 MiB in total. ANYRAY_HOOK_TEE=off disables it. |
hook-cache.json | Optimization verdicts for outputs already seen, so a repeat skips a second round trip. 24 hours, 200 entries. ANYRAY_HOOK_CACHE=off disables it. |
Seams inside your tools
Beyond each tool's base URL and key, these are the named seams Connect writes. Each carries an
ownership marker, so a re-run is idempotent and --revert removes exactly what Connect added,
leaving anything it doesn't own untouched.
| Seam | Where | What it does |
|---|---|---|
PostToolUse hook | ~/.claude/settings.json | Trims oversized tool output at the source, before it enters the transcript. Size-gated inside the hook. |
UserPromptSubmit hook | ~/.claude/settings.json | Records a paste beacon for attribution. |
SessionStart hook | ~/.claude/settings.json | Subscription mode only: re-mints a short-lived key at session start, so it can't lapse mid-session. Runs async, never delaying startup. |
anyray MCP server | ~/.claude.json under mcpServers | The retrieval server, described below. Re-invokes the same binary over stdio. |
| Cursor hooks and MCP | ~/.cursor/hooks.json, ~/.cursor/mcp.json | Cursor's native Team mode: the local Shell, Read, and MCP optimization seams, plus the same anyray retrieval server. |
| Managed shell block | ~/.zshrc, ~/.bashrc, or ~/.profile | Base-URL environment variables, fenced by # >>> anyray connect >>> and # <<< anyray connect <<< so the rest of your profile is never rewritten. |
| VS Code extension | VS Code's own extension store | Installed from the bundled VSIX through the VS Code CLI; its credential goes to VS Code SecretStorage, not to a file. |
The retrieval MCP server
The retrieval server is what makes an optimizer trim reversible: where a strategy replaces
bulk with an opaque ctx_… handle, these are the read paths that fetch the detail back.
Every client gets anyray_retrieve and anyray_recall, plus anyray_history where that
archive has content. Clients whose native search and read output cannot use Anyray's
replacement hook also get anyray_search and anyray_read. Claude Code does not advertise
those two context tools: its native Grep and Read already pass through the PostToolUse
optimizer, so a fresh session does not duplicate its first-turn exploration through MCP.
After initialization, the stdio server sends a content-free liveness heartbeat every 5 minutes until the transport closes. The gateway expires that evidence after 6 hours without verified activity, so a stopped server automatically disables fresh handle-producing strategies.
| Tool | What it does |
|---|---|
anyray_retrieve | Fetch the full original behind a known ctx_… handle. |
anyray_recall | Search the durable stash semantically when the handle has scrolled out of view, returning ranked handles. |
anyray_search | Search the local workspace and return file:line candidates, ranked and trimmed against the query. |
anyray_read | Read a workspace file, returned as a relevant slice the model can top back up rather than a lossy cut. |
anyray_history | Search your own past context. Advertised only where that archive has content. |
Every result is capped before it leaves the MCP server. If a read reaches the limit, it stops
at a line boundary and names the next startLine; a search drops the lowest-ranked tail and
reports how many matches were omitted. This prevents an MCP host from rejecting the entire
result before the gateway hook can optimize it.
Background services
On a default seat, Connect installs no background service at all: a gateway key lives 90 days, so nothing can expire under a running tool. A small unprivileged service appears only where your organization issues fast-rotating keys, or on a seat used solely for SDK and shell work. It sends credential data only, and never your prompts or replies. Per-platform service labels, unit-file paths, and how to opt out: Key renewal.
anyray-connect doctor --security-review prints the service names, unit-file paths, outbound
hosts, and the self-updater's full footprint (the release URLs it fetches, the paths it
writes, and the two commands it runs on a freshly downloaded binary) that your security or
endpoint team needs to allow-list. It is derived from the installers themselves, works
offline, needs no key, and says nothing about your traffic. Where that sheet and this page
disagree, trust the sheet.
curl -fsSL https://app.anyray.ai/connect.sh | sh -s -- doctor --security-review
Service keys
An agent host (a CI runner, a bot, a scheduled SDK job) has no person to sign in, so the console mints it a service key instead. Connect runs on that host with the key in the environment and the same headless apply a developer uses:
export ANYRAY_CLIENT_KEY=ark_svc_… # from the host's secret store
curl -fsSL https://app.anyray.ai/connect.sh | sh -s -- --gateway <origin> --yes
Detection picks the installed tools; add --tools shell-env to write only the SDK environment.
What changes on this lane:
- Identity and team come from the key.
--userand--teamare ignored, with a note saying so. - There is no enrollment cert, so nothing refreshes: no background service, no LaunchAgent or scheduled task, and the key is never re-minted on the host. Rotate or revoke it from the console.
- No remote-environment offer, and
--projectis refused: a committed repo config gets its key throughprint-key, which mints from a cert the host does not have. - Tool configs, the retrieval MCP server, and the profile are written as usual, so
doctor,status, and the MCP server all find the key.
doctor titles the credential section Service key (agent), doctor --json and
status --json carry keyKind: "service", and the host sends no seat health report: an agent
is not a seat. A --json apply marks its applied event with the same keyKind.
Connector grants
anyray-connect connectors authorize <name> connects one of the organization's OAuth
connectors (see the org MCP hub) to the developer's own account. It
binds a listener on 127.0.0.1 (a random port, for this run only), asks the gateway to start
the vendor flow with that port and a per-run nonce, opens the consent page, and redeems the
claim code the gateway redirects back with. The redirect carries the nonce's digest and the
listener accepts a code only under it, so a code from someone else's consent pushed at that
port is ignored and the run keeps waiting. stdout carries one line naming the connector and the
account. The claim code, the nonce, the client key, and the authorization URL's query string
never reach either stream; the URL is printed only when no browser could be opened, so the
developer can open it by hand.
| Flag | What it does |
|---|---|
--claim <code> | Redeem a claim code the consent page showed. No listener, no browser. |
--gateway <origin> | Gateway origin, resolved like every other verb. |
In an SSH session, a dev container, or a Codespace the browser cannot reach that listener, so
the command sends no port, prints the URL to open, and asks for a rerun with --claim once the
page shows the code. The same fallback runs when no local port can be bound. A gateway that
predates loopbackPort drops it and shows the code in the browser; Connect sees that in the
reply, says so, and hands over to --claim without waiting. Consent has five minutes; after a
timeout the redirect lands on a closed port, so the hint says to copy the claim= value from the
browser's address bar. Each gateway call has a 30 second budget. Exit codes: 0 connected, 1
not connected (a failure, or any hand-over to --claim that leaves a step to do), 2 usage.
Machine maintenance commands
Fleet and local supervisors call a stable, non-interactive command surface. These commands
accept no prompts, print one content-free JSON document to stdout, and write the identical
evidence to ~/.anyray/status.json with mode 0600.
| Command | Purpose |
|---|---|
anyray-connect reconcile | Pull org tool policy and repair managed drift. |
anyray-connect refresh | Renew credentials when due and re-assert configuration. |
anyray-connect repair | Run the complete repair pass. |
anyray-connect status --json | Print current seat evidence for scripts and policy checks. |
anyray-connect offboard | Revert managed tools, remove resident units, and clear user state. |
Exit codes are stable: 0 healthy or complete, 1 unexpected error, 2 usage error, 3
re-enrollment required, and 4 partial with drift still present. stdout never carries keys,
private key material, SSO tokens, authorization values, or URLs with credentials; diagnostics
go to stderr.
On a fleet-managed machine these commands never invoke Connect's updater or relaunch path on
their own. The gateway compares the seat's reported Connect version with the published
release and sends an update directive through the existing per-seat directive lane when it
is stale; the seat runs the same checksum-verified, smoke-tested updater as the manual
update command, typically within one maintenance cycle of a release. Off the fleet,
refresh keeps the scheduled self-update, because that tick is an unmanaged seat's only
unattended update path.
Claude Code managed policy
For Claude Code, apply and doctor inspect the machine-wide managed-settings.json. They flag
disableAllHooks: true, and flag allowManagedHooksOnly: true when the managed hooks
block does not contain Anyray's PostToolUse hook. Connect never edits IT policy: ask the MDM
owner to remove the key, or to add the credential-free hook block emitted by
anyray-connect managed --print --sso <link> --bin <path>, then restart Claude Code.
Doctor reports this as the separate claude-code / hook_policy fleet check. The failing
statuses are disabled and restricted_dropping_ours; it does not reuse the
network-liveness hook_lane check.
Claude Desktop configuration carry
Third-party inference gives Claude Desktop a separate profile, so the local MCP servers,
user-created skills, and user-installed plugins in the first-party profile are unread until they
are copied across. Every apply lane copies them, MDM reconciles included. MCP servers copy right
away; skills and plugins wait for the next full quit, because Claude Desktop rewrites those stores
on exit. Conversation history moves only through anyray-connect migrate, which reports to the
person whose files they are.
Doctor prints the result under Claude Desktop profile and reports it to the fleet as the
connect / desktop_config_carry check. It is a diagnostic: no state counts against the
compliance score or the failing-check count.
| State | Meaning |
|---|---|
carried | Every local entry is in the third-party profile. |
pending | Some entries are not there yet. Connect carries them on the next reconcile, or the next time Claude Desktop is fully quit. |
nothing_to_carry | The first-party profile holds no local MCP server, user skill, or user plugin. |
not_routed | This machine does not route Claude Desktop through Anyray and nothing is queued to, so no carry applies. Normal on a fleet whose policy holds Desktop back. |
unreadable | The first-party profile refused access. Allow Connect to read it, then run doctor again. |
unsupported | The host has no third-party profile (Linux). |
unknown | No evidence: a status document written before this check existed, or an inspection that failed for a reason other than access. The gateway records the same word for a doctor report from an older Connect. |
Update path variants
Updating an npm install
npx anyray-connect@latest bootstraps the same managed standalone install as connect.sh;
it does not create a second steady-state npm installation. The first enrollment, apply,
repair, or fleet sync that may persist a runtime downloads and verifies the managed binary,
then registers every integration against ~/.anyray/bin/anyray-connect. Later npx runs
leave that launcher in charge.
Existing seats whose hooks or services point at an older version-pinned npm runtime migrate
on their next automatic refresh. Connect smoke-tests the new binary before repointing
registrations and keeps the currently running npm copy as rollback until the migration
succeeds. Run anyray-connect update to migrate immediately, or anyray-connect update --check to preview it.
Inside a devcontainer or Codespace this migration, and self-update generally, is skipped: the image updates by rebuilding, not by downloading a new binary. See Remote and ephemeral machines.
Platforms without a standalone binary
If Anyray does not publish a standalone asset for the current OS and architecture, Connect
keeps the version-pinned durable npm runtime instead. --version, update, and doctor
report that self-update is unavailable; use npx anyray-connect@latest to pick up new
releases on that platform. A copy placed by your IT team remains externally managed and is
still theirs to roll.