Repository navigation
Automation
Nautelle can start agent work without anyone at a keyboard: run a skill on a project, fire it on a schedule, trigger it from an outside system with an inbound webhook, push Nautelle's own events out with outbound webhooks, and learn about GitHub changes instantly through a GitHub App. Every automated start sends the same typed runner command a person would, so it shows up as an ordinary run in history, priced and subject to budgets.
flowchart LR
person["Person: Run"] --> cmd
sched["Schedule<br/>(cron, BullMQ timer)"] --> gate
hook["Inbound webhook<br/>POST /hooks/<id>"] --> gate
gate{"Budget gate"} --> cmd["Typed runner command<br/>skill.run · orchestrator.start"]
cmd --> runner["Runner: own worktree<br/>+ tmux session"]
runner --> out["Report or pull request"]
events["Nautelle events"] --> outhook["Outbound webhooks<br/>signed, retried"]
gh["GitHub App"] -->|"poll now"| runner
A skill is a packaged agent workflow (SKILL.md). Nautelle lets you find, install and run skills per project.
Find and install
- Open Skills (
/skills) and search the public skills.sh catalog. - Pick a skill. The runner shallow-clones its GitHub repository, pins the commit and shows a preview.
- Install it:
-
into a project — the runner opens a pull request on branch
skills/<name>that copies the skill into.claude/skills/<name>/; -
into a runtime profile (admin) — it is copied into the profile's skills directory and every session on that profile loads it. This also needs
skills.profileInstallallowed in the runner's local policy.
-
into a project — the runner opens a pull request on branch
Skills are copied, never installed with npx or symlinked, and each copy records its source, commit and content hash. Project › Skills lists every skill available to the project: installed from the catalog, written by hand, from profiles or from plugins.
Run
- Open Project › Skills, choose a skill and Run.
- Choose the runtime profile, the model, arguments and the output:
- Report — the agent's final message, the changed files and the diff;
- Pull request — the changes are committed and a PR is opened against the project's base branch.
- Watch the live log on the run page (
/projects/<id>/skills/runs/<runId>). An admin can attach to its terminal.
Each run gets its own worktree and tmux session, so it never touches your checkout. Defaults: 60-minute timeout (6 hours maximum) and 2 concurrent runs per runner — more wait in a queue. The orchestrator and worker skills themselves cannot be run this way.
A schedule runs a skill or an orchestrator command on a project at fixed times — a security scan every night, orchestrator next every hour.
- Open Project › Schedules (or Admin › Schedules across projects).
- Choose the target: a skill (with profile, model and output) or the orchestrator (
startornext). - Enter a 5-field cron expression and a time zone.
- Choose the missed-run policy.
| Policy | When the API or runner was down |
|---|---|
skip (default) |
records the missed occurrence as skipped and waits for the next one |
catch_up |
fires once for the newest missed occurrence; older ones are recorded as skipped. Nothing older than 24 hours is caught up |
Rules that keep schedules safe:
- The minimum interval between firings is 5 minutes.
- A schedule never has two live runs: if the previous run is still going, the new occurrence is skipped.
- It fires with its creator's authority at fire time. If the creator is no longer an operator of the project, the schedule is disabled.
- Five consecutive failures disable it.
- Budgets are checked before every firing.
- Run now fires one occurrence immediately without moving the next run.
Schedules are stored in PostgreSQL; BullMQ on Redis provides the timers. Redis holds nothing that cannot be rebuilt from the database. The admin page also lists the API's own system jobs read-only.
Admins manage webhooks under Admin › Integrations.
Integrations › Triggers creates a URL that starts work when an outside system calls it — a CI failure starts a debugging skill, a deploy starts a UX test.
-
POST /hooks/<triggerId>, JSON only, signed:X-Nautelle-Timestamp: <unix seconds> X-Nautelle-Delivery: <unique id> X-Nautelle-Signature: sha256=HMAC-SHA256(secret, "<timestamp>.<delivery>.<raw body>") -
The action is a skill run or
orchestrator nexton one project. Skill arguments may use{{payload.<path>}}placeholders, limited to the paths you allow. -
Limits: 30 accepted deliveries per trigger per hour, one live run per trigger, timestamps within ±5 minutes, replayed delivery ids refused.
-
The caller gets
202at once and never waits for the agent. Unknown triggers answer404.
Integrations › Webhooks sends Nautelle events — orchestrator, slots, pull requests, a person needed, budget alerts and more — to a URL you choose (n8n, Slack, your own bot).
- Each delivery is signed:
X-Nautelle-Signature: t=<unix>,v1=HMAC-SHA256(secret, "<t>.<body>"), withX-Nautelle-EventandX-Nautelle-Delivery. - Payloads are a fixed envelope built from an allowlist of fields, never raw events.
- Failed deliveries retry with exponential backoff, up to 8 attempts. After 10 consecutive failures the webhook's circuit opens for 15 minutes.
- A delivery log shows each attempt; you can redeliver or send a test.
- Only
https://targets are allowed unless an admin allowlists the host, and private, loopback and link-local addresses are refused at send time.
Without an App, each runner polls its projects' issues and pull requests every 60 seconds. A GitHub App pushes the same facts the moment they happen, and Nautelle turns each delivery into an immediate poll on the right runner.
- Set
APP_ENCRYPTION_KEY(andPUBLIC_URL, so GitHub can reach the server) in the API environment — see Self-Hosting. - Open Admin › Integrations › GitHub and choose Create GitHub App. GitHub's manifest flow creates a read-only App (issues, pull requests, checks, statuses, contents).
- Install it on your repositories. Installations map to projects by repository.
GitHub must reach <PUBLIC_URL>/hooks/github over HTTPS — a public reverse proxy, Tailscale Funnel or a Cloudflare Tunnel. While the App is healthy for a project, polling relaxes to every 10 minutes; if GitHub cannot reach you, nothing breaks and polling stays at 60 seconds. Each project's settings show whether it is covered and healthy. The App only reads; every write to GitHub still goes through the runner's gh.
Decisions: ADR-0004 · ADR-0007 · ADR-0015 · Spec: #24, #25, #26, #27, #123
Nautelle · Website · Discord · Engineering docs · MIT
Start
Work
Cost and health
Surfaces
Operate
Reference