FAQ
Quick answers to recurring questions. If yours isn't here, try Troubleshooting first.
Installation & support
Does dotagent run on Windows?
No. dotagent uses kill(2), osascript, launchd, systemd, and Unix signal handling. WSL works (Linux paths apply). Native Windows is out of scope.
Does it need root / sudo?
No. dotagent runs as your user. The daemon is registered as a user agent (launchd gui/<uid> domain) / systemd user unit. There's no system-wide install, no setuid binary, no privileged helper.
The only step that might surface a prompt is macOS Full Disk Access / Automation entitlement when a sink-file writes into protected dirs (~/Documents, ~/Downloads) or the imessage notifier sends through Messages.app. Those are per-user TCC grants, not root.
Is there a stable release?
Pre-release as of this writing. The CHANGELOG / GitHub Releases page is authoritative.
What's stable:
The
agent.tomlmanifest schema (additive changes only)The plugin protocol (verbs + JSON payload shape)
The heartbeat file shape (compatible with the legacy Fish framework)
What might still move:
config.tomlmay grow new sections.A couple of CLI subcommands are stubs (
bootstrap,plugin invoke).
Will it run on a server (headless)?
Yes, with caveats:
desktopnotifier needs a graphical session (NSUserNotificationon macOS, D-Bus on Linux). Headless? Skip that driver —slack,ntfy,pushoverare pure HTTPS and work fine.imessageis macOS GUI-only.On Linux, enable lingering so the systemd user session survives logout:
loginctl enable-linger $USER.
Multi-user / multi-tenant?
dotagent runs per-user. The state directory is $DOTAGENT_HOME (default ~/.config/dotagent). Two users on the same machine have completely independent daemons, manifests, audits — none shared.
If you need cross-user orchestration, run one daemon per user OR build a thin shared layer (queue, shared filesystem). dotagent isn't a multi-tenant scheduler.
Concepts
Why a daemon and not just cron?
cron runs an entry. dotagent daemon runs and monitors an entry. The difference is whether you can answer "did the 08:30 run succeed?" without writing your own bookkeeping. Specifically, cron can't:
Retry on failure with backoff.
Tell you a window passed without being satisfied.
Notify on
attempt_failed/given_up/stale/recoveredsemantics — including telling you an entry stopped running at all, and saying so again tomorrow if you haven't fixed it.Detect manifest tampering or phantom agents.
Run preflight checks before the body.
Spawn one process per agent without forking the scheduler.
If your task is "run this thing every Monday at 9am, fire-and-forget, don't care what happens" — cron is enough. If you care whether it actually ran, you wanted dotagent (or kubernetes cronjobs, or nomad jobs — same family).
Why not launchd / systemd timers directly?
Same answer as cron, plus a deeper one: dotagent uses launchd / systemd to keep the daemon alive, then does adaptive scheduling itself. That's intentional:
Generates one unit, not one-per-agent. Adding an agent is a
.tomldrop, not a unit-install + reload + boot dance.Adaptive sleep — wake at the next event, not "tick every minute". 100 schedules cost the same as 10.
Per-(agent, schedule) retry policy. launchd has
RetryDelayfor the whole unit; systemd hasRestart=on-failurefor the whole unit. No notion of "this window failed".Cross-platform —
agent.tomlis identical on macOS + Linux. The launchd plist / systemd unit is a generated artifact, not your source of truth.
Why is this not just kubernetes cronjobs?
It is, ish. If you're already on a k8s cluster, k8s cronjobs are fine. dotagent is for the laptop / single-user / on-device version of the same problem — orchestrating personal automations without running k8s on your laptop. Different deployment target, similar shape.
Why is the agent a subprocess and not a library?
Crash isolation. A panic in your agent doesn't take down the daemon.
Polyglot. Fish, Python, Go, Rust, bash, a compiled binary — all first-class. No SDK to import.
No ABI. No
cdylibversioning headaches, no FFI breakage.
Trade-off: fork+exec per run (~5-10ms on Apple silicon). dotagent fires agents on discrete events (a schedule window), not in hot loops, so the cost is invisible.
Why is each notifier in-process but plugins are subprocess?
Different fire frequency:
Notifiers fire on every failure attempt. A 20-retry agent fires the notifier 20 times. fork+exec × 20 + JSON marshal/unmarshal × 20 was real overhead. In-process is faster and removes the dependency on extra binaries on
$PATH.Sinks / preflight fire once per run. The fork+exec cost is invisible.
The plugin protocol stays alive for third-party notifiers (Discord, Teams, etc.) via driver = "plugin" — escape hatch when the built-in drivers don't cover your case.
Why isn't there an LLM SDK?
dotagent runs scripts. The script decides whether and when to call an LLM. This is intentional:
Most "agent" loops don't need an LLM 80% of the time. Pay tokens only when judgment is actually required.
Picking the model / prompt / cost / retry shape is your call, not dotagent's. Lock-in to a vendor SDK is not what you want from an orchestrator.
See concepts/agents.md for the philosophy.
Does dotagent speak MCP?
It serves MCP; it does not consume it.
dotagent mcp exposes every installed agent as a callable tool over JSON-RPC on stdio, so Claude Code, Claude Desktop or any MCP proxy can run your agents. The point is that a model picks from a closed catalog instead of composing a command — a tool name that does not exist is not callable, so "only run what the operator declared" is a property of the protocol rather than a check someone has to remember.
In the other direction nothing changed: dotagent has no MCP client. An agent that wants to reach an MCP server spawns one, the same way it spawns curl. See reference/mcp.md.
Can a message start a run?
Yes, with inbound Telegram configured. It is off by default.
A message reaches a dispatcher agent you name, and that agent's stdout goes back to the chat. dotagent itself interprets nothing — there is no model, provider or prompt in the daemon. What the dispatcher does with the message is its business: hand it to claude -p, or match /disk with a case statement and spend no tokens at all.
This is the one path where someone with no access to your machine can cause a local process to run, so read V8 in the threat model before enabling it. See concepts/telegram.md.
Workflow
Can I debug an agent without the daemon?
Yes — three options:
For (3) you won't get the AGENT_* env vars — write your script to handle empty / unset gracefully if you want this to work.
How do I trigger an agent immediately?
This fires the agent now, ignoring schedule windows. Preflight, sinks, and notifiers all run as usual.
From an MCP client (Claude Code, Claude Desktop) the same thing is a tool call against dotagent mcp. From a chat, it is a message — see concepts/triggers.md for how those differ from a scheduled run.
How do I see what the daemon is about to do?
That next event timestamp is the next agent window. The daemon also wakes for the daily summary and for a 30-minute safety cap, whichever comes first — see What wakes the daemon.
How do I tail logs?
For the daemon's own structured logs:
How do I clear state for a single agent?
dotagent will re-run from scratch on the next dispatch. Your manifests and agent scripts aren't touched.
How do I version-control my agents?
Two patterns:
Pattern A — agents in dotfiles:
dotagent follows the symlink. Your agent stays under git; only the symlink lives in ~/.config/dotagent/.
Pattern B — agents in their own repo:
If you use Nix / home-manager, there's a reference module in avelino/dotfiles that handles discovery + symlinking automatically. See migrating-from-fish.md.
Security
Is dotagent sandboxed?
Not in v0. The [security] block in agent.toml is parsed and dotagent doctor warns on inconsistency, but the runner doesn't enforce allowed_commands / filesystem_writable / network policy.
Sandbox integration (sandbox-exec on macOS / bwrap / firejail on Linux) is on the roadmap. See security/threat-model.md for the full posture and what is defended in v0 (audit log, drift detection, phantom-agent detection, out-of-band notify).
Does dotagent need disk encryption / outbound firewall / etc.?
Yes — see the user-expected layers in the threat model. dotagent is one layer of defense; we assume FileVault / LUKS, Little Snitch / nftables, and a passworded SSH key are in place. Without those, dotagent's audit log lets you reconstruct what happened, but doesn't prevent the attacker from doing it.
What gets sent to third parties?
By default: nothing.
Slack / ntfy / Pushover / Telegram notifiers: only when configured per agent. Each delivery POSTs the agent name + schedule + event + message body to the configured webhook.
OpenTelemetry export: opt-in via
[telemetry] otlp_endpoint. The configured endpoint receives span metadata only (no log bodies yet).iMessage notifier: shells out to
osascript— Apple's privacy policy applies.mcpCLI (if your agent uses it): whatever yourmcpconfig says.
There's no telemetry pinging an Anthropic/Avelino-owned endpoint. No update-check call-home. No analytics.
Can I run plugins I didn't write?
Treat them like any binary you put on $PATH — same trust assumptions. The audit log records every invocation with ok / error and the resolved binary path, so misbehaving plugins are at least detectable after the fact. See V4 in the threat model.
Limits
How many agents can I run?
Soft answer: hundreds, easily, on a modern laptop. The scheduler is adaptive — sleep until the next event, not poll. The bottleneck is fork+exec, which happens only when an agent fires, not on every tick.
Hard answer: there's no internal cap. dotagent has been tested with 9 production agents firing 14+ times/day each.
Can I run a sub-second schedule?
No, and you shouldn't. interval_minutes minimum is 1 minute, and spawn overhead is real (5-10ms × language + runtime). If you need high-frequency work, write a long-running service and don't use dotagent.
What's the max agent timeout?
timeout_seconds: u64 — practical limit is "however long you're willing to wait". Default is 1800 (30 min). Set higher for slow agents (some FinOps reports take 20+ min). dotagent sends SIGTERM, waits 5 seconds, then SIGKILL.
Trivia
Why "dotagent"?
Two reasons:
"dotfiles for agents" — the same convention that turned shell config into version-controllable text turns scheduled automations into version-controllable text.
.(dot) is the smallest unit of file naming. The whole point of dotagent is staying out of the way: agent.toml is small, the binary is one, the daemon is one process. Minimal noise.
Why launchd label "run.avelino.dotagent"?
Reverse-DNS label, same convention Apple uses internally for system agents. avelino because the project was originally personal to one user; the label may genericize before 1.0. The daemon's behavior is unchanged regardless.
Will dotagent run my LLM agents?
It'll run scripts that call your LLM agents. There's no LLM in dotagent itself. See concepts/agents.md for the "script controls, AI analyzes" philosophy.
Is there a UI?
No. dotagent status is the textual dashboard. The structured logs are JSON — pipe to whatever (Grafana / Honeycomb / your dashboard tool). A web UI is not on the roadmap.
Related
Installation — install paths
First agent — zero → daemon
CLI reference — every command
Troubleshooting — sintoma → fix
Threat model — what's defended, what isn't
Last updated
Was this helpful?