# Managed agent client setup This runbook turns an operator-installed Codex, Claude Code, Pi, Copilot, or OpenCode distribution into an explicit Glove runtime. It does not copy the operator's home or make a client usable merely because it runs in the service user's shell. Read the authority model and evidence status in [client-adoption-matrix.md](client-adoption-matrix.md) first. ## Security outcome A ready runtime has four independently reviewed closures: 1. an immutable executable and dependency closure; 2. a newly created `/home/agent` containing only Glove-owned client state; 3. optional credential leases at exact private-home targets; and 4. an exact egress policy, or `no-network`. Keep the first deployment credential-free and offline. Provider access is a separate profile and is never implied by client detection, Pi adoption, or a successful `--version` probe. ## Prepare protected roots Use owner-local roots outside client homes and enrolled projects. The examples assume the Glove service user owns each directory and no other principal can write it. ```sh install -d -m 0700 \ "$HOME/.local/share/glove/harnesses" \ "$HOME/.local/share/glove/pi-adoption" \ "$HOME/.local/share/glove/evidence" install -d -m 0700 "$HOME/.config/glove" ``` Do not use `$HOME/.codex`, `$HOME/.claude`, `$HOME/.pi`, `$HOME/.copilot`, XDG client-state directories, authentication directories, or package caches as runtime dependency roots. ## Detect, stage, and pin each distribution Detection reads only explicitly listed directories and never inherited `PATH`: ```sh glove policy detect \ --search-path /absolute/reviewed/client-bin \ --json ``` For every selected runtime, stage its supported package/interpreter closure into the protected root. Review the dry run before confirming it. ```sh glove policy stage \ --runtime \ --source /absolute/reviewed/client-bin/ \ --directory "$HOME/.local/share/glove/harnesses" \ --dry-run --json # Repeat the identical command with --yes only after reviewing its paths and digest. ``` Generate and inspect the individual runtime entry using only the staged executable or an explicit protected search directory: ```sh glove policy generate \ --runtime \ --executable /absolute/protected/staged/ \ --template-id -safe ``` The adapter fixes the private home and native skill location: | Runtime | Executable | Managed skill location | Glove-owned environment | |---|---|---|---| | `codex` | `codex` | `/home/agent/.codex/skills` | `CODEX_HOME=/home/agent/.codex` | | `claude-code` | `claude` | `/home/agent/.claude/skills` | none | | `pi` | `pi` | `/home/agent/.pi/agent/skills` | none | | `copilot` | `copilot` | `/home/agent/.copilot/skills` | `COPILOT_HOME=/home/agent/.copilot` | | `opencode` | `opencode` | `/home/agent/.config/opencode/skills` | `XDG_CONFIG_HOME=/home/agent/.config` | Arguments, environment, and read-only dependencies are part of the local runtime digest. A Sage plan can select only the resulting template ID and digest; it cannot replace those fields. ## Adopt Pi packages without adopting Pi identity Pi is the only built-in adapter with a package-adoption step. Use an explicitly reviewed settings file and package store, then inspect the snapshot before confirming it: ```sh glove policy adopt-pi \ --settings /absolute/reviewed/pi/settings.json \ --package-store /absolute/reviewed/pi/package-store \ --directory "$HOME/.local/share/glove/pi-adoption" \ --dry-run --json # Repeat with --yes only after reviewing selected packages, paths, and digests. ``` The result contains immutable package payloads and generated managed settings. It excludes host authentication, sessions, provider/model selection, host settings, package-manager credentials, and arbitrary Pi state. Never place `auth.json` or a host Pi home in the adoption root. ## Generate the credential-free policy first Build the full policy from the same reviewed roots. Omit `--secret` and `--egress` for the baseline so the generated runtime remains credential-free and uses `no-network`. ```sh glove setup policy \ --search-path /absolute/protected/staged/bin \ --harness-root "$HOME/.local/share/glove/harnesses" \ --path-root /absolute/enrolled-project-root \ --output "$HOME/.config/glove/session-policy.json" \ --backend linux_production \ --runtime codex \ --runtime claude-code \ --runtime pi \ --runtime copilot \ --runtime opencode \ --pi-settings /absolute/reviewed/pi/settings.json \ --pi-package-store /absolute/reviewed/pi/package-store \ --pi-adoption-root "$HOME/.local/share/glove/pi-adoption" \ --dry-run --json # Review the complete output, then repeat with --yes. glove policy validate --file "$HOME/.config/glove/session-policy.json" glove policy explain --file "$HOME/.config/glove/session-policy.json" --json ``` Select only runtime template IDs emitted by that policy when running `glove setup`. Policy replacement is not live mutation: `gloved` freezes the policy for its process lifetime, so restart it only after an approved atomic policy replacement. ## Credential and egress profile Create a separate online policy only after the offline lifecycle passes. A credential source must be an owner-protected regular file outside every client home and enrolled project. The controller receives only the opaque handle. ```sh install -m 0600 /secure/input/client-credential \ "$HOME/.config/glove/-credential.next" glove setup policy \ \ --secret \ "$HOME/.config/glove/-credential.next" \ /home/agent/ \ --egress 443 \ --dry-run --json ``` Repeat `--egress` only for additional exact hosts required by the reviewed client flow. Do not use wildcards, broad private-network access, a host credential directory, or a provider's entire domain family. A credential does not authorize egress, and egress does not authorize a secret handle. Repository-tested credential targets are deliberately narrow: | Runtime | Repository-approved target | Status | |---|---|---| | `codex` | `/home/agent/.codex/auth.json` | Covered by secret-policy, lease, launch-binding, and lifecycle tests | | `claude-code` | none | Operator must verify the exact target for the pinned distribution before enabling a secret | | `pi` | none | Host Pi auth is explicitly excluded; a future model profile must separately approve an exact managed target | | `copilot` | none | Operator must verify the exact target for the pinned distribution before enabling a secret | | `opencode` | none | Operator must verify the exact target for the pinned distribution before enabling a secret | "None" is not permission to mount a directory. Until an exact target gains executable review evidence, that client remains credential-free. ## Rotation and revocation 1. Write a new owner-only source file under a new filename. 2. Generate a dry-run policy with a new handle or content lease. 3. Validate and atomically install the reviewed policy. 4. Restart only `gloved`; do not restart unrelated services. 5. Run one bounded session and verify its plan/profile/receipt digests. 6. Revoke the old provider credential. 7. Remove the old policy handle in the next reviewed policy revision. 8. Retain redacted evidence; never copy credential bytes into logs or receipts. Do not overwrite a live source file in place. Content-versioned leases and an exclusive lock serialize use, but policy revision and provider revocation are still explicit operator actions. ## Validation lanes ### Repository enforcement Run the normal suite plus the Linux managed-session cases. These use synthetic executables and real Glove filesystem, cgroup, terminal, receipt, stop, and cleanup paths. A topology skip is a limitation, not passing enforcement evidence. ### Installed distributions Prepare one immutable test root with this reviewed shape: ```text / node_modules/.bin/{codex,claude,pi,copilot,opencode} node-runtime/bin/ ``` Then run the dedicated credential-free lane: ```sh GLOVE_TEST_NATIVE_HARNESS_ROOT=/absolute/protected/harness-root \ ctest --test-dir build/dev --output-on-failure \ -R '^container_linux_native_harness_matrix$' ``` The lane invokes only `--version`, uses a fresh managed home, binds a verified skill projection, enforces limits, verifies terminal/profile receipts, and requires an empty materialization root after every client. If the variable or a real distribution is absent, the lane must report a skip; synthetic clients must not be substituted. ### Private model smoke For each client, use a dedicated least-privilege credential and exact provider egress. Submit one bounded non-sensitive prompt, disable wallet authority and retained host writes, record plan/session/profile/receipt digests, stop the session, and verify cleanup. This is private deployment evidence, not public CI. Never claim model access from a successful `--version` probe. ## Recovery and evidence checklist Record, without credential contents: - client version and distribution/source digest; - staged closure and Pi-adoption manifest digests; - policy revision, runtime-template ID, and adapter digest; - allowed secret handles and egress policy IDs; - plan, profile, projection, terminal, and resource-receipt digests; - stop/cancellation outcome and empty materialization root; and - skip reasons for missing distributions or unavailable kernel enforcement. After daemon or host recovery, require the same session identity and profile digest before reconciling terminal state. A changed executable, dependency, policy, Pi package snapshot, credential handle, or egress target requires a new reviewed policy revision. Do not resume a session from host client state. ## Current limitations - Repository tests prove shared Glove enforcement; they do not prove every vendor distribution remains compatible. - Missing installed clients are explicit skips, not passes. - Model-backed smoke requires private operator credentials and exact provider egress and is intentionally absent from public CI. - Tool-policy identifiers are plan-bound, but harness-native tool enforcement is not yet a supported claim. - Managed Pi does not gain Sage adapter connectivity until a policy-enforced Sage bridge exists. - Linux resource claims require delegated cgroups and the required mount, namespace, and seccomp capabilities.