apus setup

Apus ships with a built-in system agent — it speaks as "Apus" — for local setup, repair, and configuration (formerly called Crestodian). It starts only after the effective default model completes a real turn. Fresh installs establish inference first; malformed config stays on the classic doctor path.

When it starts

Running apus with no subcommand routes based on config state:

Running apus setup first live-tests the configured default model. A passing turn starts Apus. An interactive failure opens guided inference setup and hands off to Apus after a candidate passes. One-shot, JSON, and other noninteractive requests fail with instructions to run apus onboard when inference is unavailable. apus --help and apus --version keep their normal fast paths.

If inference plugin loading or owner verification fails, the error includes the underlying cause after applying Apus's error redaction. One-shot text and JSON output retain that detail alongside onboarding guidance.

Noninteractive bare apus (no TTY) exits with a short message instead of printing root help: it points to non-interactive onboarding on a fresh or invalid install, or to apus agent --local ... when config is valid.

apus onboard --modern remains a compatibility alias for Apus, but uses the same inference gate: working inference opens the chat, interactive failures start guided inference setup, and noninteractive failures exit with onboarding guidance. apus onboard --classic opens the full step-by-step wizard.

What Apus shows

Interactive Apus opens the same TUI shell as apus tui, with an Apus chat backend. The startup greeting covers:

It does not dump secrets or load plugin CLI commands just to start.

Use status for the detailed inventory: config path, docs/source paths, local CLI checks, key/token presence, agents, model, and Gateway details.

Apus uses the same reference discovery as regular agents: in a Git checkout it points at local docs/ and the source tree; in an npm install it uses bundled docs and links to https://git.apuscorp.com/business/saas/erp/desktop-app/apusami, with guidance to check source when docs are not enough.

Examples

apus
apus setup
apus setup --json
apus setup --message "models"
apus setup --message "validate config"
apus setup --message "setup workspace ~/path/to/work" --yes
apus setup --message "set default model openai/gpt-5.6" --yes
apus onboard --modern

Inside the Apus TUI:

status
health
doctor
validate config
setup
setup workspace ~/path/to/work
config set gateway.port 19001
config unset agents.defaults.fastModeDefault
config set-ref gateway.auth.token env APUS_GATEWAY_TOKEN
gateway status
configure gateway
open gateway wizard
restart gateway
agents
create agent work workspace ~/path/to/work
models
configure model provider
set default model openai/gpt-5.6
channels
channel info slack
connect slack
open channel wizard for slack
configure skills
configure web search
open search wizard
import memory
plugins list
plugins search slack
plugin install clawhub:apus-codex-app-server
talk to work agent
talk to agent for ~/path/to/work
audit
quit

Operations and approval

Apus uses typed operations instead of editing config ad hoc.

For config get, quote record keys that contain dots or brackets, such as config get channels.modelByChannel.telegram["team.ops[west]"]. Config reads redact sensitive values before selecting the requested path.

Read-only operations run immediately: show overview, list agents, list installed plugins, search ClawHub plugins, show model/backend status, run status/health checks, check Gateway reachability, run doctor without interactive fixes, validate config, show the audit-log path.

Starting a guided setup flow also runs immediately: channel setup (connect telegram), workspace skills setup (configure skills), web-search provider setup (configure web search), and local Gateway setup (configure gateway). Each config-backed hosted wizard collects explicit answers and owns the resulting writes; completions append audit entries and re-validate config. A web-search provider that needs a plugin install writes config only after the install succeeds — a failed or timed-out install stops setup and reports it instead of claiming the provider is configured.

configure gateway guides you through the local Gateway's port, bind address, token or password auth, and Tailscale exposure. It saves config without applying it to the running Gateway, because changing the active address or credential could disconnect the setup chat. Say restart gateway after chat setup, or run apus gateway restart after a terminal-wizard handoff. Remote mode is guidance-only: use apus onboard for a fresh setup or apus configure to change the mode.

import memory is copy-only rather than a config write. It detects supported local agent homes, lets you choose the available sources, and copies new memory files into the existing default agent workspace without importing config, credentials, or skills. It requires completed onboarding and reports confirmed imports, nothing-to-import results, provider failures, and failures where some files may already have been copied. No Gateway restart is needed. Use the Control UI's Import Memory page when you need to target another agent or replace an existing import.

In direct Apus chat, persistent operations require conversational approval (or --yes for a one-shot command): write config, config set, config unset, config set-ref, setup/onboarding bootstrap, change the default model, start/stop/restart the Gateway, create agents, and install plugins.

Changes delegated by a regular agent, including requests from messaging channels, follow the requesting run's effective session permission policy. Full Access applies the exact proposed operation automatically, including when Full Access comes from the configured default rather than an explicit session mode. Restricted runs from messaging channels ask for approval in the chat that made the request: channels with native approval cards show Allow once and Deny buttons, and other messaging chats receive the change summary with a /approve <id> allow-once|deny reply. Webchat and terminal runs decide in the Control UI or the Apus apps, which can also decide any chat's approval. Replying "yes" in the delegated chat cannot authorize a change; the button or /approve command does. Channels with their own approver settings decide who may approve; elsewhere only a current owner (commands.ownerAllowFrom) can approve an Apus change. Independent filesystem and sandbox boundaries, tool policy, and the operation restrictions below still apply. The host also checks that the requesting run and verified inference route remain valid. Interactive setup and agent handoffs still require a direct operator session; delegated chat cannot start a wizard, even when a model proposes it.

While a human reviews the proposal, the requesting tool stays open. Allow once applies the exact proposal and returns its application outcome; Deny or expiry returns a non-applied outcome instead of leaving the agent reporting a pending change. Approval requests expire after 10 minutes without a decision. An expired request cannot be approved: if the change is still needed, submit a fresh request and approve it through one of the controls above. Retrying the request alone does not grant approval.

Stopping the requesting run cancels its approval. A late approval cannot restart a closed run. If an approved change fails to complete, check the current settings and Apus status before retrying; approval alone does not confirm that the change was applied.

Configured agents can ask Apus to create another agent through their apus tool. The request enters the same typed create-agent operation and host authorization flow; any approval summary names the requesting agent. Apus remains the executor, and authorized creation records that requesting agent as the new agent's creator.

Delegated creation remains tied to the requesting run. If that run ends or loses authority during preparation, Apus stops before starting the next persistent write. A write already in progress may finish, and workspace files created earlier are not automatically removed. Check apus agents list before retrying from an active run; an agent whose creation already completed is not removed when its requesting run ends.

Doctor repairs are unavailable inside Apus because they can rewrite the provider, authentication, or default-agent inference route powering the session. Exit Apus and run apus doctor --fix in a terminal. Read-only doctor remains available inside Apus.

New agents inherit the live-verified default inference route. The agent ids apus and crestodian are reserved for the system agent and cannot be created as normal agents. The retired id remains blocked so an old config cannot claim it.

config set, config unset, and config set-ref propose config changes for approval. Use config unset <path> to remove an authored setting and let its inherited or runtime default apply. The setup agent uses config_unset with path for the same operation; setting a value to null does not delete it. Approved writes use the existing config validator and writer. Validation or write errors return to the assistant for one corrective proposal, which needs fresh approval. A failure after saving is reported as such. Config writes do not test whether a model route or API key works. Masked setup flows keep keys out of the model's context. If you paste an API key or token in chat anyway, Apus saves it in the shared secret store, points the config key at it with a store SecretRef, and does not echo it back. The pasted message itself already reached the model provider and the transcript; Apus masks the value in later logs and output from that point on. Each save creates a new entry named after the config key plus a random suffix (for example GATEWAY_REMOTE_TOKEN_3F9A0C1B7D2E4A68), so it can never take over a name that another config key, an auth profile, or a stale reference to a removed entry still uses. Apus never overwrites or deletes an existing entry: replacing a key leaves its previous entry in the store. If the config write fails after the key was saved, the error names the saved entry and says whether the config key points at it. The entry is kept either way, since another config key or auth profile may already use it: fix the error and reuse that entry rather than pasting the key again, and remove an entry with apus secrets store rm <NAME> only once nothing uses it. For environment storage, use config set-ref <path> env <ENV_VAR>. set default model <provider/model> still live-tests the route before saving it.

Plugin installation keeps its source restrictions. Plugin uninstall refuses a plugin that backs the active inference route; exit Apus and run apus plugins uninstall <id> from a terminal.

Approval is given in your own words: unambiguous replies ("yes", "sure", "go ahead", "not now") resolve from a closed deterministic list. When the configured route supports a separate completion call, other replies can be classified from only your message and the pending proposal — never by the conversation model itself, which cannot self-approve. Unclassified or ambiguous replies keep the proposal pending and the conversation asks again.

Change history

The Ask Apus page can show recent applied system-agent operations, Doctor migrations, Settings and CLI config writes, and manual edits to apus.json. The config journal detects external edits while the Gateway is watching, during an Apus-owned write, or at the next startup after an offline edit.

History is stored in the diagnostic_events table of the shared ~/.apus/state/apus.sqlite database, under the system-agent-audit and config-audit scopes. Each scope retains its latest 50,000 records. Discovery and read-only operations are not included. Secrets never appear in change history; config journal records contain changed paths rather than config values, and value comparison uses protected fingerprints.

Config-write records retain the writer's origin label when supplied. Automatic startup config repairs record origin: "doctor" even when console output and runtime snapshot refresh are suppressed. Existing unlabeled records are not backfilled.

Channel, web-search, and local Gateway setup can run as hosted conversations until they reach a secret. The local Apus TUI does not accept sensitive wizard answers because terminal chat input is visible. It offers open channel wizard (carrying the selected channel), open search wizard, or open gateway wizard immediately, handing off to the masked terminal wizard; you can also run apus channels add --channel <channel> or apus configure --section web or apus configure --section gateway later.

Switching to a masked terminal wizard

The local chat can hand control to a masked terminal wizard:

open channel wizard for slack
channel info slack
open search wizard
open gateway wizard

open channel wizard for <channel> opens masked channel setup after the chat TUI closes. Use channel info <channel> first for the channel label, setup state, prerequisites summary, and docs link. open search wizard works the same way for web-search provider setup, opening the masked search wizard after the chat TUI closes. open gateway wizard opens masked local Gateway setup; when it finishes, run apus gateway restart to apply the saved settings.

configure model provider directs you to Settings → Models → Connect provider without starting a wizard or changing config. Check the connected Gateway and selected System or agent scope in Settings before signing in, and sign in with the controls there. Connecting another provider does not select it as the active model or require stopping the host. Model selection is separate; replacing credentials for a provider already in use can affect work.

Setup bootstrap

setup configures the remaining workspace and Gateway state after guided onboarding has already established inference. It writes only through typed config operations and asks for approval first.

setup
setup workspace ~/path/to/work

setup preserves the verified effective model. It does not configure or replace inference.

Delegated setup remains tied to the requesting run through configuration, workspace, and session preparation. If that run ends or loses authority, Apus stops before starting the next persistent effect. Earlier completed effects remain, including an agent whose creation already finished; setup may still be incomplete. Check apus agents list and status, then request setup again from an active run and approve the new request, or finish directly with apus setup on the Gateway host. If cancellation deferred legacy history migration for a newly named agent, the next Gateway startup retries it; use apus doctor --fix on the same state/config to finish it sooner.

If inference is missing or its live check fails, leave Apus and run apus onboard. Guided onboarding tries the configured model first, then authenticated subscription CLIs, API keys, and remaining supported CLIs; it asks each candidate for a real reply and persists only a passing route. Apus starts immediately after that boundary and can then configure the workspace, Gateway, channels, agents, plugins, and other optional features.

The macOS app skips this ladder entirely when it reaches a configured Gateway whose default agent already has a configured model; it opens the normal agent UI. For a fresh or incomplete Gateway, the app drives the inference ladder through the apus.setup.detect and apus.setup.activate Gateway methods: detect lists every candidate backend it finds, activate live-tests one candidate (a real "reply with OK" completion), and only persists the model, credential, and provider/runtime state needed for that route after the test passes. Workspace and Gateway defaults remain for Apus. A failing candidate never changes config; the app automatically walks down the ladder and finally offers a manual key/token step populated from the Gateway's active text-inference provider plugins. The selected provider owns its starter model and config, and the credential is verified the same way before it is saved.

Codex supervision and other optional plugin features stay outside this inference activation transaction. Configure them only after inference is working and Apus has started; existing plugin policy and explicit supervision opt-outs remain untouched during inference setup.

AI conversation

Interactive Apus's free-form conversation runs through the same agent loop as regular Apus agents, restricted to one ring-zero Apus authority tool, apus, that wraps the typed operations. Read actions run freely, mutations require your conversational approval for that exact operation (see Operations and approval), and every applied write is audited and re-validated. The agent session persists, so Apus has real multi-turn memory. If the verified inference route later stops working, return to apus onboard and repair it before continuing.

A failed or timed-out turn ends that setup conversation with a visible error. Retrying starts a fresh conversation and live-checks the inference route again.

System-agent turns use agents.defaults.timeoutSeconds, including 0 to disable the deadline, just like ordinary agent turns. The default is 48 hours; there is no separate two-minute cap for setup and repair.

When a regular agent calls its apus tool, it delegates to this system agent through the running Gateway rather than launching the CLI. That adds a separate model turn, so routine session and workspace checks should use the agent's available tools directly. The embedded system helper does not load workspace skill catalogs because it can act only through its built-in system tool.

The host does not parse natural-language requests into operations. Free-form messages — including command-looking text and questions such as "why did my gateway stop?" — go to the AI, which can map the request to a typed operation through the apus tool.

When a mutation is pending, only unambiguous approval or decline phrases from a closed list are resolved without inference. Ambiguous consent goes to a separate configured completion call and otherwise fails closed. Structured wizard fields and exact host navigation are UI controls, not natural-language operation parsing. One secret-hygiene exception is especially important: an exact config set on a sensitive path (tokens, keys, passwords) never reaches a model. The host creates a redacted proposal, and the value is masked in the AI-visible history. Prefer config set-ref <path> env <ENV_VAR> for secrets.

Message-channel rescue mode never uses the model-assisted planner. Remote rescue stays deterministic so a broken or compromised normal agent path cannot be used as a config editor.

CLI harness trust model

Embedded runtimes and the Codex app-server harness enforce the ring-zero restriction directly: the run carries an Apus tool allow-list with only the apus tool. For Codex, Apus also disables environments, native execution, multi-agent, goal, app/plugin, skill/MCP, web-search, request_user_input, and its native planning utility for that run. CLI harnesses do not consume Apus's allow-list, so Apus admits only backends whose own tool-selection contract can prove the same restriction:

Only Apus sessions get the apus MCP server; normal agent runs never see this tool. Selectable/no-native CLI backends and API-key models therefore enforce the literal single-tool loop. Codex app-server models enforce a single Apus authority tool plus the inert native planning utility. In all three cases, setup writes remain confined to Apus's audited approval contract.

Gemini CLI remains available as an explicitly configured runtime for normal agents, but Gemini CLI and Antigravity are not inference-gate setup routes. Use AI Studio API-key or Vertex AI for the inference gate. The optional Gemini CLI runtime specifically requires an AI Studio API-key profile.

Switching to an agent

Use a natural-language selector to leave Apus and open the normal TUI:

talk to agent
talk to work agent
switch to main agent

apus tui, apus chat, and apus terminal open the normal agent TUI directly; they do not start Apus. After switching into the normal TUI, /apus returns to Apus, optionally with a follow-up request:

/apus
/apus restart gateway

Message rescue mode

Message rescue mode is the message-channel entrypoint for Apus: use it when your normal agent is dead but a trusted channel (for example WhatsApp) still receives commands.

This is a deterministic emergency command handler, not the conversational Apus agent. It does not bootstrap a fresh setup or relax the inference gate for Apus chat.

Supported command: /apus <request>. Rescue accepts the exact typed command grammar only — natural language is rejected with a hint, never guessed into an operation, and no model is ever consulted.

You, in a trusted owner DM: /apus status
Apus: Apus rescue mode. Gateway reachable: no. Config valid: no.
You: /apus restart gateway
Apus: Plan: restart the Gateway. Reply /apus yes to apply.
You: /apus yes
Apus: Applied. Audit entry written.

Agent creation can also be queued locally or via rescue:

create agent work workspace ~/path/to/work model openai/gpt-6-astra
/apus create agent work workspace ~/path/to/work

Agent creation may name only the current live-verified default model. Omit the model to inherit that route.

Rescue approval preserves optional agent details such as create agent work purpose "Write release notes" workspace ~/path/to/work. For set default model <provider/model> for agent work, approval keeps the selected agent rather than applying the change to the global default.

Remote rescue is an admin surface and must be treated like remote config repair, not normal chat.

Security contract for remote rescue:

Rescue policy is built in: it is available only when the effective runtime is YOLO, sandboxing is off, and the request is an owner DM. Pending write approvals expire after 15 minutes. apus doctor --fix removes the retired systemAgent and crestodian config blocks.

Remote rescue is covered by the Docker lane:

pnpm test:docker:system-agent-rescue

An opt-in live channel command-surface smoke checks /apus status plus a persistent approval roundtrip through the rescue handler:

pnpm test:live:system-agent-rescue-channel

Inference-gated packaged one-shot setup is covered by:

pnpm test:docker:system-agent-first-run

That packaged-CLI lane starts with an empty state dir and proves Apus fails closed without inference. It then tests and activates fake Claude through the packaged activation module. Only afterward does a fuzzy request reach the planner and resolve to typed setup, followed by one-shot commands that create an additional agent, configure Discord through a plugin enablement plus token SecretRef, validate config, and check the audit log. This lane is supporting gate/operation evidence; it does not exercise interactive onboarding or the Apus agent/tool/approval conversation. The QA Lab scenario below redirects to the same Docker lane:

pnpm apus qa suite --scenario system-agent-ring-zero-setup

Related