Linux UID/DAC Isolation Operations
This feature requires Linux, systemd, a root helper, and a dedicated UID range that does not conflict with existing accounts. The helper runs different Principals' Agent processes under different UIDs; tasks belonging to one Principal share that UID and its persistent workspace. See the Task model. A normal installation does not install the root helper or enable isolation automatically.
Installation and configuration
Build matching versions of amux, amuxlet, and amux-isolation-helper and install them in one directory. Run amux isolation helper install as the actual service user to obtain sudo commands for review and execution. This example uses service UID/GID 1001. Check the entire UID range for conflicts, then adapt the arguments:
sudo amux isolation helper install \
--service-uid 1001 --service-gid 1001 \
--amux-home /home/amux/.amux \
--socket /home/amux/.amux/isolation-helper.sock \
--uid-range-start 700000 --uid-range-end 799999 \
--principal-root /var/lib/amux/principalsThis installs the helper, matching materializer, and systemd unit. The service user's config.toml must use the same socket, UID range, and Principal root:
[isolation]
enabled = true
backend = "auto"
uid_range_start = 700000
uid_range_end = 799999
helper_socket = "/home/amux/.amux/isolation-helper.sock"
mapping_db = "/home/amux/.amux/isolation-mappings.db"
principal_root = "/var/lib/amux/principals"
gc_idle_days = 0Use absolute paths. After amux system restart, check:
amux isolation helper status
amux isolation status
amux system target listConfirm helper readiness, the actual backend, and target capabilities. Namespace/seccomp hardening is configured when installing the helper; restarting the normal system does not reapply helper installation parameters.
Identity and credentials
amux isolation principal create "Alice" --kind human
amux isolation enroll --provider cli --scope local --subject alice --principal <principal-id>
amux agent credential set openai-compat OPENAI_API_KEYWith isolation enabled, new requests must carry an identifiable identity. The CLI stores enrollment tokens securely; running agents use injected actor credentials. Do not put tokens in command arguments, docs, or logs. Identified callers' credentials are stored per Principal, with no fallback to legacy-host secrets when the Hub is unreachable. Shared service identities require explicit authorization through aliases, service membership, or delegation.
New Feishu Sessions also select a process environment from their conversation mode: ordinary topics and singleton Sessions use the host environment (passthrough), while isolated topics use linux-dac. Private chats and groups without their own settings inherit the Bot default. Enabling host isolation does not isolate every Feishu Session. Existing Sessions retain their environment; start a new Session after changing the mode. CLI, Task and other entrypoints continue to follow their existing execution policies.
Shared identities for Feishu singleton Sessions
With Linux isolation enabled, Bot singleton and group singleton Sessions use a shared service Principal. Its alias is service:<bot-profile>, scoped to that Bot's bridge ID. This is the Feishu Bot profile, such as default, rather than an Agent Profile such as builtin/codex. Independent topics use personal Principals; successful topic execution does not provision the shared singleton identity.
On the Hub host, use amux bridge feishu bots and amux isolation alias list to identify the Bot scope and the authorized sender's personal Principal, then create and bind the shared identity:
amux isolation principal create "Bot shared sessions" --kind service
# Use the service Principal ID returned by the preceding command.
amux isolation alias bind --provider feishu --scope <bridge-id> \
--subject service:<bot-profile> --principal <service-principal-id>
amux isolation service-member grant --service <service-principal-id> \
--member <sender-principal-id>If the sender has no personal identity, create a human Principal and bind an alias using the same bridge scope and that sender's open ID for this Bot. Grant service membership only to explicitly authorized senders; the group's shared access mode does not grant execution authority. Identity changes are saved in the Hub's identity database and take effect immediately. The service identity uses its own Principal credentials; supply missing model credentials as indicated by launch errors.
singleton requires service principal alias ... and active sender membership means an alias or membership is missing. Keep isolation enabled, provision the identity, and send a new group input. After switching a test host to Linux isolation, validate both creation and continuation for independent topics and singleton Sessions.
Upgrades, revocation, and cleanup
amux update automatically refreshes an installed helper and its materializer from the same complete release bundle. It uses root or sudo -n, preserves the existing systemd unit (including identity, roots, UID range and hardening), and keeps an inactive service inactive. Matching files and a matching running helper are left alone. It does not install a helper on a machine without one.
Active launches block replacement. An idle helper atomically blocks new launches for the lifetime of the updater; a failed or interrupted updater releases the guard. Older helpers without the guard protocol must be stopped once during a maintenance window after sessions finish and new submissions are paused. Run amux update, then start the helper again; subsequent updates manage the restart. The update then fails before ordinary service restarts; existing isolated sessions continue. Retry amux update after they finish. Missing administrator privileges, incomplete bundles and helper errors also fail the update instead of reporting success. Replacement or startup failures restore the previous binary pair and attempt to recover the previous service. Custom units or systemd drop-ins require an operator-managed upgrade. The explicit amux isolation helper install command remains available for installation and configuration changes. Do not force-stop active launches to replace the helper.
A successful handshake with an older helper does not prove it supports file exchange. The current helper runs its own file worker under the principal UID, independently of the profile materializer version.
amux isolation principal disable <principal-id> prevents further execution and revokes active executions for that identity; persistent accounts and working directories remain. Start with read-only inventory:
amux isolation account list
amux isolation account gc --older-than-days 90Actual GC deletion requires --execute and an exact --confirm-principal; see the CLI reference. Do not edit the mapping DB directly or reuse isolated UIDs.
Helper uninstall preserves accounts and data by default and refuses while active launches exist:
sudo amux isolation helper uninstall --amux-home /home/amux/.amux \
--socket /home/amux/.amux/isolation-helper.sock--force terminates active executions. Set isolation.enabled=false and restart the system to use the ordinary backend for new executions. Saved linux-dac objects are not rewritten to passthrough; resuming them still requires restoring the helper.
Diagnostics
AMUX_HELPER_UPGRADE_E2E=1 enables TestHelperUpgradeRootIntegration in app/cli. Provide AMUX_TEST_OLD_HELPER_BINARY and AMUX_TEST_HELPER_BINARY with different old/new helper builds and run it as root. The fixture verifies actual replacement, idempotence and failed-start recovery with disposable helper processes. It substitutes systemd control and never changes an installed unit.
The root-only scripts/test-linux-dac.sh includes inbox/outbox exchange under an unused UID, the 30 MB artifact boundary, and rejected privileged files/FIFOs/path escapes. TestArtifactDeliveryLinuxDACL4 is a separate opt-in integration fixture: it uses a disposable helper and real Feishu image/file upload, reply, download and cleanup in a dedicated test chat. Fleet discovery is replaced by an adapter that calls the real helper; it does not start an Agent or a Hub/Runtime daemon. Run it only with explicit test-message authorization, root, an unused numeric AMUX_TEST_FILE_UID, and the matching AMUX_TEST_HELPER_BINARY:
AMUX_ARTIFACT_L4=1 \
AMUX_TEST_FILE_UID=<unused-uid> \
AMUX_TEST_HELPER_BINARY=/path/to/amux-isolation-helper \
AMUX_TEST_FEISHU_CREDENTIAL_FILE=/secure/path/test-bot.json \
AMUX_TEST_FEISHU_CHAT_ID=<dedicated-test-chat> \
go test ./internal/bridge -run '^TestArtifactDeliveryLinuxDACL4$' -count=1 -vThe credential file contains app_id and app_secret; never put its content in test artifacts. The fixture removes its own messages and temporary files and does not modify service configuration or create OS accounts.
systemctl status amux-isolation-helper.service
journalctl -u amux-isolation-helper.service -n 200 --no-pager
amux isolation status
amux isolation account list- Helper unavailable: check the socket, service UID, protocol version, and configuration. Restarting objects pinned to
linux-dacnever silently reduces their isolation. - Hardening degraded: check host namespace/seccomp support and the actual UID/DAC backend.
- Agent cannot execute: check Principal UID access to every directory in the binary path and symlink target. Install shared programs in suitable system paths instead of relaxing permissions on the entire service account HOME.
- Credentials unavailable: verify the current Principal and variables declared by the selected Profile; repair through credential commands.
- Helper crash: inspect active processes and
isolation_lost, restore the helper, and explicitly restart affected Sessions.
The offline code check is scripts/check.sh. On a dedicated Linux test machine, you may additionally run sudo -E scripts/test-linux-dac.sh. It creates temporary high UIDs and accounts and must not be run as an ordinary local check.