Managed local environments
Start an isolated project environment and manage its service from your host terminal.
Run these commands on your Mac or Linux host with Docker Desktop or a Linux Docker Engine running. Install Convoy on the host. You do not need to enter a container or install the CLI there yourself.
This workflow creates a new managed environment. It does not adopt your existing Multipass VM or an existing VS Code devcontainer. Those keep their current direct CLI workflow. To reach a service on another machine, see remote targets.
Use convoy env as a shortcut for convoy environment, and --env anywhere
you would use --environment. For example, convoy env status --env dev.
On attach, service, project and keys, --target dev also works, the same
flag you use for remote targets.
Start an environment
convoy run --environment dev --no-attachThe first run builds the image with Convoy, Codex, Claude Code, Playwright Chromium and Linux dependencies. Build and provisioning progress appears in your terminal. Later runs reuse the same container and service. To start and stay attached:
convoy run --environment devCtrl+C detaches the viewer. Work continues. A second terminal can attach independently:
convoy attach --environment dev
convoy attach --environment dev --profile b --jsonconvoy run uses the name default when no environment is specified. Other
environment lifecycle commands require an explicit name. The name selects private
host controller state. Without --environment, existing
host profiles and direct CLI commands retain their normal meaning.
Register projects
Projects use the Codex and Claude Code installed in the image. Each start of the
environment reruns the sandbox check, and each project start detects the runtimes
again. CLI 0.110.0 removed environment verify.
convoy project add a --environment dev --profile-key a
convoy project add b --environment dev --profile-key b
convoy project list --environment devThe prompts appear on the host. Select existing projects or choose project
creation. Registration adds the deployment's HTTPS hostname to this environment's
shared firewall allowlist. Convex deployments also allow their MCP .convex.site
hostname. Only the selected project's worker key reaches that project's boundary.
Ordinary host profiles and runtime credentials are not copied.
Folders are created in the container's Linux workspace volume. --clone clones
there. --reuse accepts an existing directory only when its ownership already
matches the registered identity. This workflow does not mount or change ownership
of your host checkout.
For explicit creation, use the same flags as the direct project command:
convoy project add c --environment dev --profile-key c --createAuthenticate a runtime
For OpenAI API usage billing, keep the entire setup on the host:
convoy keys add work-openai --environment dev --provider openai --auth api-key
convoy keys use work-openai --environment dev --runtime codex --profile a
convoy keys use work-openai --environment dev --runtime codex --profile b
convoy service reload --environment dev --profile a --interrupt
convoy service reload --environment dev --profile b --interrupt
convoy keys status --environment dev --jsonThe add command prompts for the key with masked input. Automation can use
--from-env OPENAI_API_KEY or --stdin. Only the supplied key is sent to the
selected service. It is not stored in your host profiles or environment record.
Managed key status, rotation, rollback, disable and removal also accept
--environment. Credential changes never fall back to host writes after a lost
reply. Each project needs an explicit assignment.
For native subscription login instead:
convoy project login a --environment dev --runtime codexIt pauses A, runs codex login --device-auth in A's private shell, then reloads
A and waits until it is online. Add --interrupt if A has active runs. The TUI
offers the same as [i] Log in to Codex in the project's Actions.
Repeat for B. Native runtime authentication stays in each project's private HOME. Centralized subscription sign-in is not added by this phase.
Codex startup errors
If Codex reports that it is not authenticated, run project login above for the
affected project, or assign a managed OpenAI API key.
convoy project check a --environment dev lists every failed precondition with its fix. Logging
in on the host does not authenticate the isolated project. If a managed key is
rejected, check or replace that assignment and reload the project before retrying.
Other startup failures show the exit code or signal and a bounded, redacted
stderr diagnostic. For example, a missing CODEX_HOME is a filesystem problem;
create that directory inside the project's shell. A generic exit with no
diagnostic does not establish that authentication is missing.
Inspect work and browser output
Start a task in each project from the Convoy web app. On the host:
convoy service status --environment dev
convoy service logs --environment dev --follow
convoy service runs list --environment dev --profile a
convoy service runs history THREAD_ID --environment dev --profile a
convoy service runs logs THREAD_ID --environment dev --profile a --message MESSAGE_ID --followReplace THREAD_ID and MESSAGE_ID with IDs printed by the preceding commands.
Operational logs and agent transcripts are separate. Without --follow,
operational logs can also be read after stopping the service while its container
is still running. Transcript --follow follows
one assistant message until its run finishes. attach stays connected across runs.
To run the bundled browser smoke test without entering a shell:
convoy service pause a --environment dev --interrupt
convoy browser smoke --environment dev --profile a --session browser-test
convoy service reload --environment dev --profile a --interruptThe smoke test prints paths to the screenshot, download and browser profile inside
A's private HOME. Agent browser scripts use the same preinstalled browser. Browser
sandboxing defaults on. --no-browser-sandbox is an explicit alternative for a
host where Chromium's nested sandbox is unavailable; the project boundary remains.
Diagnose a stopped service
Run these commands on your host, such as your Mac. Replace dev with your
managed environment name. None of these commands starts or restarts the service.
convoy env status --env dev
convoy service logs --env dev
convoy service logs --env dev --profile a
convoy service logs --env dev | tail -50
convoy service logs --env dev --jsonWithout --follow, the log command prints retained events and exits. tail -50
is a shell command that selects the last 50 output lines, not a Convoy flag.
Add --follow only when you want a live viewer.
| State | What you can inspect |
|---|---|
| Container and service running | Environment status, service status, retained operational logs and run transcripts |
| Container running, service stopped | Environment status and retained operational logs without --follow; no live service connection is required |
| Container stopped | Environment status; Convoy cannot read retained logs from a stopped container yet |
Operational logs record connection states, worker exits, retries and run lifecycle events. They are not a complete crash dump and do not retain raw worker stderr or agent output. A sudden termination may leave no final explanation. Retention is bounded; the reader exposes at most the latest 1,000 events, so older events may be unavailable. Filtered output can contain fewer entries.
For agent output, use convoy service runs history and convoy service runs logs
from the service guide.
Those commands need a running service and fetch stored transcripts from Convex.
They are different from the locally retained operational log.
If the whole container stopped, inspect its stopped state before choosing to run
convoy run --env dev --no-attach. That command starts the container and service,
which can reconnect projects and accept queued work; it is not a read-only log
viewer. The retained log volume survives normal stop/start and rebuild operations.
Stop, restart, update and rebuild
# Stop only the service. Retain the running container.
convoy service stop --environment dev
convoy service start --environment dev -b
# Restart the service without rebuilding the container.
convoy environment restart --environment dev --interrupt
# Stop the service and its managed container. Keep every data volume.
convoy environment stop --environment dev
convoy run --environment dev
# Update only the inner CLI to an exact published version.
convoy environment update --environment dev --version 0.76.1 --interrupt
# Rebuild the image while retaining projects, identities, auth and selected CLI.
convoy environment rebuild --environment dev --interrupt--interrupt explicitly permits stopping current connections and runs. An update
stages its package before stopping work, preserves the previous installation,
refreshes the launcher and browser, and checks service readiness. Failure restores
the previous installation. A later run also recovers an interrupted update.
Browser OS dependency changes require a rebuild. Host convoy update remains a
separate operation.
Inspect both versions and runtime enablement with:
convoy environment status --environment dev --jsonStorage, networking and recovery
Docker volumes hold workspace files, private project identities, control config, service logs, installed CLI packages and browser binaries. Rebuilds retain all of them. Do not remove these volumes independently; identity reservations and private files belong together. No host Docker socket or management port is exposed inside the container.
The controller uses a custom seccomp policy for bubblewrap's nested namespaces and
mounts, and disables Docker's outer AppArmor profile for that container. It also sets systempaths=unconfined to let bubblewrap mount a fresh /proc.
This removes Docker's outer masked/read-only system-path restrictions, including
paths under /proc and /sys. It retains
per-project UID separation, private mounts, cleared capabilities and no-new-privileges.
It never uses a privileged container or adds SYS_ADMIN. Namespace probes fail
closed on unsupported hosts.
The firewall is shared by all projects. You can set the initial deployment and additional domains when first creating an environment:
convoy run --environment other --deployment example-deployment --domains example.com --no-attachProject registration adds backend domains later. Network access is not isolated per project. A different Docker daemon or an ownership mismatch stops the command without modifying the other environment.
A host lifecycle command holds a private lock under
~/.convoy/environments/NAME/lock. Concurrent commands wait. After a crashed host
command, inspect the PID in that directory and confirm the writer has exited
before removing the lock directory. Retrying an uncertain registration must start
with project list and checking Convoy for any newly created remote project.
Never blindly repeat --create after losing its result.
Manual acceptance
Use disposable projects A and B and keep your existing VM unchanged.
- Start
dev, register A/B and assign a managed key or authenticate each natively. Run real agent tasks that write different marker files. Confirm both complete. - Attach in two host terminals, one filtered to A and one to B. Detach A and confirm B and both workers continue. Reattach and inspect run history/logs.
- Ask A to read B's workspace, private HOME and control socket. Reads must fail. Confirm A can still edit its own files and perform browser automation.
- Add C while A/B are connected. Confirm it appears without a rebuild.
- Pause A, run the host browser smoke command, and reload A. B must continue.
- Stop/start the service, then stop/start the container. Confirm stable project UIDs, marker files, native credentials and operational logs.
- Update to an exact available version, then rebuild. Confirm the same identity and data. Try a nonexistent version; package staging must fail while the old service keeps running. Automated tests cover failure after switching packages and crash recovery; record a real failed-health recovery before certification.
- Run two
run --no-attachcommands concurrently. Confirm one container and one service. Stop Docker and check the prerequisite diagnostic.
This workspace has no Docker daemon. Automated controller, bridge and recovery checks are separate from this real-host acceptance.
For an unpublished build, pack the CLI and pass its absolute archive path:
convoy run --environment acceptance --package /path/to/useconvoy-cli-0.76.1.tgz --no-attachThe archive is only used when building a new image. It does not replace an existing installation volume. Use a fresh environment name for an unpublished candidate.
Recover from a nested proc mount failure
If the sandbox check reports bwrap: Can't mount proc on /newroot/proc: Operation not permitted, a container created before CLI 0.76.1 may still have Docker's default
system-path restrictions. Update the host CLI/source checkout and rebuild the
managed container. A service restart does not change these Docker settings.
For an unpublished source checkout, run from apps/cli on your host, using the
source-backed convoy function:
pnpm pack
convoy env rebuild --env test --interrupt --package "$PWD/useconvoy-cli-0.76.1.tgz"The rebuild retains project and authentication volumes and the installed inner
CLI version. This fix is in the host's container-creation options, so the inner
CLI does not need an update. A published installation can omit --package.
If the sandbox check still fails, projects stay stopped; report the output.
Command reference
The environment and project command reference
lists lifecycle, registration, attachment, service, run-history and browser commands.
For managed credential rotation, rollback, disabling and removal, see
model provider keys.
Add --env dev to target this environment rather than the host's configuration.