Setup & Configure
The CLI is served by your Shield360 platform. Get the install key from Settings → Collection & deployment:
curl -fsSL https://app.shield360.ai/api/cli/install.sh | SHIELD360_INSTALL_KEY=<key> sh$env:SHIELD360_INSTALL_KEY = "<key>"iwr -useb https://app.shield360.ai/api/cli/install.ps1 | iexReplace app.shield360.ai with your own address if you self-host. The script installs to ~/.shield360/bin/shield360 (%USERPROFILE%\.shield360\bin\shield360.exe on Windows), enrols the machine, and installs hooks for every coding agent it finds, so the next step is only needed for agents installed later. Coding-agent telemetry is then sent through the machine’s own collector token, and no platform API key is needed on the machine. See Deploy the collector.
shield360 coding install writes the right hook config for the agent you pass and is fully idempotent. You can also point at the plugin marketplace (plugins/ in the Shield360 distribution) and let the agent pull the manifest itself, or invoke the agent through shield360 coding launch which auto-installs and execs.
# One-time installshield360 coding install --vendor=claude-code
# Or run Claude Code through the launcher (auto-installs)shield360 coding launch claude-codeManifest path: ~/.claude/plugins/shield360-cc/. Hooks wired: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest, Stop, SubagentStop, SessionEnd, each with a 5-second time-out. PermissionRequest records that Claude Code asked you to approve a tool call; a PostToolUse for the same call then shows you allowed it (Claude Code does not tell hooks about a denial). Claude Code’s transcript JSONL (transcript_path in the hook payload) is tailed on SessionStart for early model attribution and on SessionEnd for authoritative token usage and cost.
Optional: Claude Code’s native OpenTelemetry exporter. If you’d rather not install the plugin, or you want a second signal source for cross-checking, you can point Claude Code’s built-in OTel exporter at your Shield360 collector instead. Both paths can run side by side - Shield360 dedupes per session.id (Claude Code’s authoritative cost/tokens from the native path win, while the hook path provides the repository/working-folder context that Claude Code itself can’t see).
export CLAUDE_CODE_ENABLE_TELEMETRY=1export OTEL_METRICS_EXPORTER=otlpexport OTEL_LOGS_EXPORTER=otlpexport OTEL_EXPORTER_OTLP_PROTOCOL=grpcexport OTEL_EXPORTER_OTLP_ENDPOINT=$SHIELD360_OTLP_ENDPOINTexport OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer $SHIELD360_API_KEY"# Optional: also enable traces (beta - gives per-tool / per-LLM-turn spans)export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1export OTEL_TRACES_EXPORTER=otlpSee Claude Code’s monitoring docs for the full environment-variable surface (managed settings, dynamic headers, cardinality controls, content-capture gates). When both paths are active, Shield360 folds them into one chat thread automatically.
shield360 coding install --vendor=cursorManifest path: ~/.cursor/hooks.json (user scope - applies to every workspace you open in Cursor; works the same on macOS, Linux, and Windows). All 18 Cursor hook events (sessionStart, sessionEnd, beforeSubmitPrompt, afterAgentResponse, afterAgentThought, preToolUse, postToolUse, postToolUseFailure, subagentStart, subagentStop, beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution, beforeReadFile, afterFileEdit, preCompact, stop), each with a 5-second time-out, invoke shield360 coding hook --vendor=cursor --event=<name> directly. At install time the shield360 token in each command is rewritten to the absolute path of the CLI binary that ran shield360 coding install, which sidesteps the minimal-PATH that GUI-launched Cursor windows inherit on macOS and Linux, and makes the same manifest work on Windows where there is no shell wrapper.
shield360 coding install --vendor=codexManifest path: ~/.local/share/shield360/codex-marketplace/, a local plugin marketplace. Codex does not load plugins dropped into ~/.codex/plugins/, so the install registers the marketplace with codex plugin marketplace add, installs the plugin with codex plugin add shield360@shield360, and then marks each Shield360 hook as trusted in ~/.codex/config.toml (the same [hooks.state."shield360@shield360:…"] records Codex writes when you approve a hook under /hooks), so the hooks run on the next session with nothing to approve. The codex binary is found on PATH, or inside the Codex or ChatGPT desktop app, or under ~/.codex/bin.
Hooks wired: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest (10-second time-out each) and Stop (30 seconds). As with Claude Code, PermissionRequest records that you were asked to approve a tool call. Codex scopes every hook to a turn_id so we emit one coding_agent.llm.turn span per turn (built on Stop), with the prompt, last-assistant message, and the per-tool calls produced during that turn folded into the OTel-canonical gen_ai.input.messages / gen_ai.output.messages envelopes.
The CLI tails ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl on Stop to compute the per-turn token delta (input, output, cached, reasoning) from Codex’s running token_count events, so cost rollups in Shield360 reflect the same per-turn deltas Codex itself records.
Subagent linkage is read from the transcript’s session_meta record at SessionStart; child turns inherit coding_agent.agent.parent_id automatically so the UI folds them under the spawning chat. Codex doesn’t expose a SessionEnd event, so the session row updates incrementally as each Stop lands.
If codex features list doesn’t already enable codex_hooks on your build, add this to ~/.codex/config.toml:
[features]codex_hooks = true
[plugins."shield360"]enabled = trueOlder Codex builds use hooks = true and plugin_hooks = true instead of codex_hooks.
shield360 coding install --vendor=opencode
# Or install and launch OpenCode in one stepshield360 coding launch opencodePlugin path: $XDG_CONFIG_HOME/opencode/plugins/shield360.ts when XDG_CONFIG_HOME is set, otherwise <user-home>/.config/opencode/plugins/shield360.ts. OpenCode automatically loads global JavaScript and TypeScript plugins from this directory at startup, so restart OpenCode after installation.
The plugin projects session lifecycle, completed-assistant metadata, and tool execution into shield360 coding hook --vendor=opencode. Shield360 emits canonical LLM-turn and tool-call spans with coding_agent.client=opencode. Provider-executed tools, which bypass OpenCode’s explicit tool hooks, are recovered from terminal tool-part metadata and deduplicated by call ID.
OpenCode does not expose a terminal SessionEnd hook: session.idle is a turn boundary and can also follow errors or cancellation. Shield360 therefore does not fabricate a completed session root. In metadata_only and full, it records lifecycle events as they arrive. In minimal, it emits non-terminal coding_agent.session.snapshot.start / coding_agent.session.snapshot spans; token and cost values are per-snapshot deltas, while duration and tool count are cumulative. None of these snapshots carries coding_agent.session.outcome.
OpenCode message text, reasoning text, system messages, and structured parts are never exported. Explicit tool arguments and results are included only when SHIELD360_CODING_CONTENT_CAPTURE=full; provider-executed fallback events contain terminal metadata only.
The plugin enforces your organization’s policy the way the Claude Code, Cursor and Codex hooks do. It waits for the hook’s answer on three OpenCode plugin hooks:
| OpenCode hook | What is checked | What a refusal does |
|---|---|---|
chat.message | The text you typed and the paths of attached files: the agent guard, prompt-injection checks and budget limits. The turn is also recorded for sequence policies. | The prompt is not saved or sent to the model. OpenCode reports a failed prompt and the reason appears as a toast. opencode run prints a generic server error; the reason is in OpenCode’s log. |
tool.execute.before | The tool call’s arguments: the agent guard (secrets, secret files, edit rules), prompt-injection checks on arguments and on files about to be read, and sequence policies. | The tool call fails with the reason, which the model and you both see. |
tool.execute.after | The tool’s output: prompt-injection checks, and the result is recorded for sequence policies. | The output is replaced with the reason before the model sees it. In warn mode a notice is added after the output. |
Warnings are shown as toasts in the OpenCode TUI. OpenCode does not let a plugin ask you to approve a call, so an answer that would ask is treated as a refusal. The prompt text is passed to the local shield360 hook to be checked; it is not exported.
The hook has 5 seconds to answer, as in the Claude Code and Cursor manifests. If it cannot be started, crashes, exits with an error other than 2, or does not answer in time, the event goes ahead (fail open), as it does for the other agents; a refusal it wrote before the time-out still counts. Failing closed is decided by the hook: when the organization turned on Block when the policy is unavailable and the policy cannot be read, it exits with code 2 and the plugin refuses. Session lifecycle, completed responses and session snapshots are still sent in the background without waiting.
Re-running the install is idempotent and replaces only shield360.ts; other files in your global OpenCode plugin directory are preserved. The collector also installs it automatically when it finds OpenCode on the machine.
# Copilot CLI and agent mode in VS Code, on this machineshield360 coding install --vendor=copilot
# The Copilot cloud agent, per repositoryshield360 coding install --vendor=copilot --repo /path/to/checkoutManifest path: ~/.copilot/hooks/shield360.json (or $COPILOT_HOME/hooks/). Copilot CLI reads it, and so does agent mode in VS Code, which loads the same folder. Hooks wired: sessionStart, sessionEnd, userPromptSubmitted, preToolUse, postToolUse, postToolUseFailure, agentStop, subagentStart, subagentStop, errorOccurred. If you installed before these were added, run the command again to pick them up.
--repo writes .github/hooks/shield360.json for the cloud agent. See GitHub Copilot for what each surface reports, the cloud agent’s setup, and what cannot be seen.
Run any short coding-agent session, then refresh the Agents page in your Shield360 UI. You should see a new row labelled with the vendor and a “Coding” badge. Click in for the dedicated Overview / Sessions / Users tabs.
Configure
Section titled “Configure”Everything below is a setting you can change at any point after setup - none of it needs to happen up front.
Endpoint, API key, and content capture
Section titled “Endpoint, API key, and content capture”The fastest path is shield360 configure - it answers the same questions a CI / Helm chart would set via env. The result is written to ~/.config/shield360/config.env (Linux/macOS) or %APPDATA%\shield360\config.env (Windows). For headless / fleet rollouts, prefer env vars or flags directly - they take precedence over the file (flags > env > config file).
shield360 configure \ --endpoint https://shield360.example.com:4318 \ --api-key $SHIELD360_API_KEYEquivalent environment variables (precedence: flags > env > config file):
| Variable | Purpose |
|---|---|
SHIELD360_OTLP_ENDPOINT | OTLP/HTTP endpoint of your collector |
SHIELD360_API_KEY | Authenticates the OTLP exporter |
SHIELD360_USER | Optional override for gen_ai.user.name (email or login) |
SHIELD360_CODING_CONTENT_CAPTURE | minimal | metadata_only | full (unset: an enrolled machine follows the organization’s policy, which allows full only when Data retention stores content, so metadata_only by default; a machine with no organization sends full). Can only narrow the organization’s level, never widen it - see Privacy & Governance |
Standard OTEL_EXPORTER_OTLP_* variables are honoured as fallbacks so existing OTel users can reuse their setup. Re-run shield360 configure (or update the env vars) any time - changes apply to the next session, no reinstall of the vendor hooks needed.
Updates
Section titled “Updates”An installed CLI keeps itself current. Once an hour, on the same pass that installs hooks for newly found coding agents, the collector asks the Shield360 server it enrolled with which CLI version it serves. When the versions differ, it downloads the server’s binary for its platform, checks it against the sha256 the server publishes, and swaps it into place. Hooks use the new binary from their next invocation; the background collector restarts itself on it.
Upgrading the server is therefore how the fleet is upgraded. A machine that must stay on a given build can set SHIELD360_SELF_UPDATE=off. A locally built dev binary never updates itself.
Stop tracking / uninstall
Section titled “Stop tracking / uninstall”The inverse of shield360 coding install. Removes the per-vendor host plugin manifests written by install, deregisters the plugin from the vendor’s own CLI where applicable (Claude Code, Codex), and leaves your shared config alone by default so you can re-onboard without re-entering credentials.
shield360 coding uninstall --vendor=cursor # one vendorshield360 coding uninstall --vendor=all # every vendor at onceshield360 coding uninstall --vendor=all --purge # also drop ~/.config/shield360 + session-state cacheshield360 coding uninstall --vendor=cursor --dry-run # preview without touching diskWhat each flag removes:
| Path | Removed by --vendor=<v> | Removed by --purge |
|---|---|---|
~/.claude/plugins/shield360-cc/ | ✓ (when <v> is claude-code or all) | - |
~/.local/share/shield360/claude-marketplace/ | ✓ (when <v> is claude-code or all) | - |
shield360 entries in ~/.cursor/hooks.json (other tools’ entries preserved; file deleted if it ends up empty) | ✓ (when <v> is cursor or all) | - |
~/.local/share/shield360/codex-marketplace/ | ✓ (when <v> is codex or all) | - |
$XDG_CONFIG_HOME/opencode/plugins/shield360.ts when set; otherwise <user-home>/.config/opencode/plugins/shield360.ts | ✓ (when <v> is opencode or all) | - |
claude plugin uninstall shield360-cc@shield360 | ✓ best-effort | - |
codex plugin remove shield360@shield360 + codex plugin marketplace remove shield360 | ✓ best-effort | - |
~/.config/shield360/ (your configure output) | - | ✓ |
<UserCacheDir>/shield360/sessions/ (session-state cache) | - | ✓ |
The shield360 binary itself is not touched. Uninstall it the way you installed it:
brew uninstall shield360 # Homebrewrm ~/.shield360/bin/shield360 # curl|sh installerrm $(go env GOPATH)/bin/shield360 # go installIf you only want to pause a vendor temporarily rather than uninstall it, re-run shield360 coding install --vendor=<v> later - it’s idempotent and will re-wire the same manifest.
Troubleshooting
No row showing up, or hooks running with no spans landing? Start here.