How can we help?

What the LLM token tracking install scripts do (security review reference)

Uri Nativ
Uri Nativ
  • Updated
Torii AI

This article is a reference for security and IT teams reviewing the Torii install scripts before approving a rollout. It documents exactly which files get touched, which keys get written, which network calls happen, and which exit codes can occur. The published script bytes (the exact bytes that run on your workstations) are served at https://assets.toriihq.com/otel/latest/<script-name> and the SHA256 manifest is at https://assets.toriihq.com/otel/latest/manifest.json - fetch them with curl and review before approving.

The three guarantees

Every Torii install script, for every tool, on every OS:

  1. Touches exactly one file. The CLI's config file for the resolved user, or the system-wide override file. Nothing else on disk is changed.
  2. Backs up before changing. Any non-empty existing config is copied to <file>.ai-otel-backup-YYYYMMDD-HHMMSS before any write that changes it. The script renders the desired state to a temp file and compares first - a re-run that changes nothing writes nothing and creates no backup.
  3. Owns only its own keys. The merge replaces the Torii-owned env keys (Claude Code), telemetry block (Gemini), or managed-marker block (Codex) and preserves everything else in the file. A re-run - including one that repoints an OTLP endpoint you had set elsewhere - backs the file up first; the timestamped backup is the rollback path.

Network behavior at install time

OS What the install script downloads
macOS Nothing. JSON merges use native osascript -l JavaScript (shipped with macOS since 10.10).
Linux (Claude Code, Gemini CLI) A ~1 MB Go binary (ai-otel-helper) from https://assets.toriihq.com/otel/latest/helper/linux-<arch>.gz, plus its SHA256 sidecar. Verified, gunzipped, used, then deleted on exit.
Linux (Codex CLI) Nothing. The Codex installer is pure awk on a TOML marker-block.
Windows Nothing. PowerShell's native ConvertFrom-Json / ConvertTo-Json handle the JSON merges.

For air-gapped Linux fleets, set HELPER_BASE_URL to point at an internal HTTPS mirror that hosts the helper at the same relative path (/helper/linux-<arch>.gz + .gz.sha256). See Article 5.

Why a Go helper on Linux?

Linux distributions ship without a built-in JSON parser. Torii's install scripts have a strict no-runtime-dependency rule - they can't require jq, python3, or node on the workstation. Pure-shell JSON edits (regex tricks) cannot safely preserve nested objects in a customer's settings.json; they corrupt structures or mangle Unicode.

The helper exists to do JSON merges safely. It's a single statically-linked Go binary (~1 MB compressed, CGO_ENABLED=0, no shared library dependencies). It exposes a tiny vocabulary of mutation subcommands (merge-env, replace-key, delete-env-keys) - all idempotent, all preserving unrelated state.

Claude Code - what the installer writes

Target file (resolved at runtime):

  • Run as root, no --user-scope override: system-wide file
    • macOS: /Library/Application Support/ClaudeCode/managed-settings.d/10-torii-otel.json
    • Linux: /etc/claude-code/managed-settings.d/10-torii-otel.json
  • Run as a non-root user: per-user file
    • macOS/Linux: ~/.claude/settings.json
    • Windows: %USERPROFILE%\.claude\settings.json

Env keys written into the env object:

CLAUDE_CODE_ENABLE_TELEMETRY              "1"
OTEL_METRICS_EXPORTER                     "otlp"
OTEL_LOGS_EXPORTER                        "otlp"
OTEL_EXPORTER_OTLP_PROTOCOL               "http/json"
OTEL_EXPORTER_OTLP_ENDPOINT               "https://ai-events.toriihq.com"
OTEL_EXPORTER_OTLP_HEADERS                "Authorization=Bearer <token>"
OTEL_RESOURCE_ATTRIBUTES                  "host.name=…,host.id=…,enduser.id=…"
OTEL_METRIC_EXPORT_TEMPORALITY_PREFERENCE "delta"
OTEL_LOG_USER_PROMPTS                     "0"  (privacy default)
OTEL_LOG_TOOL_DETAILS                     "1"  (tool + MCP visibility)

Existing keys in env that aren't in the list above are preserved.

What OTEL_LOG_TOOL_DETAILS=1 captures: tool events include the tool name and its input arguments in truncated form - the Bash command line, file paths for read/edit/write tools, MCP server and tool names, and skill names. Individual argument values are truncated at 512 characters and the serialized payload is bounded to ~4 KB per event. It does not capture tool output, file contents, or prompt text - prompts are governed separately by OTEL_LOG_USER_PROMPTS, which stays "0".

Resource attributes captured:

  • host.name - hostname on Linux/macOS; computer name on Windows.
  • host.id - machine-id on Linux (/etc/machine-id or /var/lib/dbus/machine-id); hardware serial on macOS; MachineGuid on Windows.
  • enduser.id - resolved console user (when run as root) or current process user.

Gemini CLI - what the installer writes

Target file: per-user only (Gemini has no system-wide override path).

  • macOS/Linux: ~/.gemini/settings.json
  • Windows: %USERPROFILE%\.gemini\settings.json

Block written (replaces the entire .telemetry key, if any):

"telemetry": {
  "enabled": true,
  "target": "local",
  "otlpEndpoint": "<endpoint>/t/<token>",
  "otlpProtocol": "http",
  "logPrompts": false
}

Why the token is in the URL. Gemini's telemetry block does not currently expose a way to set custom OTLP request headers. To still authenticate ingest, the token rides in the endpoint path component (/t/<token>) and Torii's ingest extracts it server-side and synthesizes the equivalent of an Authorization: Bearer header. Treat the token as a bearer credential - handle it accordingly.

Identity model: Gemini emits user.email only for OAuth-authenticated users. Vertex AI service-account and API-key sessions appear as anonymous (Torii receives only an installation ID). This is upstream Gemini behavior, not a Torii choice.

Codex CLI - what the installer writes

Target file: per-user only.

  • macOS/Linux: ~/.codex/config.toml
  • Windows: %USERPROFILE%\.codex\config.toml

Block written (appended or replaced via marker comments):

# BEGIN AI_OTEL_MANAGED
[otel]
environment = "prod"
log_user_prompt = false
exporter         = { otlp-http = { endpoint = "<endpoint>/v1/logs",    protocol = "json", headers = { Authorization = "Bearer <token>" } } }
trace_exporter   = { otlp-http = { endpoint = "<endpoint>/v1/traces",  protocol = "json", headers = { Authorization = "Bearer <token>" } } }
metrics_exporter = { otlp-http = { endpoint = "<endpoint>/v1/metrics", protocol = "json", headers = { Authorization = "Bearer <token>" } } }
# END AI_OTEL_MANAGED

The # BEGIN / # END AI_OTEL_MANAGED markers define the editable region. Re-running the installer replaces the block between the markers; everything else in config.toml is left untouched.

Backup file naming

Format: <target-file>.ai-otel-backup-YYYYMMDD-HHMMSS. One per config-changing run (only created if the target file existed, was non-empty, and the run actually changed it - converged re-runs create no backup).

The path of each backup file is printed to stderr (backup: <path>) immediately after it's created - useful when collecting script output through MDM agent logs.

Examples:

~/.claude/settings.json.ai-otel-backup-20260520-142315
~/.gemini/settings.json.ai-otel-backup-20260520-142318
~/.codex/config.toml.ai-otel-backup-20260520-142322
/Library/Application Support/ClaudeCode/managed-settings.d/10-torii-otel.json.ai-otel-backup-20260520-142315

The install script never deletes backups. Because no-change re-runs skip the backup, a recurring MDM policy in steady state creates none - you'll see one backup per actual config change (first install, token rotation, script update). Sweep old ones with a separate cleanup script if needed.

Re-runs and pre-existing OTEL config

Earlier script versions refused to write when the target file already pointed OTLP at a non-Torii host (exit code 5, bypassed with --force). Both were removed. The installer now converges: it renders the desired state, compares with what’s on disk, writes only when something differs, replaces only the Torii-owned keys/block, and backs the file up first. If the machine was pointing telemetry at your own collector, a direct install repoints it at Torii - if you want to keep routing through your collector, use the existing-collector path instead of the direct install; the timestamped backup is the rollback if a direct install ran anyway.

Exit codes

Code Meaning
0 Success.
2 Invalid args (missing token, or a malformed endpoint override).
3 Could not resolve target user (when running as root with no console session).
4 JSON parse error reading existing config (Claude Code & Gemini only).
6 Permission denied writing to the target file (Claude Code & Gemini only).
7 --dry-run with intended changes. Not a failure - used to preview.

Flags supported by every install script

All three install scripts (per tool) accept the same set of flags:

Flag Default Meaning
--endpoint <URL> https://ai-events.toriihq.com OTLP endpoint override for relays/staging. The production endpoint is baked into the script - you normally never pass this.
--token <TOKEN> required Ingest token. Also honored via a TORII_TOKEN environment variable when no flag is passed (shell installers, and $env:TORII_TOKEN in the Windows .ps1 installers). The legacy un-prefixed TOKEN name still works.
--environment <name> prod Tag for the events. Useful for staging vs production fleets.
--log-prompts true|false false Privacy default off. If you intentionally want prompt content captured (typically for evaluation), set true.
--user-scope current|<path> current Override the resolved user's home (e.g., for shared-tenant Linux boxes).
--dry-run - Print intended changes; don't write. Exits with code 7 if changes would have happened.
--verbose - Extra non-secret diagnostics on stderr.

Tokens are never logged in full. Verbose mode prints only the last 4 characters of the token on the summary line.

The detect scripts (Intune compliance, etc.)

For each tool/OS combination, there's a matching detect-* script that returns exit 0 + non-empty stdout if the workstation is compliant (Torii config present and pointed at the correct endpoint), and exit 1 otherwise. Intune compliance policies and other MDMs that support detect-then-remediate workflows can pair the detect and install scripts to make the rollout self-healing.

What's in the manifest

The Torii asset host publishes a manifest.json alongside the scripts at https://assets.toriihq.com/otel/latest/manifest.json. It lists every published file with its size and SHA256 hash. Use it to verify the exact byte sequence you're about to ship has not drifted from what you reviewed.

Next steps

Was this article helpful?

0 out of 0 found this helpful

Have more questions? Submit a request