@action-llama/skill 0.23.4 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1436 @@
1
+ # Agents
2
+
3
+ An agent is a directory inside your project that contains instructions and configuration for an autonomous LLM session. Each run is self-contained: the agent wakes up (on a schedule or webhook), executes its task, and shuts down.
4
+
5
+ ## Skills vs Agents
6
+
7
+ A **skill** is a portable artifact — a `SKILL.md` file (and optionally a `Dockerfile`) that defines what an agent does. Skills can be shared, published, and installed from git repos.
8
+
9
+ An **agent** is a skill instantiated in your project with local runtime configuration. When you run `al add` to install a skill, it becomes an agent with its own `config.toml` for project-specific settings like credentials, schedule, and model.
10
+
11
+ ## Agent Structure
12
+
13
+ An agent is a directory with at least two files:
14
+
15
+ ```
16
+ agents/<name>/
17
+ ├── SKILL.md # Portable metadata + instructions (the skill)
18
+ ├── config.toml # Project-local runtime config
19
+ └── Dockerfile # Optional — custom container image
20
+ ```
21
+
22
+ - **`SKILL.md`** contains portable metadata (name, description, license, compatibility) in its YAML frontmatter, and the agent's instructions in its markdown body.
23
+ - **`config.toml`** contains project-specific runtime configuration: credentials, models, schedule, webhooks, hooks, params, scale, and timeout.
24
+ - **`Dockerfile`** is optional. Defines custom container dependencies. May be provided by the skill author or customized per-project.
25
+
26
+ The directory name becomes the agent name. No registration is needed — the scheduler discovers agents by scanning for directories that contain a `SKILL.md`.
27
+
28
+ ## How Context is Assembled
29
+
30
+ At runtime, the agent's LLM session receives two inputs:
31
+
32
+ ### System prompt
33
+
34
+ The markdown body of `SKILL.md`, prepended with a **preamble** that teaches the agent its [language skills](#language-skills).
35
+
36
+ ### User prompt
37
+
38
+ Assembled from several blocks:
39
+
40
+ 1. **`<agent-config>`** — JSON of the `params` field from `config.toml`
41
+ 2. **`<credential-context>`** — describes which environment variables and tools are available (e.g. `GITHUB_TOKEN`, `git`, `gh`, SSH config)
42
+ 3. **`<environment>`** — filesystem constraints and working directory info
43
+ 4. **Trigger context** (one of):
44
+ - *Scheduled run:* "You are running on a schedule. Check for new work and act on anything you find."
45
+ - *Manual run:* "You have been triggered manually. Check for new work and act on anything you find."
46
+ - *Webhook:* `<webhook-trigger>` block with the full event payload (source, event, action, repo, etc.)
47
+ - *Subagent call:* `<skill-subagent>` block with the caller agent name and context
48
+
49
+ Your `SKILL.md` instructions should reference `<agent-config>` for parameter values and handle both scheduled and webhook triggers if the agent uses both.
50
+
51
+ ## Language Skills
52
+
53
+ Before the `SKILL.md` instructions run, the agent receives a preamble that teaches it a set of **language skills** — shorthand operations the skill can reference naturally. The preamble explains the underlying mechanics (curl commands, env vars) so agent authors never need to think about them.
54
+
55
+ | Category | Skills | Description |
56
+ |----------|--------|-------------|
57
+ | **Signals** | `al-rerun`, `al-status`, `al-return`, `al-exit` | Shell commands for signaling the scheduler |
58
+ | **Calls** | `al-subagent`, `al-subagent-check`, `al-subagent-wait` | Agent-to-agent calls with return values |
59
+ | **Locks** | `LOCK(...)`, `UNLOCK(...)`, `HEARTBEAT(...)` | Resource locking for parallel coordination |
60
+ | **Credentials** | `GITHUB_TOKEN`, `gh`, `git`, etc. | Credential access and tool usage |
61
+
62
+ Agent authors write the shorthand naturally (e.g. `LOCK("github issue acme/app#42")`). The agent learns what it means from the preamble.
63
+
64
+ See [Agent Commands](/reference/agent-commands) for the complete command reference.
65
+
66
+ ## Runtime Lifecycle
67
+
68
+ Each agent run is an isolated, short-lived process. By default agents run in Docker containers, but agents can also be configured to run on the host machine under a separate OS user (see [Runtime](/reference/agent-config#runtime)). Here's the full sequence from trigger to exit:
69
+
70
+ 1. **Trigger fires** — a cron tick, webhook event, manual `al run`, or `al-subagent` from another agent.
71
+ 2. **Work is queued** — if all runners for the target agent are busy, the trigger is placed in a SQLite-backed work queue until a runner becomes available.
72
+ 3. **Process launches** — a fresh container (or host-user process) starts with credentials and config passed via environment variables and volume mounts (or temp directories).
73
+ 4. **Credentials are loaded** — the entry point reads credential files from the credentials path (`/credentials/` in containers, or the `AL_CREDENTIALS_PATH` temp directory in host-user mode). Key credentials are injected as env vars the LLM can use directly: `GITHUB_TOKEN`, `GH_TOKEN`, `SENTRY_AUTH_TOKEN`, `GIT_SSH_COMMAND`, git author identity, etc.
74
+ 5. **Hooks run** — if `hooks.pre` steps are defined in `config.toml`, they execute sequentially (clone repos, fetch data, run shell commands) to stage context before the LLM starts. See [Dynamic Context](/guides/dynamic-context).
75
+ 6. **LLM session starts** — the model receives the `SKILL.md` instructions as system prompt and the assembled user prompt.
76
+ 7. **Agent runs autonomously** — the LLM executes tools (bash, file I/O, API calls) until it finishes or hits an error. Rate-limited API calls are retried automatically (up to 5 attempts with exponential backoff).
77
+ 8. **Error detection** — the runtime watches for repeated auth/permission failures (e.g. "bad credentials", "permission denied"). After 3 such errors, it aborts early.
78
+ 9. **Signals are processed** — the agent uses `al-rerun`, `al-status`, `al-return`, and `al-exit` commands to write signal files. The scheduler reads them after the session ends.
79
+ 10. **Process exits** — exit code 0 (success), 1 (error), or 124 (timeout). Any held locks are released automatically. The scheduler logs the result and the container is removed (or the working directory is cleaned up in host-user mode).
80
+
81
+ ## Timeout
82
+
83
+ Each agent process has a self-termination timer controlled by `timeout` in the agent's `config.toml` (falls back to `local.timeout` in project `config.toml`, then 900 seconds). If the timer fires, the process exits with code 124. This is a hard kill — there is no graceful shutdown.
84
+
85
+ See [Agent Config — Timeout](/reference/agent-config#timeout) for configuration.
86
+
87
+ ## Reruns
88
+
89
+ When a scheduled agent runs `al-rerun`, the scheduler immediately re-runs it. This continues until the agent completes without `al-rerun` (no more work), hits an error, or reaches the `maxReruns` limit (default: 10, configurable in `config.toml`). This lets an agent drain its work queue without waiting for the next cron tick.
90
+
91
+ Webhook-triggered and agent-called runs do not re-run — they respond to a single event.
92
+
93
+ ## Work Queue
94
+
95
+ When a trigger fires (webhook event or agent call) but all runner instances for the target agent are busy, the event is placed in a **work queue** instead of being dropped. Items are dequeued and executed as runners become available.
96
+
97
+ The queue is backed by SQLite (`.al/work-queue.db`), so pending items survive scheduler restarts. Each agent has its own queue. If the queue is full, the oldest items are dropped.
98
+
99
+ You can see queue depth per agent in `al stat` output (the `queue` column).
100
+
101
+ | Setting | Location | Default | Description |
102
+ |---------|----------|---------|-------------|
103
+ | `workQueueSize` | `config.toml` | `100` | Maximum queued work items per agent |
104
+
105
+ ## Container Filesystem
106
+
107
+ When running in the default container runtime:
108
+
109
+ | Path | Mode | Contents |
110
+ |------|------|----------|
111
+ | `/app` | read-only | Action Llama application + node_modules |
112
+ | `/credentials` | read-only | Mounted credential files (`/<type>/<instance>/<field>`) |
113
+ | `/tmp` | read-write (tmpfs, 2GB) | Agent working directory — repos, scratch files, SSH keys |
114
+ | `/workspace` | read-write (2GB) | Persistent workspace |
115
+ | `/home/node` | read-write (64MB) | Home directory |
116
+
117
+ The root filesystem is read-only. All agent work should happen in `/tmp`.
118
+
119
+ ### Host-User Filesystem
120
+
121
+ When running in [host-user mode](/reference/agent-config#runtime), the agent runs directly on the host:
122
+
123
+ | Path | Contents |
124
+ |------|----------|
125
+ | `/tmp/al-runs/<instance-id>/` | Working directory (chowned to agent user) |
126
+ | `AL_CREDENTIALS_PATH` (temp dir) | Staged credential files (`/<type>/<instance>/<field>`) |
127
+
128
+ The agent has access to the host filesystem but runs as a separate OS user, so it cannot access other users' files or credentials.
129
+
130
+ ## See Also
131
+
132
+ - [Getting Started](/first-steps/getting-started) — create your first agent
133
+ - [Agent Commands](/reference/agent-commands) — signals, calls, and lock commands
134
+ - [Agent Config Reference](/reference/agent-config) — SKILL.md and config.toml fields
135
+ - [Agent Docs](/reference/agent-docs) — SKILL.md, AGENTS.md, CLAUDE.md
136
+ - [Credentials](/reference/credentials) — credential types and storage
137
+ - [Web Dashboard](/reference/web-dashboard) — monitoring agents in your browser
138
+
139
+ ---
140
+
141
+ # Agent Configuration
142
+
143
+ Each agent lives in a directory under `agents/<name>/`. Configuration is split across two files:
144
+
145
+ | File | Purpose | Portable? |
146
+ |------|---------|-----------|
147
+ | `SKILL.md` | Portable metadata (name, description, license, compatibility) + markdown instructions | Yes — travels with the skill |
148
+ | `config.toml` | Runtime config (credentials, models, schedule, webhooks, hooks, params, scale, timeout) | No — project-local |
149
+
150
+ A **skill** is the portable artifact (SKILL.md + optionally a Dockerfile). An **agent** is a skill instantiated in your project with local runtime config. When you `al add` a skill, it becomes an agent.
151
+
152
+ An optional `Dockerfile` can also live in the agent directory for custom container images. It may be provided by the skill author or customized per-project.
153
+
154
+ ```
155
+ agents/<name>/
156
+ ├── SKILL.md # Portable metadata + instructions
157
+ ├── config.toml # Project-local runtime config
158
+ └── Dockerfile # Optional — custom container image (container runtime only)
159
+ ```
160
+
161
+ ## SKILL.md
162
+
163
+ The YAML frontmatter contains portable metadata. The markdown body contains the agent's instructions.
164
+
165
+ ```yaml
166
+ ---
167
+ name: dev-agent
168
+ description: Solves GitHub issues by writing and testing code
169
+ license: MIT
170
+ compatibility: ">=0.5.0"
171
+ ---
172
+
173
+ # Instructions
174
+
175
+ You are a dev agent. Check for open issues labeled "agent" and fix them.
176
+
177
+ ## Workflow
178
+
179
+ 1. List open issues labeled "agent" in repos from `<agent-config>`
180
+ 2. For each issue, clone the repo, create a branch, implement the fix
181
+ 3. Open a PR and link it to the issue
182
+ ```
183
+
184
+ ### SKILL.md Frontmatter Fields
185
+
186
+ | Field | Type | Required | Description |
187
+ |-------|------|----------|-------------|
188
+ | `name` | string | No | Human-readable name (defaults to directory name) |
189
+ | `description` | string | No | Short description of what the agent does |
190
+ | `license` | string | No | License identifier (e.g. `"MIT"`) |
191
+ | `compatibility` | string | No | Semver range for Action Llama compatibility |
192
+
193
+ ## config.toml
194
+
195
+ The per-agent `config.toml` contains project-specific runtime configuration. This file is created by `al add`, `al agent new`, or `al config`.
196
+
197
+ ```toml
198
+ # Install origin — used by `al update` to pull upstream SKILL.md changes
199
+ source = "acme/dev-skills"
200
+
201
+ # Required: named model references from project config.toml [models.*]
202
+ # First in list is primary; rest are fallbacks tried on rate limits
203
+ models = ["sonnet", "haiku"]
204
+
205
+ # Required: credential types the agent needs at runtime
206
+ # Use "type" for default instance, "type:instance" for named instance
207
+ credentials = ["github_token", "git_ssh", "sentry_token"]
208
+
209
+ # Optional: cron schedule (standard cron syntax)
210
+ # Agent must have at least one of: schedule, webhooks
211
+ schedule = "*/5 * * * *"
212
+
213
+ # Optional: number of concurrent runs allowed (default: 1)
214
+ # When scale > 1, use LOCK/UNLOCK in your actions to coordinate
215
+ scale = 2
216
+
217
+ # Optional: max runtime in seconds (default: falls back to [local].timeout, then 900)
218
+ timeout = 600
219
+
220
+ # Optional: max queued work items for this agent (default: global workQueueSize)
221
+ # When all runners are busy, incoming events are queued up to this limit.
222
+ # Oldest events are dropped to make room for newer ones.
223
+ maxWorkQueueSize = 50
224
+
225
+ # Optional: webhook triggers (instead of or in addition to schedule)
226
+ [[webhooks]]
227
+ source = "my-github"
228
+ repos = ["acme/app"]
229
+ events = ["issues"]
230
+ actions = ["labeled"]
231
+ labels = ["agent"]
232
+
233
+ [[webhooks]]
234
+ source = "my-sentry"
235
+ resources = ["error", "event_alert"]
236
+
237
+ [[webhooks]]
238
+ source = "my-linear"
239
+ events = ["issues"]
240
+ actions = ["create", "update"]
241
+ labels = ["bug"]
242
+
243
+ [[webhooks]]
244
+ source = "my-mintlify"
245
+ events = ["build"]
246
+ actions = ["failed"]
247
+
248
+ # Optional: hooks — shell commands that run before or after the LLM session
249
+ [hooks]
250
+ pre = [
251
+ "gh repo clone acme/app /tmp/repo --depth 1",
252
+ "curl -o /tmp/context/flags.json https://api.internal/v1/flags",
253
+ "gh issue list --repo acme/app --label P1 --json number,title,body --limit 20 > /tmp/context/issues.json",
254
+ ]
255
+ post = ["upload-artifacts.sh"]
256
+
257
+ # Optional: custom parameters injected into the agent prompt
258
+ [params]
259
+ repos = ["acme/app", "acme/api"]
260
+ triggerLabel = "agent"
261
+ assignee = "bot-user"
262
+ sentryOrg = "acme"
263
+ sentryProjects = ["web-app", "api"]
264
+
265
+ # Optional: runtime mode — "container" (default) or "host-user"
266
+ # Host-user runs the agent as a separate OS user via sudo, without Docker.
267
+ # Useful when the agent needs to run Docker commands itself.
268
+ [runtime]
269
+ type = "host-user"
270
+ run_as = "al-agent" # OS user to run as (default: "al-agent")
271
+ ```
272
+
273
+ ### config.toml Field Reference
274
+
275
+ | Field | Type | Required | Description |
276
+ |-------|------|----------|-------------|
277
+ | `source` | string | No | Git URL or GitHub shorthand for `al update`. Set automatically by `al add`. |
278
+ | `models` | string[] | Yes | Named model references from `config.toml [models.*]`. First is primary; rest are fallbacks tried automatically on rate limits. |
279
+ | `credentials` | string[] | Yes | Credential refs: `"type"` for default instance, `"type:instance"` for named instance. See [Credentials](/reference/credentials). |
280
+ | `schedule` | string | No* | Cron expression for polling |
281
+ | `scale` | number | No | Number of concurrent runs allowed (default: 1). Set to `0` to disable the agent. Use lock skills in your actions to coordinate instances. See [Resource Locks](/concepts/resource-locks). |
282
+ | `timeout` | number | No | Max runtime in seconds. Falls back to `[local].timeout` in project config, then `900`. See [Timeout](#timeout). |
283
+ | `maxWorkQueueSize` | number | No | Maximum queued work items when all runners are busy. Falls back to global `workQueueSize` (default: 20). Oldest events are dropped to make room for newer ones. |
284
+ | `webhooks` | array | No* | Array of webhook trigger objects. See [Webhooks](/reference/webhooks). |
285
+ | `hooks` | table | No | Pre/post hooks that run around the LLM session. See [Hooks](#hooks). |
286
+ | `params` | table | No | Custom key-value params for the agent prompt |
287
+ | `runtime` | table | No | Runtime mode configuration. See [Runtime](#runtime). |
288
+
289
+ *At least one of `schedule` or `webhooks` is required (unless `scale = 0`).
290
+
291
+ ## Scale
292
+
293
+ The `scale` field controls how many instances of an agent can run concurrently.
294
+
295
+ - **Default**: 1 (only one instance can run at a time)
296
+ - **Minimum**: 0 (disables the agent — no runners, cron jobs, or webhook bindings are created)
297
+ - **Maximum**: No hard limit, but consider system resources and model API rate limits
298
+
299
+ ### How it works
300
+
301
+ 1. **Scheduled runs**: If a cron trigger fires but all agent instances are busy, the scheduled run is skipped with a warning
302
+ 2. **Webhook events**: If a webhook arrives but all instances are busy, the event is queued (up to `workQueueSize` limit in global config, default: 100)
303
+ 3. **Agent calls**: If one agent calls another but all target instances are busy, the call is queued in the same work queue
304
+
305
+ ### Example use cases
306
+
307
+ - **Dev agent** with `scale = 3`: Handle multiple GitHub issues simultaneously
308
+ - **Review agent** with `scale = 2`: Review multiple PRs in parallel
309
+ - **Monitoring agent** with `scale = 1`: Ensure only one instance processes alerts at a time
310
+ - **Disabled agent** with `scale = 0`: Keep the config in the project but don't run it
311
+
312
+ ### Resource considerations
313
+
314
+ Each parallel instance:
315
+ - Uses a separate Docker container (or OS process in host-user mode)
316
+ - Has independent logging streams
317
+ - May consume LLM API quota concurrently
318
+ - Uses system memory and CPU
319
+
320
+ See [Scaling Agents](/guides/scaling-agents) for a guide on scaling with resource locks.
321
+
322
+ ## Timeout
323
+
324
+ The `timeout` field controls the maximum runtime for an agent invocation. When the timeout expires, the process is terminated with exit code 124.
325
+
326
+ **Resolution order:** `config.toml timeout` -> `project config.toml [local].timeout` -> `900` (default)
327
+
328
+ This means you can set a project-wide default in `[local].timeout` and override it per-agent.
329
+
330
+ ### Examples
331
+
332
+ ```toml
333
+ # Fast webhook responder
334
+ timeout = 300 # 5 minutes
335
+
336
+ # Medium-length task
337
+ timeout = 900 # 15 minutes
338
+
339
+ # Long-running agent
340
+ timeout = 3600 # 1 hour
341
+
342
+ # Omit timeout — uses [local].timeout or defaults to 900s
343
+ ```
344
+
345
+ ## Hooks
346
+
347
+ Hooks run shell commands before and after the LLM session. Pre-hooks (`hooks.pre`) run after credentials are loaded but before the LLM session starts — use them for cloning repos, fetching data, or staging files. Post-hooks (`hooks.post`) run after the session completes — use them for cleanup, artifact upload, or reporting.
348
+
349
+ See [Dynamic Context](/guides/dynamic-context) for a guide on using hooks effectively.
350
+
351
+ ### How it works
352
+
353
+ 1. Commands run **sequentially** in the order they appear in `config.toml`
354
+ 2. Commands run inside the agent's execution environment (container or host-user process) after credential/env setup
355
+ 3. Each command runs via `/bin/sh -c "..."`
356
+ 4. If any command exits non-zero, the run aborts with an error
357
+ 5. Credential env vars (`GITHUB_TOKEN`, `GH_TOKEN`, etc.) are available to hook commands
358
+
359
+ ### Fields
360
+
361
+ | Field | Type | Required | Description |
362
+ |-------|------|----------|-------------|
363
+ | `hooks.pre` | string[] | No | Shell commands to run before the LLM session |
364
+ | `hooks.post` | string[] | No | Shell commands to run after the LLM session |
365
+
366
+ ### Examples
367
+
368
+ ```toml
369
+ [hooks]
370
+ pre = [
371
+ "gh repo clone acme/app /tmp/repo --depth 1",
372
+ "gh issue list --repo acme/app --label P1 --json number,title,body --limit 20 > /tmp/context/issues.json",
373
+ "curl -o /tmp/context/flags.json https://api.internal/v1/flags",
374
+ ]
375
+ post = ["upload-artifacts.sh"]
376
+ ```
377
+
378
+ ### Notes
379
+
380
+ - Each hook has a 5-minute timeout
381
+ - Hooks are bounded by the container-level timeout
382
+ - Environment variables set inside hook commands do not propagate back to the agent's `process.env`
383
+
384
+ ## Runtime
385
+
386
+ The `[runtime]` table controls how the agent process is launched. By default, agents run in Docker containers. The `host-user` runtime runs agents as a separate OS user on the host machine via `sudo -u`, without Docker.
387
+
388
+ Host-user mode is useful when agents need to run Docker commands themselves (Docker-in-Docker is insecure), or when you want lightweight isolation without container overhead.
389
+
390
+ ```toml
391
+ [runtime]
392
+ type = "host-user"
393
+ run_as = "al-agent"
394
+ ```
395
+
396
+ ### Fields
397
+
398
+ | Field | Type | Default | Description |
399
+ |-------|------|---------|-------------|
400
+ | `type` | string | `"container"` | Runtime mode: `"container"` (Docker) or `"host-user"` (OS user isolation) |
401
+ | `run_as` | string | `"al-agent"` | OS username to run the agent as. Only used when `type = "host-user"`. |
402
+
403
+ ### How host-user mode works
404
+
405
+ 1. The scheduler spawns `sudo -u <run_as> al _run-agent <agent> --project <dir>`
406
+ 2. Credentials are staged to a temp directory and chowned to the agent user
407
+ 3. Each run gets an isolated working directory at `/tmp/al-runs/<instance-id>/`
408
+ 4. Logs are written to `/tmp/al-runs/<instance-id>.log` (owned by the scheduler, not the agent)
409
+ 5. No Docker images are built for host-user agents
410
+
411
+ ### Setup
412
+
413
+ The agent OS user must exist and sudoers must be configured. Run `al doctor` to validate and auto-configure (Linux only):
414
+
415
+ ```bash
416
+ al doctor
417
+ ```
418
+
419
+ On Linux, `al doctor` will:
420
+ - Create the OS user if it doesn't exist (`useradd --system --shell /usr/sbin/nologin <run_as>`)
421
+ - Add a sudoers rule allowing passwordless execution
422
+
423
+ On macOS, `al doctor` prints manual setup instructions.
424
+
425
+ ### Limitations
426
+
427
+ - No custom Dockerfiles — `Dockerfile` in the agent directory is ignored
428
+ - No container filesystem isolation — the agent runs on the host filesystem
429
+ - The `[local]` config section (`memory`, `cpus`, `image`) does not apply to host-user agents
430
+ - `needsGateway` is false — the gateway is not started for host-user-only projects
431
+
432
+ ## Webhook Trigger Fields
433
+
434
+ Each entry in the `webhooks` array has the following fields:
435
+
436
+ | Field | Type | Required | Description |
437
+ |-------|------|----------|-------------|
438
+ | `source` | string | Yes | Name of a webhook source from the project's `config.toml` (e.g. `"my-github"`) |
439
+
440
+ All filter fields below are optional. Omit all of them to trigger on everything from that source. See [Webhooks](/reference/webhooks) for complete filter field tables per provider.
441
+
442
+ ### GitHub filter fields
443
+
444
+ | Field | Type | Description |
445
+ |-------|------|-------------|
446
+ | `repos` | string[] | Filter to specific repos |
447
+ | `orgs` | string[] | Filter to specific organizations |
448
+ | `org` | string | Filter to a single organization |
449
+ | `events` | string[] | Event types: issues, pull_request, push, etc. |
450
+ | `actions` | string[] | Event actions: opened, labeled, closed, etc. |
451
+ | `labels` | string[] | Only trigger when issue/PR has these labels |
452
+ | `assignee` | string | Only trigger when assigned to this user |
453
+ | `author` | string | Only trigger for this author |
454
+ | `branches` | string[] | Only trigger for these branches |
455
+ | `conclusions` | string[] | Only for workflow_run events with these conclusions |
456
+
457
+ ### Sentry filter fields
458
+
459
+ | Field | Type | Description |
460
+ |-------|------|-------------|
461
+ | `resources` | string[] | Resource types: event_alert, metric_alert, issue, error, comment |
462
+
463
+ ### Linear filter fields
464
+
465
+ | Field | Type | Description |
466
+ |-------|------|-------------|
467
+ | `organizations` | string[] | Filter to specific Linear organizations |
468
+ | `events` | string[] | Linear event types: issues, issue_comment, etc. |
469
+ | `actions` | string[] | Event actions: create, update, delete, etc. |
470
+ | `labels` | string[] | Only when issue has these labels |
471
+ | `assignee` | string | Only when assigned to this user (email) |
472
+ | `author` | string | Only for this author (email) |
473
+
474
+ ### Mintlify filter fields
475
+
476
+ | Field | Type | Description |
477
+ |-------|------|-------------|
478
+ | `projects` | string[] | Filter to specific Mintlify projects |
479
+ | `events` | string[] | Mintlify event types: build, etc. |
480
+ | `actions` | string[] | Event actions: failed, succeeded, etc. |
481
+ | `branches` | string[] | Only for these branches |
482
+
483
+ ## Model Configuration
484
+
485
+ The `models` field references named models defined in `config.toml` under `[models.<name>]`. List one or more model names — the first is the primary model, and subsequent entries are fallbacks tried automatically when the primary is rate-limited or unavailable.
486
+
487
+ ```toml
488
+ models = ["sonnet", "haiku", "gpt4o"]
489
+ ```
490
+
491
+ See [Models](/reference/models) for all supported providers, model IDs, auth types, thinking levels, and credential setup.
492
+
493
+ ---
494
+
495
+ # Agent Docs
496
+
497
+ Action Llama uses three markdown files with distinct purposes. Only `SKILL.md` is required.
498
+
499
+ ## SKILL.md
500
+
501
+ The portable part of an agent. YAML frontmatter at the top contains portable metadata (name, description, license, compatibility), and the markdown body is the system prompt that drives the agent's behavior. Runtime configuration (credentials, schedule, models, webhooks, hooks, params) lives in the separate `config.toml` file.
502
+
503
+ ### What it is
504
+
505
+ `SKILL.md` lives inside each agent's directory (e.g. `agents/dev/SKILL.md`). The frontmatter is parsed for portable metadata, and the markdown body is injected as the LLM's system prompt at runtime. Everything the agent does is driven by these instructions.
506
+
507
+ ### How it's used
508
+
509
+ The scheduler reads `SKILL.md` and sends the markdown body as the system prompt. Runtime configuration is loaded from `config.toml`. A preamble is prepended that teaches the agent its [language skills](/reference/agent-commands) (signals, calls, locks, credentials). The LLM then receives a user-message prompt with:
510
+
511
+ 1. **`<skill-config>`** — JSON of the `params` table from the agent's `config.toml`
512
+ 2. **`<credential-context>`** — describes available environment variables and tools
513
+ 3. **`<environment>`** — filesystem constraints (read-only root, `/tmp` for work)
514
+ 4. **Trigger context** — schedule, webhook payload, manual, or subagent call context
515
+
516
+ ### Writing tips
517
+
518
+ - **Write as direct instructions to an LLM.** "You are an automation agent. Your job is to..."
519
+ - **Be specific about workflow.** Numbered steps are better than vague descriptions.
520
+ - **Reference `<skill-config>` for parameter values.** Don't hardcode repo names or labels — put them in `params` and reference them.
521
+ - **Handle both trigger types** if the agent uses both schedule and webhooks.
522
+ - **Use signal commands** like `al-rerun` for backlog draining and `al-status` for TUI updates.
523
+ - **Keep it concise.** The system prompt consumes tokens every run. Avoid lengthy explanations of things the LLM already knows.
524
+
525
+ ### Example
526
+
527
+ ```markdown
528
+ # Dev Agent
529
+
530
+ You are an automation agent. Your job is to pick up GitHub issues and implement the requested changes.
531
+
532
+ Your configuration is in the `<skill-config>` block at the start of your prompt.
533
+ `GITHUB_TOKEN` is already set in your environment. Use `gh` CLI and `git` directly.
534
+
535
+ ## Workflow
536
+
537
+ 1. **Find work** — If triggered by webhook, work on the issue from the trigger. If scheduled, search for open issues labeled with the label from `<skill-config>`.triggerLabel.
538
+ 2. **Lock the issue** — LOCK("github issue owner/repo#N"). If locked, skip it.
539
+ 3. **Implement** — Clone the repo, create a branch, make changes, run tests.
540
+ 4. **Open a PR** — Push and open a PR linking to the issue.
541
+ 5. **Unlock** — UNLOCK("github issue owner/repo#N").
542
+ 6. **Continue** — If you completed work and there may be more issues, run `al-rerun`.
543
+
544
+ ## Rules
545
+
546
+ - Never force-push
547
+ - Run tests before opening a PR
548
+ - If tests fail after 3 attempts, comment on the issue and move on
549
+ ```
550
+
551
+ ### Handling trigger context
552
+
553
+ Your `SKILL.md` should handle different trigger types if the agent uses both:
554
+
555
+ ```markdown
556
+ ## Trigger handling
557
+
558
+ - **Webhook trigger**: The `<webhook-trigger>` block contains the full event payload. Work on the specific issue/PR from the event.
559
+ - **Scheduled trigger**: Search for open work matching your configured filters.
560
+ - **Subagent call**: The `<skill-subagent>` block contains context from the calling agent. Do what was requested and use `al-return` to send back results.
561
+ ```
562
+
563
+ ## AGENTS.md
564
+
565
+ Project-level shared instructions that are loaded by `al chat`.
566
+
567
+ ### What it is
568
+
569
+ `AGENTS.md` lives at the project root (e.g. `my-project/AGENTS.md`). It provides shared context about the project that is relevant when interacting with agents via the chat console.
570
+
571
+ ### How it's used
572
+
573
+ When you run `al chat` (project-level console), the contents of `AGENTS.md` are loaded as reference context. It is **not** injected into automated agent runs — only into the interactive chat session.
574
+
575
+ ### When to use it
576
+
577
+ Use `AGENTS.md` to document:
578
+
579
+ - Project conventions that are relevant when working with agents interactively
580
+ - How agents in the project relate to each other
581
+ - Common tasks and how to accomplish them via chat
582
+
583
+ ## CLAUDE.md
584
+
585
+ Instructions for AI development tools (like Claude Code). Not used by Action Llama at runtime.
586
+
587
+ ### What it is
588
+
589
+ `CLAUDE.md` lives at the project root and provides instructions to AI coding assistants that may be editing the project's source code. Do not confuse it with `SKILL.md`, which is the agent instructions file.
590
+
591
+ ### How it's used
592
+
593
+ `CLAUDE.md` is **not** read by Action Llama. It has no effect on agent runs, the scheduler, or the chat console. It exists purely for developer tooling context.
594
+
595
+ ### When to use it
596
+
597
+ If you use Claude Code or similar AI development tools to work on your Action Llama project, put project conventions, build commands, and coding guidelines in `CLAUDE.md`. See [Claude Integration](/integrations/claude) for how Claude Code uses this file alongside the MCP server.
598
+
599
+ ---
600
+
601
+ # Credentials
602
+
603
+ Credentials are stored in `~/.action-llama/credentials/<type>/<instance>/<field>`. Each credential type is a directory containing one file per field. Reference them in your agent's `config.toml` by type name (e.g. `"github_token"`) for the `default` instance, or use `"type:instance"` for a named instance (e.g. `"git_ssh:botty"`).
604
+
605
+ ## Built-in Credentials
606
+
607
+ ### Agent runtime credentials
608
+
609
+ | Type | Fields | Description | Runtime Injection |
610
+ |------|--------|-------------|-------------------|
611
+ | `github_token` | `token` | GitHub PAT with repo and workflow scopes | `GITHUB_TOKEN` and `GH_TOKEN` env vars |
612
+ | `anthropic_key` | `token` | Anthropic API key, OAuth token, or pi auth | _(read by SDK)_ |
613
+ | `openai_key` | `token` | OpenAI API key | _(read by SDK)_ |
614
+ | `groq_key` | `token` | Groq API key | _(read by SDK)_ |
615
+ | `google_key` | `token` | Google Gemini API key | _(read by SDK)_ |
616
+ | `xai_key` | `token` | xAI API key | _(read by SDK)_ |
617
+ | `mistral_key` | `token` | Mistral API key | _(read by SDK)_ |
618
+ | `openrouter_key` | `token` | OpenRouter API key | _(read by SDK)_ |
619
+ | `custom_key` | `token` | Custom provider API key | _(read by SDK)_ |
620
+ | `sentry_token` | `token` | Sentry auth token for error monitoring | `SENTRY_AUTH_TOKEN` env var |
621
+ | `linear_token` | `token` | Linear personal API token | `LINEAR_API_TOKEN` env var |
622
+ | `linear_oauth` | `client_id`, `client_secret`, `access_token`, `refresh_token` | Linear OAuth2 credentials | `LINEAR_CLIENT_ID`, `LINEAR_CLIENT_SECRET`, `LINEAR_ACCESS_TOKEN`, `LINEAR_REFRESH_TOKEN` env vars |
623
+ | `bugsnag_token` | `token` | Bugsnag auth token | `BUGSNAG_AUTH_TOKEN` env var |
624
+ | `netlify_token` | `token` | Netlify Personal Access Token | `NETLIFY_AUTH_TOKEN` env var |
625
+ | `mintlify_token` | `token` | Mintlify API token | `MINTLIFY_API_TOKEN` env var |
626
+ | `slack_bot_token` | `token` | Slack bot user OAuth token | `SLACK_BOT_TOKEN` env var |
627
+ | `git_ssh` | `id_rsa`, `username`, `email` | SSH private key + git author identity | SSH key mounted as file; `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/`GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` set from `username`/`email` |
628
+ | `x_twitter_api` | `api_key`, `api_secret`, `bearer_token`, `access_token`, `access_token_secret` | X (Twitter) API credentials | `X_API_KEY`, `X_API_SECRET`, `X_BEARER_TOKEN`, `X_ACCESS_TOKEN`, `X_ACCESS_TOKEN_SECRET` env vars |
629
+ | `aws` | `access_key_id`, `secret_access_key`, `default_region` | AWS credentials | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION` env vars |
630
+ | `reddit_oauth` | `client_id`, `client_secret`, `username`, `password`, `user_agent` | Reddit OAuth2 credentials for script apps | `REDDIT_CLIENT_ID`, `REDDIT_CLIENT_SECRET`, `REDDIT_USERNAME`, `REDDIT_PASSWORD`, `REDDIT_USER_AGENT` env vars |
631
+
632
+ ### Webhook secrets
633
+
634
+ | Type | Fields | Description |
635
+ |------|--------|-------------|
636
+ | `github_webhook_secret` | `secret` | Shared secret for GitHub webhook HMAC verification |
637
+ | `sentry_client_secret` | `secret` | Client secret for Sentry webhook verification |
638
+ | `linear_webhook_secret` | `secret` | Shared secret for Linear webhook verification |
639
+ | `mintlify_webhook_secret` | `secret` | Shared secret for Mintlify webhook verification |
640
+ | `discord_bot` | `application_id`, `public_key`, `bot_token` | Discord bot credentials for Ed25519 webhook verification and API access. Injected as `DISCORD_APPLICATION_ID`, `DISCORD_PUBLIC_KEY`, `DISCORD_BOT_TOKEN`. |
641
+ | `slack_signing_secret` | `secret` | Signing secret for Slack webhook verification |
642
+
643
+ ### Infrastructure credentials
644
+
645
+ These are used by CLI commands (provisioning, deployment) and are not injected into agent containers.
646
+
647
+ | Type | Fields | Description |
648
+ |------|--------|-------------|
649
+ | `gateway_api_key` | `key` | API key for dashboard and CLI access to the gateway |
650
+ | `vultr_api_key` | `api_key` | Vultr API key for VPS provisioning |
651
+ | `hetzner_api_key` | `api_key` | Hetzner API key for VPS provisioning |
652
+ | `cloudflare_api_token` | `token` | Cloudflare API token for DNS and TLS setup during provisioning |
653
+ | `vps_ssh` | `id_rsa` | SSH private key for VPS access (generated or selected during provisioning) |
654
+ | `gcp_service_account` | `key_json` | GCP service account JSON key for Cloud Run Jobs runtime (requires `roles/run.admin`, `roles/secretmanager.admin`, `roles/artifactregistry.admin`) |
655
+
656
+ ## How Credentials Work
657
+
658
+ 1. **Configuration**: List credential types in your agent's `config.toml`:
659
+ ```toml
660
+ credentials = ["github_token", "git_ssh"]
661
+ ```
662
+
663
+ 2. **Storage**: Credential values live in `~/.action-llama/credentials/<type>/<instance>/<field>`. Each field is a plain text file.
664
+
665
+ 3. **Injection**: When an agent runs, the credentials it requires are made available at a credentials path and key values are injected as environment variables. In Docker mode, credentials are mounted at `/credentials/<type>/<instance>/<field>`. In [host-user mode](/reference/agent-config#runtime), they are staged to a temp directory (path set via `AL_CREDENTIALS_PATH`) and chowned to the agent user.
666
+
667
+ 4. **Git identity**: The `git_ssh` credential includes `username` and `email` fields (prompted during `al new`/`al doctor`). These are injected as `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL` and `GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` env vars at runtime, so `git commit` works without requiring `git config`.
668
+
669
+ 5. **LLM credentials**: The LLM credential (e.g. `anthropic_key`) does not need to be listed in the agent's `credentials` array — it is loaded automatically based on the `[models.*]` config.
670
+
671
+ ## Named Instances
672
+
673
+ Each credential type supports named instances. For example, you could have webhook secrets for multiple GitHub orgs:
674
+
675
+ ```
676
+ ~/.action-llama/credentials/github_webhook_secret/MyOrg/secret
677
+ ~/.action-llama/credentials/github_webhook_secret/OtherOrg/secret
678
+ ```
679
+
680
+ Or multiple SSH keys:
681
+
682
+ ```
683
+ ~/.action-llama/credentials/git_ssh/default/id_rsa
684
+ ~/.action-llama/credentials/git_ssh/default/username
685
+ ~/.action-llama/credentials/git_ssh/botty/id_rsa
686
+ ~/.action-llama/credentials/git_ssh/botty/username
687
+ ```
688
+
689
+ By default, just reference `"git_ssh"` — this resolves to the `default` instance. To use a named instance, use colon syntax: `"git_ssh:botty"`.
690
+
691
+ ## Managing Credentials
692
+
693
+ ### `al creds add`
694
+
695
+ Add or update a credential interactively. Runs validation for the credential type (e.g. API key format, GitHub API check):
696
+
697
+ ```bash
698
+ al creds add github_token # default instance
699
+ al creds add github_webhook_secret:myapp
700
+ al creds add git_ssh:prod
701
+ ```
702
+
703
+ ### `al creds rm`
704
+
705
+ Remove a credential:
706
+
707
+ ```bash
708
+ al creds rm github_token # default instance
709
+ al creds rm github_webhook_secret:myapp
710
+ ```
711
+
712
+ ### `al creds ls`
713
+
714
+ List all stored credentials grouped by type:
715
+
716
+ ```bash
717
+ al creds ls
718
+ ```
719
+
720
+ ### `al creds types`
721
+
722
+ Browse available credential types interactively. Shows all 26 built-in types with their fields, environment variables, and descriptions. Offers to add the selected credential immediately.
723
+
724
+ ```bash
725
+ al creds types
726
+ ```
727
+
728
+ ### `al doctor`
729
+
730
+ Scan all agents in a project and prompt for any missing credentials:
731
+
732
+ ```bash
733
+ al doctor
734
+ ```
735
+
736
+ ### During `al new`
737
+
738
+ The `al new` command prompts for the Anthropic credential during initial setup. Other credentials are configured per-agent by `al doctor` or `al creds add`.
739
+
740
+ ### Manually
741
+
742
+ Write credential files directly:
743
+
744
+ ```bash
745
+ mkdir -p ~/.action-llama/credentials/github_token/default
746
+ echo "ghp_your_token_here" > ~/.action-llama/credentials/github_token/default/token
747
+
748
+ mkdir -p ~/.action-llama/credentials/anthropic_key/default
749
+ echo "sk-ant-api-your_key_here" > ~/.action-llama/credentials/anthropic_key/default/token
750
+ ```
751
+
752
+ ## Anthropic Auth Methods
753
+
754
+ Three auth methods are supported:
755
+
756
+ - **`api_key`** — Standard API key (`sk-ant-api-...`). Set `authType = "api_key"` in model config.
757
+ - **`oauth_token`** — OAuth token (`sk-ant-oat-...`). Set `authType = "oauth_token"`.
758
+ - **`pi_auth`** — Use existing pi auth credentials (`~/.pi/agent/auth.json`). Set `authType = "pi_auth"`. No credential file needed.
759
+
760
+ ## Webhook Secrets
761
+
762
+ Webhook secrets use named credential instances. For example, to set up a GitHub webhook secret for your org:
763
+
764
+ ```bash
765
+ al creds add github_webhook_secret:MyOrg
766
+ ```
767
+
768
+ Or manually:
769
+
770
+ ```bash
771
+ mkdir -p ~/.action-llama/credentials/github_webhook_secret/MyOrg
772
+ echo "your-webhook-secret" > ~/.action-llama/credentials/github_webhook_secret/MyOrg/secret
773
+ ```
774
+
775
+ The gateway automatically loads secrets from all credential instances (e.g. `github_webhook_secret:MyOrg`, `sentry_client_secret:MyOrg`) and uses them to verify incoming webhook payloads. No global configuration is needed.
776
+
777
+ ## VPS Credential Sync
778
+
779
+ When deploying to a VPS, credentials are transferred to the remote server via SSH. The remote layout mirrors the local one: `~/.action-llama/credentials/{type}/{instance}/{field}`.
780
+
781
+ No external secrets manager is needed — same trust model as SSH access.
782
+
783
+ ## Troubleshooting
784
+
785
+ ### "Bad credentials" or "401 Unauthorized"
786
+
787
+ ```bash
788
+ al doctor # Re-prompts for missing or invalid credentials
789
+ al creds ls # Verify stored credentials
790
+ ```
791
+
792
+ For GitHub tokens, ensure the token has the required scopes (`repo`, `read:org`, `workflow`).
793
+
794
+ ### Credential not found at runtime
795
+
796
+ Agents only receive credentials listed in their `config.toml`:
797
+
798
+ ```toml
799
+ credentials = ["github_token", "git_ssh"]
800
+ ```
801
+
802
+ If a credential is missing from this list, the agent won't have access to it. Add it and re-run.
803
+
804
+ ---
805
+
806
+ # Models
807
+
808
+ Action Llama supports 8 LLM providers. Define named models in `config.toml` under `[models.<name>]`, then reference them by name in each agent's `config.toml`. Agents list models in priority order — the first is the primary, the rest are fallbacks tried automatically on rate limits.
809
+
810
+ ## `[models.<name>]` Fields
811
+
812
+ | Field | Type | Required | Description |
813
+ |-------|------|----------|-------------|
814
+ | `provider` | string | Yes | Provider name (see table below) |
815
+ | `model` | string | Yes | Model ID |
816
+ | `authType` | string | Yes | `"api_key"`, `"oauth_token"`, or `"pi_auth"` |
817
+ | `thinkingLevel` | string | No | Reasoning budget (Anthropic only) |
818
+
819
+ ## Providers
820
+
821
+ ### Anthropic
822
+
823
+ Claude models with optional extended thinking.
824
+
825
+ ```toml
826
+ [models.sonnet]
827
+ provider = "anthropic"
828
+ model = "claude-sonnet-4-20250514"
829
+ thinkingLevel = "medium"
830
+ authType = "api_key"
831
+ ```
832
+
833
+ | Model | Description |
834
+ |-------|-------------|
835
+ | `claude-opus-4-20250514` | Most capable, best for complex multi-step tasks |
836
+ | `claude-sonnet-4-20250514` | Balanced performance and cost (recommended) |
837
+ | `claude-haiku-3-5-20241022` | Fastest and cheapest |
838
+
839
+ **Credential:** `anthropic_key` (field: `token`)
840
+
841
+ **Auth types:**
842
+
843
+ | `authType` | Token format | Description |
844
+ |------------|-------------|-------------|
845
+ | `api_key` | `sk-ant-api-...` | Standard Anthropic API key |
846
+ | `oauth_token` | `sk-ant-oat-...` | OAuth token from `claude setup-token` |
847
+ | `pi_auth` | _(none)_ | Uses existing pi auth credentials (`~/.pi/agent/auth.json`). No credential file needed. |
848
+
849
+ **Note:** `pi_auth` is not supported in Docker mode. Switch to `api_key` or `oauth_token` for containerized runs.
850
+
851
+ **Thinking level:** Anthropic is the only provider that supports `thinkingLevel`. Valid values:
852
+
853
+ | Level | Description |
854
+ |-------|-------------|
855
+ | `off` | No extended thinking |
856
+ | `minimal` | Minimal reasoning |
857
+ | `low` | Light reasoning |
858
+ | `medium` | Balanced (recommended) |
859
+ | `high` | Deep reasoning |
860
+ | `xhigh` | Maximum reasoning budget |
861
+
862
+ If omitted, thinking is not explicitly configured. For other providers, `thinkingLevel` is ignored.
863
+
864
+ ### OpenAI
865
+
866
+ ```toml
867
+ [models.gpt4o]
868
+ provider = "openai"
869
+ model = "gpt-4o"
870
+ authType = "api_key"
871
+ ```
872
+
873
+ | Model | Description |
874
+ |-------|-------------|
875
+ | `gpt-4o` | Flagship multimodal model (recommended) |
876
+ | `gpt-4o-mini` | Smaller, faster, cheaper |
877
+ | `gpt-4-turbo` | Previous generation |
878
+ | `o1-preview` | Reasoning model |
879
+ | `o1-mini` | Smaller reasoning model |
880
+
881
+ **Credential:** `openai_key` (field: `token`)
882
+
883
+ ### Groq
884
+
885
+ ```toml
886
+ [models.groq-llama]
887
+ provider = "groq"
888
+ model = "llama-3.3-70b-versatile"
889
+ authType = "api_key"
890
+ ```
891
+
892
+ | Model | Description |
893
+ |-------|-------------|
894
+ | `llama-3.3-70b-versatile` | Llama 3.3 70B on Groq inference |
895
+
896
+ Groq runs open-source models at high speed. Check Groq's docs for the full list of available model IDs.
897
+
898
+ **Credential:** `groq_key` (field: `token`)
899
+
900
+ ### Google Gemini
901
+
902
+ ```toml
903
+ [models.gemini]
904
+ provider = "google"
905
+ model = "gemini-2.0-flash-exp"
906
+ authType = "api_key"
907
+ ```
908
+
909
+ | Model | Description |
910
+ |-------|-------------|
911
+ | `gemini-2.0-flash-exp` | Fast experimental model |
912
+
913
+ Check Google AI Studio for the full list of available model IDs.
914
+
915
+ **Credential:** `google_key` (field: `token`)
916
+
917
+ ### xAI
918
+
919
+ ```toml
920
+ [models.grok]
921
+ provider = "xai"
922
+ model = "grok-beta"
923
+ authType = "api_key"
924
+ ```
925
+
926
+ | Model | Description |
927
+ |-------|-------------|
928
+ | `grok-beta` | Grok beta |
929
+
930
+ **Credential:** `xai_key` (field: `token`)
931
+
932
+ ### Mistral
933
+
934
+ ```toml
935
+ [models.mistral]
936
+ provider = "mistral"
937
+ model = "mistral-large-2411"
938
+ authType = "api_key"
939
+ ```
940
+
941
+ | Model | Description |
942
+ |-------|-------------|
943
+ | `mistral-large-2411` | Mistral Large (November 2024) |
944
+
945
+ Check Mistral's docs for the full list of available model IDs.
946
+
947
+ **Credential:** `mistral_key` (field: `token`)
948
+
949
+ ### OpenRouter
950
+
951
+ OpenRouter provides access to models from many providers through a single API.
952
+
953
+ ```toml
954
+ [models.or-sonnet]
955
+ provider = "openrouter"
956
+ model = "anthropic/claude-3.5-sonnet"
957
+ authType = "api_key"
958
+ ```
959
+
960
+ Model IDs use the `provider/model` format. See OpenRouter's model list for all available models.
961
+
962
+ **Credential:** `openrouter_key` (field: `token`)
963
+
964
+ ### Custom
965
+
966
+ For any provider not listed above. The model ID and API routing are handled by the underlying pi.dev agent harness.
967
+
968
+ ```toml
969
+ [models.my-model]
970
+ provider = "custom"
971
+ model = "your-model-name"
972
+ authType = "api_key"
973
+ ```
974
+
975
+ **Credential:** `custom_key` (field: `token`)
976
+
977
+ ## Mixing Models
978
+
979
+ Each agent can use a different model. Define all models in the project's `config.toml`, then reference them by name in each agent's `config.toml`:
980
+
981
+ ```
982
+ config.toml → [models.sonnet], [models.gpt4o], [models.groq-llama]
983
+ agents/dev/config.toml → models = ["sonnet"]
984
+ agents/reviewer/config.toml → models = ["gpt4o"]
985
+ agents/devops/config.toml → models = ["groq-llama"]
986
+ ```
987
+
988
+ ## Model Fallback
989
+
990
+ Agents can list multiple models to create a fallback chain. When the primary model is rate-limited or unavailable, Action Llama automatically tries the next model in the list:
991
+
992
+ ```toml
993
+ # agents/<name>/config.toml
994
+ models = ["sonnet", "haiku", "gpt4o"]
995
+ ```
996
+
997
+ Fallback switching is instant — there is no delay when moving to the next model. Exponential backoff only kicks in after all models in the chain have been exhausted.
998
+
999
+ A circuit breaker tracks model availability in memory. When a model returns a rate limit or overload error, it is marked unavailable for 60 seconds. After the cooldown expires, the model is retried.
1000
+
1001
+ ## Credential Setup
1002
+
1003
+ Each provider requires a corresponding credential in `~/.action-llama/credentials/`. Run `al doctor` to configure them interactively.
1004
+
1005
+ LLM credentials are loaded automatically based on the models referenced in the agent's `models` list in `config.toml` — they do not need to be listed in the agent's `credentials` array. The `credentials` array is for runtime credentials the agent uses during execution (GitHub tokens, SSH keys, etc.).
1006
+
1007
+ See [Credentials](/reference/credentials) for the full credential reference.
1008
+
1009
+ ---
1010
+
1011
+ # Webhooks
1012
+
1013
+ Action Llama agents can be triggered by webhooks in addition to (or instead of) cron schedules. Seven providers are supported: GitHub, Sentry, Linear, Mintlify, Slack, Discord, and X (Twitter).
1014
+
1015
+ ## Supported Providers
1016
+
1017
+ | Provider | Type | Description |
1018
+ |----------|------|-------------|
1019
+ | [GitHub](/reference/webhooks/github) | `"github"` | Repository events: issues, pull requests, pushes, workflow runs, and more |
1020
+ | [Sentry](/reference/webhooks/sentry) | `"sentry"` | Error monitoring events: alerts, issues, errors, comments |
1021
+ | [Linear](/reference/webhooks/linear) | `"linear"` | Project management events: issues, comments, labels |
1022
+ | [Mintlify](/reference/webhooks/mintlify) | `"mintlify"` | Documentation events: build successes and failures |
1023
+ | [Slack](/reference/webhooks/slack) | `"slack"` | Workspace events: messages, app mentions, reactions |
1024
+ | [Discord](/reference/webhooks/discord) | `"discord"` | Discord Interactions Endpoint: slash commands, message components, modals, autocomplete |
1025
+ | [X (Twitter)](/reference/webhooks/twitter) | `"twitter"` | Account activity events: tweets, likes, follows, direct messages |
1026
+
1027
+ See each provider's page for filter fields, setup instructions, and example configurations.
1028
+
1029
+ ## Defining Webhook Sources
1030
+
1031
+ Webhook sources are defined once in the project's `config.toml`. Each source has a name, a provider type, and an optional credential for signature validation:
1032
+
1033
+ ```toml
1034
+ [webhooks.my-github]
1035
+ type = "github"
1036
+ credential = "MyOrg" # credential instance name (github_webhook_secret:MyOrg)
1037
+
1038
+ [webhooks.my-sentry]
1039
+ type = "sentry"
1040
+ credential = "SentryProd" # credential instance name (sentry_client_secret:SentryProd)
1041
+
1042
+ [webhooks.my-linear]
1043
+ type = "linear"
1044
+ credential = "LinearMain" # credential instance name (linear_webhook_secret:LinearMain)
1045
+
1046
+ [webhooks.my-mintlify]
1047
+ type = "mintlify"
1048
+ credential = "MintlifyMain" # credential instance name (mintlify_webhook_secret:MintlifyMain)
1049
+
1050
+ [webhooks.my-slack]
1051
+ type = "slack"
1052
+ credential = "MainWorkspace" # credential instance name (slack_signing_secret:MainWorkspace)
1053
+
1054
+ [webhooks.my-twitter]
1055
+ type = "twitter"
1056
+ credential = "MyXApp" # credential instance name (x_twitter_api:MyXApp)
1057
+ ```
1058
+
1059
+ | Field | Type | Required | Description |
1060
+ |-------|------|----------|-------------|
1061
+ | `type` | string | Yes | Provider type: `"github"`, `"sentry"`, `"linear"`, `"mintlify"`, `"slack"`, `"discord"`, or `"twitter"` |
1062
+ | `credential` | string | No | Credential instance name for HMAC signature validation. Omit for unsigned webhooks. |
1063
+
1064
+ ## Agent Webhook Triggers
1065
+
1066
+ Agents reference a webhook source by name and add filters in their `config.toml`:
1067
+
1068
+ ```toml
1069
+ # agents/<name>/config.toml
1070
+ [[webhooks]]
1071
+ source = "my-github"
1072
+ repos = ["acme/app"]
1073
+ events = ["issues"]
1074
+ actions = ["labeled"]
1075
+ labels = ["agent"]
1076
+ ```
1077
+
1078
+ Each `[[webhooks]]` entry is a trigger. The `source` field (referencing a name from the project's `config.toml`) is required. All filter fields are optional — omit all of them to trigger on everything from that source.
1079
+
1080
+ An agent must have at least one of `schedule` or `webhooks` (or both).
1081
+
1082
+ ## How Webhooks Work at Runtime
1083
+
1084
+ 1. The gateway receives a webhook POST request at `/webhooks/<type>` (e.g. `/webhooks/github`)
1085
+ 2. It verifies the payload signature using secrets loaded from the credential instances defined in `config.toml` webhook sources
1086
+ 3. It parses the event into a `WebhookContext` (source, event, action, repo, etc.)
1087
+ 4. It matches the context against each agent's webhook triggers
1088
+ 5. Matching agents are triggered with the webhook context injected into their prompt
1089
+
1090
+ ## Hybrid Agents
1091
+
1092
+ Agents can have both `schedule` and `webhooks`. Scheduled runs poll for work proactively; webhook runs respond to events immediately.
1093
+
1094
+ ## Troubleshooting
1095
+
1096
+ ### Webhooks not firing
1097
+
1098
+ 1. **Check the webhook URL** — GitHub/Sentry/Linear must be able to reach your gateway. For local development, use a tunnel (e.g. ngrok, Cloudflare Tunnel).
1099
+ 2. **Check the webhook secret** — if using HMAC validation, the secret in `al creds` must match the one configured in the external service.
1100
+ 3. **Check event filters** — verify the `events`, `actions`, and other filter fields in the agent's `config.toml` match the incoming event.
1101
+
1102
+ ```bash
1103
+ al doctor # Validates webhook trigger field names and types
1104
+ ```
1105
+
1106
+ ### Webhook events being dropped
1107
+
1108
+ If runners are busy, events are queued (up to `workQueueSize`, default 100). If the queue is full, old events are dropped. Check queue depth with `al stat`.
1109
+
1110
+ To handle more concurrent events, increase `scale` in the agent's `config.toml`:
1111
+
1112
+ ```toml
1113
+ scale = 3 # Run up to 3 instances concurrently
1114
+ ```
1115
+
1116
+ ## Discord Webhooks
1117
+
1118
+ Discord support uses the **Interactions Endpoint** (HTTP-based), which covers slash commands, message components, modals, and autocomplete. This requires a `discord_bot` credential with your application's public key for Ed25519 signature verification.
1119
+
1120
+ | Filter Field | Type | Description |
1121
+ |---|---|---|
1122
+ | `events` | string[] | Interaction types: `application_command`, `message_component`, `modal_submit`, `autocomplete` |
1123
+ | `guilds` | string[] | Discord guild (server) IDs to filter on |
1124
+ | `channels` | string[] | Channel IDs to filter on |
1125
+ | `commands` | string[] | Slash command names (e.g. `ask`, `deploy`) — only applies to `application_command` and `autocomplete` events |
1126
+
1127
+ ### Setup
1128
+
1129
+ 1. In the [Discord Developer Portal](https://discord.com/developers/applications), create or select your application
1130
+ 2. Under **General Information**, copy your **Application ID** and **Public Key**
1131
+ 3. Under **Bot**, copy or reset your **Bot Token**
1132
+ 4. Add these to your credentials: `al creds add discord_bot`
1133
+ 5. Set your Interactions Endpoint URL to `https://your-server:8080/webhooks/discord`
1134
+ 6. Discord will send a PING verification request — Action Llama responds automatically after validating the signature
1135
+
1136
+ ### Example Configuration
1137
+
1138
+ ```toml
1139
+ # In project config.toml
1140
+ [webhooks.my-discord]
1141
+ type = "discord"
1142
+ credential = "MyBot" # discord_bot credential instance name
1143
+ ```
1144
+
1145
+ ```toml
1146
+ # In agents/<name>/config.toml
1147
+ [[webhooks]]
1148
+ source = "my-discord"
1149
+ events = ["application_command"]
1150
+ commands = ["ask", "status"]
1151
+ guilds = ["1234567890"]
1152
+ ```
1153
+
1154
+ ---
1155
+
1156
+ # GitHub Webhooks
1157
+
1158
+ GitHub webhooks let agents respond to repository events like issues, pull requests, and pushes.
1159
+
1160
+ ## Filter Fields (all optional)
1161
+
1162
+ | Field | Type | Description |
1163
+ |-------|------|-------------|
1164
+ | `repos` | string[] | Only trigger for these repos |
1165
+ | `orgs` | string[] | Only trigger for these organizations |
1166
+ | `org` | string | Only trigger for this organization (singular form) |
1167
+ | `events` | string[] | GitHub event types (issues, pull_request, push, etc.) |
1168
+ | `actions` | string[] | Event actions (opened, labeled, closed, etc.) |
1169
+ | `labels` | string[] | Only when issue/PR has these labels |
1170
+ | `assignee` | string | Only when assigned to this user |
1171
+ | `author` | string | Only for this author |
1172
+ | `branches` | string[] | Only for these branches |
1173
+ | `conclusions` | string[] | Only for workflow_run events with these conclusions (success, failure, cancelled, skipped, timed_out, action_required) |
1174
+
1175
+ ## Setup
1176
+
1177
+ 1. In your GitHub repo, go to **Settings > Webhooks > Add webhook**
1178
+ 2. Set the payload URL to your Action Llama gateway (e.g. `https://your-server:8080/webhooks/github`)
1179
+ 3. Set content type to `application/json`
1180
+ 4. Set the secret to match the `github_webhook_secret` credential instance referenced by the webhook source in `config.toml`
1181
+ 5. Select the events you want to receive
1182
+
1183
+ ## Using ngrok for Local Development
1184
+
1185
+ ```bash
1186
+ ngrok http 8080
1187
+ ```
1188
+
1189
+ Use the ngrok URL as your webhook payload URL in GitHub. See [Using Webhooks](/first-steps/using-webhooks) for a full tutorial.
1190
+
1191
+ ## Example Configuration
1192
+
1193
+ ```toml
1194
+ # In project config.toml
1195
+ [webhooks.my-github]
1196
+ type = "github"
1197
+ credential = "MyOrg"
1198
+ ```
1199
+
1200
+ ```toml
1201
+ # In agents/<name>/config.toml
1202
+ [[webhooks]]
1203
+ source = "my-github"
1204
+ repos = ["acme/app"]
1205
+ events = ["issues"]
1206
+ actions = ["labeled"]
1207
+ labels = ["agent"]
1208
+ ```
1209
+
1210
+ ---
1211
+
1212
+ # Sentry Webhooks
1213
+
1214
+ Sentry webhooks let agents respond to error alerts, metric alerts, and issue events.
1215
+
1216
+ ## Filter Fields (all optional)
1217
+
1218
+ | Field | Type | Description |
1219
+ |-------|------|-------------|
1220
+ | `resources` | string[] | Resource types: event_alert, metric_alert, issue, error, comment |
1221
+
1222
+ ## Setup
1223
+
1224
+ 1. In Sentry, go to **Settings > Developer Settings > New Internal Integration**
1225
+ 2. Set the webhook URL to your gateway (e.g. `https://your-server:8080/webhooks/sentry`)
1226
+ 3. Copy the client secret to `~/.action-llama/credentials/sentry_client_secret/<instance>/secret`
1227
+ 4. Select the resource types you want to receive
1228
+
1229
+ ## Example Configuration
1230
+
1231
+ ```toml
1232
+ # In project config.toml
1233
+ [webhooks.my-sentry]
1234
+ type = "sentry"
1235
+ credential = "SentryProd"
1236
+ ```
1237
+
1238
+ ```toml
1239
+ # In agents/<name>/config.toml
1240
+ [[webhooks]]
1241
+ source = "my-sentry"
1242
+ resources = ["event_alert", "issue"]
1243
+ ```
1244
+
1245
+ ---
1246
+
1247
+ # Linear Webhooks
1248
+
1249
+ Linear webhooks let agents respond to issue and comment events in your Linear workspace.
1250
+
1251
+ ## Filter Fields (all optional)
1252
+
1253
+ | Field | Type | Description |
1254
+ |-------|------|-------------|
1255
+ | `organizations` | string[] | Only trigger for these Linear organizations |
1256
+ | `events` | string[] | Linear event types (issues, issue_comment, etc.) |
1257
+ | `actions` | string[] | Event actions (create, update, delete, etc.) |
1258
+ | `labels` | string[] | Only when issue has these labels |
1259
+ | `assignee` | string | Only when assigned to this user (email) |
1260
+ | `author` | string | Only for this author (email) |
1261
+
1262
+ ## Setup
1263
+
1264
+ 1. In Linear, go to **Settings > Workspace > Webhooks**
1265
+ 2. Click **Create webhook**
1266
+ 3. Set the URL to your Action Llama gateway (e.g. `https://your-server:8080/webhooks/linear`)
1267
+ 4. Set the secret to match the `linear_webhook_secret` credential instance referenced by the webhook source in `config.toml`
1268
+ 5. Select the resource types you want to receive (Issues, Comments, etc.)
1269
+
1270
+ ## Example Configuration
1271
+
1272
+ ```toml
1273
+ # In project config.toml
1274
+ [webhooks.linear-main]
1275
+ type = "linear"
1276
+ credential = "main-workspace"
1277
+ ```
1278
+
1279
+ ```toml
1280
+ # In agents/<name>/config.toml
1281
+ [[webhooks]]
1282
+ source = "linear-main"
1283
+ events = ["issues", "issue_comment"]
1284
+ actions = ["create", "update"]
1285
+ organizations = ["your-org-id"]
1286
+ labels = ["bug", "ready-for-dev"]
1287
+ ```
1288
+
1289
+ ---
1290
+
1291
+ # Mintlify Webhooks
1292
+
1293
+ Mintlify webhooks let agents respond to documentation build events.
1294
+
1295
+ ## Filter Fields (all optional)
1296
+
1297
+ | Field | Type | Description |
1298
+ |-------|------|-------------|
1299
+ | `projects` | string[] | Only trigger for these Mintlify projects |
1300
+ | `events` | string[] | Mintlify event types (build, etc.) |
1301
+ | `actions` | string[] | Event actions (failed, succeeded, etc.) |
1302
+ | `branches` | string[] | Only for these branches |
1303
+
1304
+ ## Setup
1305
+
1306
+ 1. In Mintlify, go to your project settings
1307
+ 2. Navigate to **Webhooks** or **Integrations**
1308
+ 3. Add a webhook with URL: `https://your-server:8080/webhooks/mintlify`
1309
+ 4. Set the secret to match the `mintlify_webhook_secret` credential instance referenced by the webhook source in `config.toml`
1310
+ 5. Select build events you want to receive (build failures, successes, etc.)
1311
+
1312
+ ## Example Configuration
1313
+
1314
+ ```toml
1315
+ # In project config.toml
1316
+ [webhooks.mintlify-docs]
1317
+ type = "mintlify"
1318
+ credential = "docs-project"
1319
+ ```
1320
+
1321
+ ```toml
1322
+ # In agents/<name>/config.toml
1323
+ [[webhooks]]
1324
+ source = "mintlify-docs"
1325
+ events = ["build"]
1326
+ actions = ["failed"]
1327
+ projects = ["my-docs"]
1328
+ ```
1329
+
1330
+ ---
1331
+
1332
+ # Slack Webhooks
1333
+
1334
+ Slack webhooks let agents respond to workspace events like messages, app mentions, and reactions via the Slack Events API.
1335
+
1336
+ ## Filter Fields (all optional)
1337
+
1338
+ | Field | Type | Description |
1339
+ |-------|------|-------------|
1340
+ | `events` | string[] | Slack event types: `message`, `app_mention`, `reaction_added`, `reaction_removed`, `channel_created`, `member_joined_channel` |
1341
+ | `channels` | string[] | Only trigger for these Slack channel IDs |
1342
+ | `team_ids` | string[] | Only trigger for these Slack workspace/team IDs |
1343
+
1344
+ ## Setup
1345
+
1346
+ 1. In the Slack API dashboard (https://api.slack.com/apps), create or select your app
1347
+ 2. Go to **Event Subscriptions** and enable events
1348
+ 3. Set the Request URL to `https://your-server:8080/webhooks/slack`
1349
+ 4. The gateway automatically responds to Slack's URL verification challenge
1350
+ 5. Subscribe to the bot events you need (e.g., `message.channels`, `app_mention`)
1351
+ 6. Go to **Basic Information → App Credentials** and copy the **Signing Secret**
1352
+ 7. Set the signing secret credential to match `slack_signing_secret` referenced by the webhook source in `config.toml`
1353
+
1354
+ ## URL Verification
1355
+
1356
+ The Slack provider automatically handles URL verification challenges. When Slack sends a `url_verification` request, the gateway validates the signature and responds with the challenge token. No manual setup is needed.
1357
+
1358
+ ## Replay Protection
1359
+
1360
+ The provider rejects requests with timestamps older than 5 minutes, protecting against replay attacks.
1361
+
1362
+ ## Example Configuration
1363
+
1364
+ ```toml
1365
+ # In project config.toml
1366
+ [webhooks.my-slack]
1367
+ type = "slack"
1368
+ credential = "MainWorkspace"
1369
+ ```
1370
+
1371
+ ```toml
1372
+ # In agents/<name>/config.toml
1373
+ [[webhooks]]
1374
+ source = "my-slack"
1375
+ events = ["message", "app_mention"]
1376
+ channels = ["C0123456789"]
1377
+ team_ids = ["T0123456789"]
1378
+ ```
1379
+
1380
+ ---
1381
+
1382
+ # Twitter Webhooks
1383
+
1384
+ X (Twitter) webhooks let agents respond to account activity events like tweets, likes, follows, and direct messages via the Account Activity API.
1385
+
1386
+ ## Filter Fields (all optional)
1387
+
1388
+ | Field | Type | Description |
1389
+ |-------|------|-------------|
1390
+ | `events` | string[] | Twitter event types: `tweet_create_events`, `tweet_delete_events`, `favorite_events`, `follow_events`, `unfollow_events`, `block_events`, `unblock_events`, `mute_events`, `unmute_events`, `direct_message_events`, `direct_message_indicate_typing_events`, `direct_message_mark_read_events` |
1391
+ | `users` | string[] | Only trigger for these subscribed user IDs (`for_user_id` values) |
1392
+
1393
+ ## Setup
1394
+
1395
+ 1. In the X Developer Portal, create or open your app
1396
+ 2. Under **Keys and tokens**, note your **Consumer Key** and **Consumer Secret**
1397
+ 3. Generate an **Access Token** and **Access Token Secret** for your bot user account
1398
+ 4. Run `al doctor` — it will prompt for all four values plus your **Bearer Token**
1399
+ 5. Register your webhook URL with the Account Activity API: `https://your-server:8080/webhooks/twitter`
1400
+ 6. The gateway handles the CRC challenge-response handshake automatically using the Consumer Secret
1401
+ 7. On startup, the gateway automatically subscribes your bot user if Access Token credentials are configured
1402
+
1403
+ ## Credentials
1404
+
1405
+ The `x_twitter_api` credential has five fields:
1406
+
1407
+ | Field | Required | Description |
1408
+ |-------|----------|-------------|
1409
+ | `consumer_key` | Yes | OAuth 1.0a Consumer Key |
1410
+ | `consumer_secret` | Yes | OAuth 1.0a Consumer Secret (used for CRC and HMAC validation) |
1411
+ | `bearer_token` | Yes | App-Only Bearer Token (used for API v2 validation) |
1412
+ | `access_token` | No | OAuth 1.0a Access Token for the bot user (enables auto-subscribe) |
1413
+ | `access_token_secret` | No | OAuth 1.0a Access Token Secret for the bot user (enables auto-subscribe) |
1414
+
1415
+ When `access_token` and `access_token_secret` are provided, the gateway will automatically check the webhook registration status and subscribe the bot user to the Account Activity API on startup.
1416
+
1417
+ ## CRC Challenge
1418
+
1419
+ The Twitter provider automatically handles CRC (Challenge-Response Check) validation. When Twitter sends a GET request with a `crc_token` query parameter, the gateway responds with the correct HMAC-SHA256 response token. No manual setup is needed.
1420
+
1421
+ ## Example Configuration
1422
+
1423
+ ```toml
1424
+ # In project config.toml
1425
+ [webhooks.my-twitter]
1426
+ type = "twitter"
1427
+ credential = "MyXApp"
1428
+ ```
1429
+
1430
+ ```toml
1431
+ # In agents/<name>/config.toml
1432
+ [[webhooks]]
1433
+ source = "my-twitter"
1434
+ events = ["tweet_create_events", "favorite_events", "direct_message_events"]
1435
+ users = ["123456789"]
1436
+ ```