> For the complete documentation index, see [llms.txt](https://dotagent.avelino.run/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dotagent.avelino.run/getting-started/next-steps.md).

# Next steps

> You have a working agent under the daemon. Pick what's next based on what you want to do.

```mermaid
flowchart TD
    A[Working agent + daemon] --> B{What now?}
    B --> N["Notify when things go wrong<br/>→ notifications"]
    B --> M["Add more agents<br/>→ agents concept"]
    B --> P["Persist output somewhere<br/>→ plugins / sinks"]
    B --> S["Schedule by cron-style<br/>→ agent spec"]
    B --> O["See into the daemon<br/>→ observability"]
    B --> F["Migrate from Fish/cron<br/>→ migration guide"]
    B --> D["Operate the daemon<br/>→ daemon lifecycle"]
    B --> T["Something broke<br/>→ troubleshooting"]
```

***

## Make failures loud

The example in [`first-agent.md`](/getting-started/first-agent.md) already wired a **desktop banner**. The rest of the built-in drivers (`slack`, `ntfy`, `pushover`, `telegram`, `imessage`) follow the same shape — a `[[notifiers]]` block, no plugin install, no subprocess fork:

```toml
[[notifiers]]
driver = "slack"
webhook_url = "${SLACK_WEBHOOK_URL}"
events = ["given_up", "recovered"]
```

Note the `${VAR}`. A Slack webhook URL *is* the credential, and an `agent.toml` lives in a repo — put the value in `~/.config/dotagent/secrets.env` (mode `0600`) and dotagent resolves it at send time. The same holds for `ntfy.token`/`base_url`/`topic`, `pushover.token`/`user`, and `telegram.bot_token`.

→ **Read**: [`concepts/notifications.md`](/concepts/notifications.md) for every driver, per-driver message size caps, the tiered-notify pattern (desktop on every fail, phone only on `given_up`), and rate-limit semantics. [`concepts/secrets.md`](/concepts/secrets.md) covers the secrets file.

***

## Make output go somewhere

A *sink plugin* persists the agent's stdout. Three come pre-installed:

* **`sink-file`** — write to a file (overwrite or append).
* **`sink-roam`** — publish hierarchical content to Roam Research, idempotent via `marker_regex`.
* **`sink-outl`** — same shape as `sink-roam` but targets Outl, with a single batched delete + write call.

```toml
[[on_success]]
plugin = "sink-file"
config = { path = "/Users/me/reports/daily.md", mode = "overwrite" }
```

→ **Read**: [`docs/plugins/sink-file.md`](/built-in-plugins/sink/sink-file.md), [`docs/plugins/sink-roam.md`](/built-in-plugins/sink/sink-roam.md), [`docs/plugins/sink-outl.md`](/built-in-plugins/sink/sink-outl.md), and the overview at [`concepts/plugins.md`](/concepts/plugins.md).

***

## Gate the run on something external

A *preflight plugin* fails the run before spawning the agent. Built-ins:

* **`preflight-warp`** — abort if Cloudflare WARP isn't connected.
* **`preflight-cmd`** — generic: run any command, gate on exit code + stdout match.

```toml
[[preflight]]
plugin = "preflight-cmd"
config = { command = "aws", args = ["sts", "get-caller-identity"], expect_exit = 0 }
```

→ **Read**: [`docs/plugins/preflight-cmd.md`](/built-in-plugins/preflight/preflight-cmd.md), [`docs/plugins/preflight-warp.md`](/built-in-plugins/preflight/preflight-warp.md).

***

## Run it on demand, not only on schedule

Every agent you install is already a callable tool:

```bash
dotagent mcp     # JSON-RPC over stdio, one tool per agent
```

Point Claude Code or Claude Desktop at it and you can ask for any agent by name:

```json
{ "mcpServers": { "dotagent": { "command": "dotagent", "args": ["mcp"] } } }
```

For a chat front end, inbound Telegram hands messages to a dispatcher agent whose stdout goes back to the conversation. Off until you configure it, and it changes the threat model — read [V8](/security/threat-model.md) first.

→ **Read**: [`docs/reference/mcp.md`](/reference/mcp.md), [`docs/concepts/telegram.md`](/concepts/telegram.md), [`docs/concepts/triggers.md`](/concepts/triggers.md).

***

## Schedule like a grown-up

The tutorial used `type = "interval"` for speed. Production agents usually want **cron-style** schedules with weekdays + hours + minute:

```toml
[[schedules]]
id = "daily"
type = "cron"
weekdays = [1, 2, 3, 4, 5]      # Mon-Fri (0 = Sun, 6 = Sat — matches launchd)
hours = [8]
minute = 30
```

Plus retry policy:

```toml
[defaults]
max_retries = 3
retry_backoff_minutes = [5, 15, 30]
stale_after_minutes = 120         # don't bother retrying a stale window
```

→ **Read**: [`reference/agent-spec.md`](/reference/agent-spec.md) for the full manifest schema. [`concepts/agents.md`](/concepts/agents.md) for the patterns (digest / triage / generator / watchdog).

***

## See into the daemon

Out of the box you get structured JSON logs, daily rotation, and a sharded log per agent — zero config. To export traces to Honeycomb / Grafana Tempo / Jaeger / Datadog, two lines of `config.toml`:

```toml
[telemetry]
otlp_endpoint = "https://api.honeycomb.io:443"
```

```bash
export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_KEY"
dotagent reload
```

→ **Read**: [`guides/observability.md`](/guides/observability.md) for log schema, vendor recipes, jq queries. → **Or just tweak retention**: [`guides/config-reference.md`](/guides/config-reference.md).

***

## Add many agents

`agents/<name>/` is one directory per agent. Add a second:

```bash
mkdir -p ~/.config/dotagent/agents/hn-morning
# … drop your agent.toml + entry script …
dotagent doctor                  # validates every agent at once
dotagent reload                  # daemon picks up the new one on next tick
```

For inspiration:

* **`examples/disk-alert/`** — pure-shell agent with tiered notifications
* **`examples/hn-digest/`** — bash agent that calls `claude -p`, with the guards an LLM step needs (see [`guides/llm-agents.md`](/guides/llm-agents.md))
* **`examples/hello-{fish,python,go,rust}/`** — minimal "hello" variants per language
* **The fish framework's gallery** — 9 production agents listed in [`concepts/agents.md#examples-gallery`](/concepts/agents.md#examples-gallery)

→ **Read**: [`concepts/agents.md`](/concepts/agents.md) — patterns, extending, connecting agents.

***

## Migrate from Fish / cron

If you came from the `lib/agent.fish` framework, every concept maps 1-to-1:

→ **Read**: [`guides/migrating-from-fish.md`](/guides/migrating-from-fish.md).

If you came from `cron` (no framework), the pattern is:

1. Move the script body into `agents/<name>/agent.sh`.
2. Write an `agent.toml` that recreates your cron line in the `[[schedules]]` block.
3. Remove the cron entry; let the daemon take over.

There's no separate cron migration guide today — the Fish guide is the closest thing, and `cron` ↔ launchd weekday differences are flagged in [Troubleshooting](/guides/troubleshooting.md#symptom-cron-style-schedule-never-matches).

***

## Operate the daemon

How to install/start/stop/reload across macOS launchd + Linux systemd, with diagnostics for "is this thing on?":

→ **Read**: [`guides/daemon-lifecycle.md`](/guides/daemon-lifecycle.md).

***

## Something broke

A sintoma → diagnostic decision tree covering:

* Daemon won't start
* `doctor` errors
* Agent never runs
* Agent runs but fails
* Notifier / sink not working
* Logs / audit / plugin issues
* Performance

→ **Read**: [`guides/troubleshooting.md`](/guides/troubleshooting.md).

***

## Read the source

When the docs disagree with the code, **the code wins**. Worth bookmarking:

| Question                                                 | Crate / module                                                                                                                   |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| "What does the daemon actually do?"                      | [`crates/dotagent/src/commands/daemon.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent/src/commands/daemon.rs) |
| "How does the runner spawn agents?"                      | [`crates/dotagent-runner/src/lib.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent-runner/src/lib.rs)           |
| "How are heartbeats serialized?"                         | [`crates/dotagent-core/src/heartbeat.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent-core/src/heartbeat.rs)   |
| "How does scheduling math work?" (pure functions, no IO) | [`crates/dotagent-scheduler/src/lib.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent-scheduler/src/lib.rs)     |
| "What audit events exist?"                               | [`crates/dotagent-core/src/audit.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent-core/src/audit.rs)           |
| "What's in `agent.toml`?"                                | [`crates/dotagent-core/src/manifest.rs`](https://github.com/avelino/dotagent/tree/main/crates/dotagent-core/src/manifest.rs)     |

For contributor onboarding: [`CLAUDE.md`](https://github.com/avelino/dotagent/tree/main/CLAUDE.md) at the repo root.

***

## Read the FAQ

Quick answers to the recurring questions ([`docs/faq.md`](/misc/faq.md)):

* Windows? root? cron → dotagent? debug without the daemon? multiple users? sandbox? when is 1.0? why not just cron?

***

That's the menu. Each section above is an entry point into a deeper guide — pick the one closest to what you actually need, and ignore the rest until later.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://dotagent.avelino.run/getting-started/next-steps.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
