Connect reference
What Connect writes and runs on a machine, for security review and fleet
operations. Connect's runtime runs per user, without privilege. Native packages and
system-wide managed-enrollment bootstrap files are installed by IT with administrator
privileges; managed --write also needs privilege for fleet policy. Connect installs no CA
certificates, machine-wide proxy, DNS changes, or kernel extension. 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
CLI state lives in ~/.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/ | Recovery copies of replaced tool output. The re-read policy writes only when emitting a stub. 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. |
hook-policy-state.json | Experimental source-trim counters and bounded session metadata. Stores hashes, handles and tool-call numbers, never file paths or content. Mode 0600. |
hook-policy-observation-gap | A bookkeeping failure is awaiting recovery. The next successful metadata write resets read history and clears the signal; the cumulative gap counter survives. Contains no content. |
The desktop inventory has four categories: the installed app and its bundled engine, the OS login registration, the local profile, and the resident engine process. These are categories, not a four-file limit. Tool integrations, logs, update staging and supporting state remain part of the security inventory.
On macOS 13 or later, login uses Apple's Service Management registration. Windows uses the per-user Run entry; Linux uses the desktop autostart entry. Desktop maintenance runs in the bundled engine on the app's timer, without a separate refresh scheduler. Quitting the app stops renewal until it runs again; it does not remove the login registration. Disabling that registration in OS settings stays effective after reopening the app.
Upgrades retire the old macOS tray job after ownership and native login state are recorded.
A short-lived bundled engine worker survives unloading the old job by using a separate
process group. Interrupted removal leaves a .plist.retiring marker for retry. IT handles
system-wide enrollment bootstrap cleanup
separately from this per-user migration.
The running tray reads the login setting every 15 seconds. Changes are saved and reported when detected; unchanged observations are checkpointed every five minutes. Machines shows the last reported native setting and its original timestamp per user. An observation becomes stale after 15 minutes, even if other seat activity continues. Disabled, unknown and stale login settings do not lower routing compliance. These reports use the existing client key without minting a replacement or running maintenance. The gateway's existing renew-on-use rules still apply when it authenticates that key. Older gateways ignore this additive observation; upgrade the gateway to see it.
Maintenance runs every 30 minutes and immediately on ownership handover. If scheduler teardown fails, retries back off from one to 30 minutes. A successful maintenance pass can authorize teardown-only retries for 30 minutes; after that, maintenance runs again.
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. |
PostToolUseFailure hook | ~/.claude/settings.json | Observes Edit failures for the experimental re-read policy; forwards failures unchanged. |
Lifecycle SessionStart, PreCompact, SessionEnd hooks | ~/.claude/settings.json | Record session lifecycle support and clear experimental re-read records and pending windows. Aggregate counters survive. |
UserPromptSubmit hook | ~/.claude/settings.json | Records a paste beacon for attribution. |
Key-refresh 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.
Claude Code source trims
Managed Claude settings include the source hook in both credential lanes. Deferred SSO and an explicit fleet binary use the command hook. Without a binary, Connect emits a native HTTP hook with the client key read from the host environment, never embedded in the fleet file.
Managed command hooks require current-session retrieval proof and verify the actual handle before emitting a replacement. They keep original output on failure or after two seconds. HTTP hooks currently stand aside because their event cannot prove session retrieval. Existing content-mode controls still govern gateway capture.
HTTP hooks also cannot invoke Claude's apiKeyHelper. If the credential exists only in that
helper, authentication fails open to original output. Local managed --write selects a durable
Connect binary automatically; fleet --print uses only the binary explicitly supplied by IT.
doctor and status --json expose sourceHook: installation is command, http, missing, or
unknown; retrieval is verified, not_seen, or unknown. A recent report appears separately on
the console's Agents row. Missing reports and older gateways never mean a hook is absent.
Two independent experiments live under hookPolicies in the existing Connect profile,
~/.anyray/connect.json (or the legacy ~/.anyray file). Merge these fields into the profile;
keep other settings. No environment variable enables them.
{
"hookPolicies": {
"greenCollapse": false,
"rereadStub": false
}
}
Set only the policy being benched to true. Each hook reads the switches afresh; setting one
back to false stops that policy on the next invocation. Both default to false.
Opt-in repairs older hook settings for future sessions. Re-read stubs require a lifecycle receipt
from this session’s SessionStart or PreCompact hook; an already-running session without one declines.
| Switch | When it can hide output |
|---|---|
greenCollapse | Bash ran a recognized test, lint, build or type-check command, reported numeric exit code zero, and printed a recognizable summary. Keeps the runner's summary lines, warning paragraphs, and all stderr. |
rereadStub | Read returned the same absolute path, offset and limit as an earlier Read in this session, with matching SHA-256 hashes of the whole file and returned region. First and changed reads continue through the shipped hook. |
Green collapse recognizes commands such as go test, golangci-lint run, pytest, vitest,
jest, tsc, cargo test, make test, and eslint, including common package-runner wrappers.
It hides only recognized progress rows. Benchmark, verbose, debug, coverage, duration and reporter
flags decline; unaccounted rows such as asset-size tables also decline.
It accepts cd … && and chains of recognized runners, but declines pipelines, ||, shell
program strings and unsupported syntax. Nonzero, missing, conflicting or interrupted exit status,
or any failure marker (including FAIL, panic, Error, Traceback, not ok, or an assertion diff),
declines to the shipped hook. No recognizable summary also means no collapse.
Every decline preserves the existing digest, gateway and local trim pipeline.
Claude Code 2.1.257 does not send numeric exit status. Green collapse therefore stands down on that client, even when enabled. Synthetic numeric-status tests establish guard behavior, not live savings.
Both policies require the registered Anyray MCP server and a successful anyray_retrieve call
in the bounded main transcript tail,
a successful local tee, and a replacement shorter than the original. Restricted subagents and
unknown contexts decline to the shipped hook. The marker contains retrieve ctx_…; call anyray_retrieve
with that handle for the bytes. These handles resolve through Connect's existing local tee
reader, not the gateway stash. The original stays on the machine under the tee retention rules
above. No extra gateway optimization request runs for policy replacements.
Only native Claude Code Read results qualify for stubs; other result shapes retain the shipped hook behavior on every delivery. The marker refers to your earlier Read of the same file in this conversation. Missing session identity, unreadable files, unsupported Read results, and files over 16 MiB pass through. Records are bounded to 256 reads per session and 64 sessions, with a 24-hour idle expiry checked on use. Compaction and session end remove all read hashes and handles; they do not delete recovery bytes still referenced by transcript markers.
doctor --json and status --json expose hookPolicies and hookPolicyMetrics. Metrics include
greenCollapses, rereadStubs, editFailuresAfterStub, stubsFollowedByEditFailure,
retrievesAfterStub, retrievesAfterCollapse, retrievalMissesAfterPolicy,
completedWindows, censoredWindows, observationGaps, and observationGap. Exact-handle retrievals
and Edit failures are observed for the next five main-transcript tool calls. Subagent calls do not
advance these windows. An Edit failure counts once per Edit and once per affected stub. Compaction or session end before five
calls censors that window. An observation gap invalidates benchmark results. Recovery clears stale read history automatically;
observationGaps preserves the evidence loss after the transient signal clears.
These switches remain off until paired runs beat pass-through beyond the 53% noise floor and the third quartile still saves. Include retrieval calls, cache writes, and long-tail turn counts in the comparison. Fewer output bytes alone do not establish a session saving.
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 organization MCP endpoint) 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 and print one content-free JSON document to stdout. All except directives
write the same 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 directives | Pull and run one pending admin directive. |
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.
Desktop automation also uses persistence --adopt-app --app-path <path> for ownership
handover, persistence --release-app for removal recovery, and managed-enroll --json
for enrollment from the machine's managed settings. persistence keeps stdout empty and
returns 0 on success or 1 on failure; diagnostics go to stderr. managed-enroll --json
is silent when enrollment is skipped and emits enrollment events when it runs. The previous __anyray-persistence, __anyray-managed-enroll and
__anyray-refresh spellings remain aliases for one release.
The tray starts resident --protocol-version 1 once and sends maintenance and status
requests over stdin. Stdout carries versioned newline-delimited JSON events, bounded to
256 KiB per line. A protocol error or an unresponsive child makes status unavailable;
the tray retries with bounded backoff. Ordinary read-only status does not register login
or start maintenance.
On a fleet-managed machine, refresh skips ambient updates. The gateway
compares the seat's reported Connect version with the published release and sends an update
directive through the existing per-seat lane when it is stale. The seat runs the same
checksum-verified, smoke-tested updater as the manual update command within 30 minutes on
supported CLI runtimes. The desktop poll stages app updates and acknowledges them once the
running app is current. Other admin commands take priority while installation is pending; see
desktop updates. 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.
doctor and status --json include sourceTrim.state, read from the verified key on GET /v1/me: unsupported, needs_gateway_upgrade, observing, active, active_no_source_trim, or unavailable. This is successful trim evidence, separate from the local hook invocation/probe check. Support and observation window.