Skip to content
Alpha — private preview. Expect rough edges and breaking changes between releases.

Configuration reference

The manager reads a single YAML file at ~/.config/agentarivm/agentarivm.yml (override with --config <path> or $AGENTARIVM_CONFIG). It is validated at startup and the process refuses to run on a bad config, loudly — a control plane for remote code execution should not start half-configured.

The file is policy: paths, allowlists, cadences, and setup profiles. Repositories themselves live in the manager’s database and are added at runtime with agentarivm project add; the projects: block here only refines them.

This page summarises the sections that matter. Defaults shown are the shipped ones.

real (default) or fake. In fake mode every external adapter — git, GitHub, the agent — is swapped for a deterministic double, giving you an offline development loop.

server:
host: 127.0.0.1 # loopback by default
port: 8787
publicUrl: https://your-host.example:8443 # what pairing tells devices to talk to
tls:
mode: managed # off | managed | files
requireClientCert: true
extraHosts: [] # managed: extra names the server certificate must cover
  • host — loopback by default. Binding anything else while TLS is off is refused at config load, because the misconfiguration looks perfectly healthy from the inside while your tokens are on the wire in cleartext.
  • publicUrl — the origin devices should use. The manager cannot guess this; it is what agentarivm pair prints, so an unset value means a pairing code with no address attached.
  • tls.modeoff (plain HTTP, right for loopback and tests), managed (the manager runs its own private CA, issues its own server certificate and one client certificate per paired device), or files (bring your own certificate, e.g. Let’s Encrypt — set certFile, keyFile and clientCaFile).
  • tls.requireClientCert — on by default whenever TLS is on. This is what turns strangers away during the handshake.
  • trustProxy and allowInsecureBind exist for deployments with their own proxy in front; leave them off unless that describes you.

All required, no defaults — these are decisions about your disk:

paths:
gitRoot: /home/agent/git # canonical clones
worktreeRoot: /home/agent/worktrees # one worktree per session, under here
secretsRoot: /home/agent/secrets # per-project secret files copied by setup profiles
stateDir: ... # the SQLite database
runtimeDir: ... # sockets, runtime files
logDir: ...

Every generated worktree path is checked to remain inside worktreeRoot.

git:
executable: git # absolute path recommended on a deployed machine
signing: off # off | ssh | inherit
# signingKey: ~/.ssh/id_ed25519.pub # required by signing: ssh
# authorName / authorEmail # override commit attribution; usually unset

signing: off is the default deliberately: a global commit.gpgsign=true inherited on a headless machine makes every commit die inside gpg, because pinentry has no terminal to prompt on. ssh is the mode that works unattended.

github:
ghExecutable: gh
requireWritePermission: true # only repos the gh user can push to may be added
expectedAccount: your-login # refused at boot if gh is logged in as anyone else
issueTaskLabel: agent-task # marks an issue as agent work
issueReadyLabel: agent:ready # authorises a session for it
issueWatch:
enabled: false # off by default — see GitHub issue automation
intervalSeconds: 60
allowedActors: [] # empty means NOBODY may authorise via label

Pin expectedAccount: a manager authenticated as the wrong account works perfectly and simply does everything under somebody else’s name. See GitHub issue automation for issueWatch.

exec:
path: /usr/local/bin:/usr/bin:/bin:/home/agent/.local/bin

The PATH given to every subprocess, replacing the inherited one. Not optional in practice on a deployed machine: a daemon inherits a minimal PATH, and tools like gh and claude are shims that call node, which is not on it — they exit 127 with no explanation. Unset means inherit, which is right for a development machine. See Troubleshooting.

agent:
claudeExecutable: /home/agent/.local/bin/claude
permissionMode: bypassPermissions
# maxBudgetUsd: 25 # hard ceiling per session; unset by default
extraArgs: []
stopGraceSeconds: 10
preTrustWorktrees: false

claudeExecutable is the agent itself. The manager runs one claude per session, for as long as the session lives, and talks to it over pipes — so an absolute path matters here more than anywhere else in this file.

permissionMode decides what an agent may do without asking, and the default is a real decision rather than an oversight. An unattended agent cannot answer a permission prompt, and anything short of bypassPermissions stalls it at the first git commit — so the honest options are “let it work inside its own worktree” or “do not run it unattended at all”. The blast radius is the worktree, on a machine whose entire purpose is running agents.

A question the agent genuinely asks still reaches you: it arrives in the app as a card, with whatever answers the agent suggested, and the session waits.

preTrustWorktrees pre-accepts Claude Code’s “is this a project you trust?” dialog for each new worktree. Off by default: the manager runs the agent in print mode, where the dialog is skipped, so this would write to ~/.claude.json before every session for a prompt that cannot appear. Turn it on only if a session ever hangs before producing any output.

session:
allowedModels: [opus, sonnet]
allowedEfforts: [low, medium, high, max]
defaultModel: opus
defaultEffort: high
staleMinutes: 20 # a running session with no activity is flagged
launchTimeoutMinutes: 5 # stuck in `starting` this long → failed
maxConcurrentPerProject: 3

The app can only pick from the allowlists; there is no way to request an arbitrary model.

How often the manager re-reads reality — the trade between a responsive timeline and a machine that spends its day forking git and gh:

poll:
enabled: true
activeSeconds: 5 # a session that changed something recently
idleSeconds: 30 # running but quiet
pullRequestSeconds: 60 # waiting on review
githubSeconds: 30 # floor between GitHub calls per session

A setup profile prepares a worktree before the agent starts:

setupProfiles:
none: {} # must exist; the default for new projects
flutter:
copyFiles: [.env] # copied from secretsRoot/<owner>/<repo>/ into the worktree
setupCommands:
- [flutter, pub, get]
verifyCommands: # the definition of done, written into the prompt
- [flutter, analyze]
- [flutter, test]
timeoutSeconds: 600

Commands are argument arrays, never shell strings — nothing here is ever passed to sh -c.

The projects: block refines repositories already registered (or clones them at boot with bootstrap: true):

projects:
owner/repo:
displayName: My App
components:
- id: app
dir: apps/mobile
profile: flutter