Read without execution
inspect and doctor never invoke target CLIs, skills, hooks, plugins, scripts, or MCP servers.
Security model · v0.2
agentctl separates inspection, observation, planning, and mutation so each command receives only the authority its outcome requires.
inspect and doctor never invoke target CLIs, skills, hooks, plugins, scripts, or MCP servers.
Lifecycle work exposes exact recipes and preconditions. It requires --yes; --dry-run changes nothing.
Uninstall removes the selected CLI distribution—not agent credentials, configuration, sessions, or user data.
Inspection boundary
The inspector reads known global roots, selected top-level configuration, SKILL.md content for hashing, and regular-file metadata under skill scripts/. Symbolic links are not traversed during recursive resource walks. Configuration files larger than 2 MiB are skipped and marked.
Potential credential-like key names and line numbers may appear in reports. Detected values do not.
Observation boundary
agentctl agents list reads static catalog data. agentctl agents status invokes only the selected tool's documented version query, without a shell and with a five-second timeout. Status does not authenticate, update, or run an agent session.
Mutation boundary
Install, update, and uninstall recipes are reviewed arrays in the source catalog. agentctl does not accept arbitrary shell strings or interpolate tool IDs into shell commands. A plan names the channel, desired-state change, exact execution, preservation policy, and all local preconditions.
Without --yes, a mutation exits after printing the plan. Bulk uninstall is unsupported. Unknown uninstall ownership fails closed until the user selects a supported channel.
Native installers
Supported native installers are fetched over HTTPS from static URLs with a 30-second download timeout. Both initial and final redirect hosts must match a static allowlist. Empty, larger-than-1-MiB, timed-out, or non-script responses are rejected. The content is staged privately, hashed with SHA-256, executed with a fixed interpreter and static arguments, then removed.
The hash records exactly what ran; it is not an independent authenticity signature. OpenCode native installation uses its no-PATH-modification option.
Ownership boundary
npm and Homebrew remove their registered packages. Claude native removal is limited to ~/.local/bin/claude and ~/.local/share/claude; ~/.claude survives. OpenCode native invokes its official keep-config and keep-data behavior.
Native removal paths are static and must resolve beneath the selected home. If another executable still resolves after uninstall, verification fails without broadening deletion scope.
Long-running agents
OpenClaw uninstall first invokes its service-only, non-interactive uninstaller and only then removes the npm package. It never selects state or workspace removal. OpenClaw update delegates to its supervised updater so staged package validation, doctor, Gateway handoff, restart, and health verification remain intact.
Hermes native installation is blocked for root, skips setup and browser bootstrap, and receives ~/.local/bin only in the child environment so its installer does not edit shell profiles. Update retains Hermes' pre-update snapshot and rollback behavior; uninstall omits --full so ~/.hermes survives.
Self lifecycle
agentctl self update uses the bounded remote-installer path, the public installer's release checksum, atomic activation, and a post-update version probe. agentctl self uninstall removes only the managed command and version library under the selected home.
Self-uninstall rejects any path outside that home and any library target that contains the canonical root. The Git repository, agent configuration, and credentials are preserved.
Failure evidence
Confirmed lifecycle work writes canonical desired truth before invoking the external package manager or installer. A success receipt is written only after the expected executable state is observed. If the external operation fails, the desired state remains and status exposes the drift for an explicit retry.
agentctl installer
The public agentctl installer downloads a versioned archive and SHA-256 file from the GitHub release, verifies it, installs into a staged version directory, then atomically changes the active symlink. Self-update strips ambient source/version overrides and supplies a minimum-version guard, pinning itself to the canonical channel without silent downgrade. The installer does not edit PATH, shell files, the canonical root, or agent configuration.
A checksum from the same release channel detects corruption but is not an independent signature. Signed build provenance remains a v1 release gate.
Disclosure
Use GitHub private vulnerability reporting for secret exposure, execution-boundary bypass, path escape, configuration deletion, installer compromise, or release-integrity findings.
Do not place exploit details or real configuration in a public issue.