10 KiB
Managed client adoption and containment matrix
This document defines how an operator-installed agent client becomes launchable
inside Glove and which evidence is required before the multi-agent matrix in
future-work.md is complete. Follow the operational sequence
in managed-client-setup.md without broadening these
authority boundaries.
Host configuration is discovery input, not authority
Installing or configuring a client as the Glove service user is not sufficient
for managed launch. Glove deliberately does not inherit the service user's
PATH, home, authentication, sessions, provider/model selection, package-manager
credentials, or arbitrary client settings.
The operator must separately authorize four closures:
- Executable closure — detect the client in an explicit search directory,
then pin a canonical executable and any immutable dependencies in a runtime
template. Package-manager trees that are not safe launch authority must first
be copied with
glove policy stageinto a protected snapshot. - Managed home closure — Glove creates a fresh
/home/agentand projects only adapter-owned configuration and verified Sage skills into the client's native locations. - Credential closure — an owner-protected source file is named only by an opaque secret handle in the controller plan. Linux copies it into a content-versioned lease and mounts the lease at an exact path below the managed home. The original host file and broader host home are never mounted.
- Egress closure — a separate local policy names the exact allowed network targets. A credential does not imply network access, and network access does not imply a credential.
A client configured under user bm therefore becomes usable only after its
executable closure, private-home adapter, credential lease (when needed), and
egress policy have each been reviewed and bound into the Glove policy. This is
intentional: "works on the host" must never mean "inherits host authority."
Supported adapter inventory
All built-in adapters use /home/agent, receive verified Agent Skills bundles,
and are bound to the same Linux managed-session filesystem and resource
lifecycle.
| Runtime | Executable | Native skill root | Adapter-owned environment | Managed configuration | Host-state adoption |
|---|---|---|---|---|---|
codex |
codex |
.codex/skills |
CODEX_HOME=/home/agent/.codex |
Glove writes a minimal trusted-project config.toml; Glove remains the sandbox authority |
None; credentials require an explicit secret mount |
claude-code |
claude |
.claude/skills |
None | None | None; credentials require an explicit secret mount |
pi |
pi |
.pi/agent/skills |
None | Glove generates settings.json from the adopted package snapshot |
Explicit package-closure adoption only; auth, sessions, host settings, model state, and package credentials are excluded |
copilot |
copilot |
.copilot/skills |
COPILOT_HOME=/home/agent/.copilot |
None | None; credentials require an explicit secret mount |
opencode |
opencode |
.config/opencode/skills |
XDG_CONFIG_HOME=/home/agent/.config |
None | None; credentials require an explicit secret mount |
Pi is intentionally different. glove policy adopt-pi reads an explicitly named
host settings file only to select package closure members from an explicitly
named package store. It emits immutable payload snapshots and a generated
managed setting containing relative extension paths plus
enableSkillCommands=true. It does not copy the host settings document.
Operator workflow
For every client:
glove policy detect --search-path /absolute/reviewed/bin --json
glove policy stage \
--runtime <runtime-id> \
--source /absolute/reviewed/bin/<executable> \
--directory /absolute/protected/runtime-root \
--dry-run
# Review, then repeat with --yes.
glove policy generate \
--runtime <runtime-id> \
--executable /absolute/protected/runtime-root/<executable> \
--template-id <runtime-id>-safe
Pi additionally requires a separate adoption preview and confirmed snapshot:
glove policy adopt-pi \
--settings /absolute/reviewed/pi/settings.json \
--package-store /absolute/reviewed/pi/package-store \
--directory /absolute/protected/pi-adoption \
--dry-run
# Review, then repeat with --yes.
Credential source files and egress targets are added only through a separately reviewed policy generation step. Client homes or authentication directories are never valid runtime dependency roots.
Containment evidence matrix
Required means the repository must provide executable evidence for every
supported adapter. Shared lifecycle evidence may be parameterized by runtime ID
when the enforcement code is client-independent. An installed-client probe is
still required to prove the pinned distribution starts through the same path.
| Invariant | Current evidence | Required completion evidence | Status |
|---|---|---|---|
| Explicit executable authority | Runtime-template validation rejects inherited PATH; detection and staging tests cover canonical protected paths |
Keep one shared denial suite and one successful staged closure per distribution shape | Partial |
| Fresh private home | Synthetic Linux managed-session cases cover all five native roots | Parameterized assertion for every adapter that host homes and unrelated client state are absent | Partial |
| Native skill projection | Synthetic Linux cases cover all five skill roots and receipt-bound bundle digests | Retain shared projection assertions for every adapter | Covered |
| Managed environment | Synthetic cases cover Codex, Copilot, and OpenCode variables | Assert exact environment allowlist and absence of representative inherited variables for all five | Partial |
| Managed client configuration | Codex and Pi generated files have focused tests | Assert no unmanaged configuration appears for Claude Code, Copilot, or OpenCode | Partial |
| Pi package adoption | Dedicated snapshot, mutation, ownership, link-count, auth/session exclusion, and generated-settings tests | Keep Pi-specific adoption evidence; do not generalize it into host-home copying | Covered |
| Credential isolation | Generic secret-lease and launch-binding tests cover owner files, private-home targets, and runtime binding | Add a table of reviewed client credential target paths and a no-secret startup probe; real credentials remain outside CI | Partial |
| Egress isolation | Linux no-network lifecycle tests are client-independent | Run the same deny-network probe under every adapter identity; online provider access requires a separate opt-in lane | Partial |
| Tool-policy binding | Session-plan validation binds an allowed tool-policy identifier into the canonical plan | Prove the identifier reaches the Sage/controller authorization boundary; do not claim harness-native tool enforcement that does not exist | Gap |
| Terminal limits | PTY, transcript, input, output, resize, signal, and stop tests cover the shared lifecycle | Parameterize adapter identity in terminal receipt assertions or document the shared binding proof | Partial |
| Cancellation and cleanup | Shared Linux process-tree, cgroup, materialization, and cleanup tests exist | Parameterize each adapter identity and require empty materialization roots after exit/stop | Partial |
| Crash recovery | Session/process identity and journal recovery tests cover the shared lifecycle | Demonstrate that every adapter launch uses the same recoverable session identity and profile digest | Partial |
| Installed client startup | Dedicated container_linux_native_harness_matrix runs --version for Codex, Claude Code, Pi, Copilot, and OpenCode through managed PTYs; a missing harness root is an explicit CTest skip |
Run this lane against a protected root containing every reviewed distribution and retain its receipts/output as deployment evidence | Partial |
| Model-backed smoke | No credentialed provider call is claimed | Optional operator-run lane with dedicated credentials, exact egress, bounded prompt, receipts, rotation, and cleanup; never a required public CI secret | Gap |
Required test lanes
Repository lane
The ordinary test suite remains credential-free. It must cover all five adapter identities with synthetic executables while exercising real Glove enforcement: filesystem projection, private home, environment scrubbing, no-network policy, resource limits, terminal behavior, cancellation, receipts, and cleanup.
Installed-client lane
A dedicated Linux CTest lane receives a protected, prebuilt harness root through
GLOVE_TEST_NATIVE_HARNESS_ROOT. It runs the real installed executables only
through the normal adapter and managed-session path:
GLOVE_TEST_NATIVE_HARNESS_ROOT=/absolute/protected/harness-root \
ctest --test-dir build/dev --output-on-failure \
-R '^container_linux_native_harness_matrix$'
It must:
- include Codex, Claude Code, Pi, Copilot, and OpenCode;
- verify immutable executable/dependency mounts;
- invoke a credential-free command such as
--version; - bind a verified skill projection and private home;
- produce a terminal receipt tied to the launch profile and projection digest;
- enforce resource and output ceilings;
- leave no materialization behind; and
- emit an explicit skip when a client distribution is unavailable.
This lane proves distribution compatibility, not model-provider access.
Operator model-access lane
A model-backed smoke is private deployment evidence. Each client gets a dedicated least-privilege credential, an exact credential target beneath its private home, and an explicit provider egress allowlist. The test uses a bounded prompt, no wallet, no host auth, and no retained host write. Rotate by installing a new owner-protected source, updating the policy to a new handle or content lease, verifying one session, then revoking the old credential.
Completion rule
The future-work.md multi-agent item is complete only when:
- every repository-lane row above is
Covered; - the installed-client lane is a separately visible test and includes all five adapters without silently substituting synthetic clients;
- skipped kernel or missing-distribution probes are reported as skips, not passes;
- a review confirms that client-specific code cannot bypass the shared Linux filesystem, resource, terminal, receipt, and recovery lifecycle; and
- documentation preserves the separation between executable, managed-home, credential, and egress authority.