Each pylon you create gets its own config file atDocumentation Index
Fetch the complete documentation index at: https://docs.pylon.to/llms.txt
Use this file to discover all available pages before exploring further.
~/.pylon/pylons/<name>/pylon.yaml. Running pylon construct <name> creates this file through an interactive prompt; you can open it in your editor at any time with pylon edit <name>. Per-pylon settings take priority over the global defaults in ~/.pylon/config.yaml, so you only need to specify fields that differ from the global configuration.
Examples
These are complete, copy-pasteablepylon.yaml files covering the three most common patterns.
Sentry webhook with approval
A webhook pylon that triages Sentry errors. HMAC validation ensures only authentic Sentry payloads are accepted, andapproval: true requires a human to approve each job before the agent starts.
GitHub PR review (no approval)
A webhook pylon that reviews every pull request automatically. The workspace repo and branch are resolved dynamically from the GitHub webhook payload, so the agent always clones the exact branch under review. No approval step — the agent starts immediately.Cron audit (scheduled weekly)
A cron pylon that runs a weekly security audit. There is no webhook trigger — Pylon fires the job on a schedule. The workspace is a fresh git clone so the agent always audits the latest code.Field reference
Top-level fields
Identifier for this pylon. Must match the directory name under
~/.pylon/pylons/. Set automatically by pylon construct.Optional human-readable description shown in
pylon list output.When
true, pylon start skips this pylon entirely. Use this to temporarily pause a pylon without deleting it.ISO 8601 timestamp set automatically when you run
pylon construct. Do not edit this field.trigger
How the pylon is activated. Accepted values:
webhook, cron.URL path for the webhook endpoint (for example,
/my-pipeline). Required when type is webhook. Pylon registers this path on the global server port when the daemon starts.Cron expression for scheduled pylons (for example,
0 9 * * 1-5 for weekdays at 9 AM). Required when type is cron.HMAC secret used to validate incoming webhook signatures. When set, Pylon rejects requests whose signature does not match. Use
${VAR} to reference a value from ~/.pylon/.env.HTTP header Pylon reads to find the HMAC signature (for example,
X-Hub-Signature-256). Required when trigger.secret is set.Overrides
server.public_url from the global config for this pylon only. Useful when a single Pylon server serves webhooks from multiple domains.workspace
How the agent accesses source code. Accepted values:
git-clone— Pylon clones the repository fresh for each job.git-worktree— Pylon creates a worktree from a local clone, which is faster than a full clone.local— Pylon mounts a local directory from the host into the container.none— No codebase. Use this for pylons that do not need to read or modify files.
Git repository URL. Use SSH (
git@github.com:org/repo.git) for private repositories. Supports template variables so you can resolve the URL from the webhook payload (for example, {{ .body.repository.clone_url }}). Required when type is git-clone or git-worktree.Branch or tag to check out. Supports template variables (for example,
{{ .body.pull_request.head.ref }}). Defaults to main when not specified.Absolute path to a local directory on the host. Pylon mounts this directory into the agent container. Required when
type is local.channel
The channel block is optional. When omitted, the pylon uses the global defaults.channel from config.yaml. When present, the pylon-level settings take full priority.
Notification backend for this pylon. Accepted values:
telegram, slack, webhook, stdout. Overrides the global default.Telegram connection settings. Accepts the same fields as
defaults.channel.telegram in the global config. Required when channel.type is telegram.Slack connection settings. Accepts the same fields as
defaults.channel.slack in the global config. Required when channel.type is slack.Thread or topic subject line shown in the notification. Supports template variables for injecting webhook payload data.
Notification message body displayed above the Approve/Ignore buttons. Supports template variables.
When
true, Pylon sends a notification with Approve and Ignore buttons and waits for a human to respond before starting the agent. When false, the agent starts immediately on every trigger event.agent
The agent block is optional. When omitted, the pylon uses defaults.agent from the global config.
Agent runtime for this pylon. Accepted values:
claude, opencode. Overrides the global default.Authentication method. Overrides the global default for the chosen agent type. Accepted values:
oauth, api_key (Claude); none, api-key (OpenCode).API key reference, used when
auth is api_key. Use ${VAR} to reference a value from ~/.pylon/.env (for example, ${ANTHROPIC_API_KEY}). This lets you assign a different key per pylon.LLM provider for OpenCode agents. Accepted values:
anthropic, openai, google. Overrides the global default.Additional environment variables injected into the agent container. Use this to pass service-specific configuration without hardcoding values in the prompt.
The instruction sent to the agent when a job starts. Supports Go template syntax to inject data from the webhook payload. See the Prompt templates section below.
Maximum run time for a single job (for example,
10m, 30m). Overrides docker.default_timeout from the global config.Host directories to mount into the agent container. Each entry uses the format
source:target[:ro|rw]. Defaults to read-only (ro) when the mode is omitted. See the Volumes section below.Prompt templates
Pylon renders your agent prompt as a Go template before sending it to the agent container. This means you can embed data from the incoming webhook payload directly in the prompt, so the agent receives context-rich instructions without any extra glue code. The same template syntax works inchannel.topic and channel.message, letting you surface the right information in your notification thread title and preview message.
Template syntax
Access a field from the webhook JSON body using double curly braces and the.body prefix:
text/template package. Any valid Go template expression works, including conditionals and range loops, but most prompts only need simple field substitutions.
Available variables
| Variable | Description |
|---|---|
{{ .body.error }} | Generic top-level error message |
{{ .body.issue.title }} | Issue title (GitHub, Linear, or generic) |
{{ .body.number }} | Pull request or issue number |
{{ .body.pull_request.title }} | GitHub pull request title |
{{ .body.pull_request.head.ref }} | Branch name for a pull request |
{{ .body.repository.clone_url }} | HTTPS clone URL for the repository |
{{ .body.data.event.title }} | Sentry event title |
{{ .body.data.event.culprit }} | Sentry culprit file and function |
{{ .body.data.event.level }} | Sentry severity level (e.g. error, fatal) |
{{ .body.data.event.platform }} | Sentry platform (e.g. python, javascript) |
{{ .body.data.event.web_url }} | Link to the Sentry issue in the web UI |
Template examples
Sentry error triage — inject event details from a Sentry webhook:workspace.repo and workspace.ref, so Pylon clones the exact branch being reviewed.
Notification channel fields — template variables apply to channel.topic and channel.message too, not just the agent prompt:
Testing template expansion
Usepylon test with a --payload flag to see how your templates expand against a sample payload before sending real traffic:
Building channel.message interactively
Writing message templates by hand means guessing at payload field names. Nexus ships an interactive builder that reads the last real trigger payload for a pylon, shows you its structure, and writes a channel.message block directly into pylon.yaml when you save.
Trigger the pylon at least once
Send a real webhook or run
pylon test <name> so Pylon has a sample payload to read from. The builder refuses to open if the pylon has never fired.Open Nexus and select the pylon
Run
pylon nexus, highlight the pylon in the sidebar, and press l or enter to focus the detail panel.Press `a` to open the builder
Nexus renders the payload as collapsible groups. Navigate with
j/k, expand groups with space, and check fields you want in the message with space.Tips
Volumes
By default, agent containers are isolated Docker environments with no access to your host filesystem beyond the mounted workspace. Volumes let you mount additional host directories into the container — typically credential directories or configuration files that CLI tools inside the container need to authenticate with external services.Configuring volumes
Theagent.volumes list in pylon.yaml defines host paths to mount into the agent container. Each entry uses Docker-style source:target[:mode] syntax:
ro (read-only). Set it to rw if the tool needs to write to the mounted directory.
Source paths can use ~ to reference the home directory of the user running pylon start.
If you mount a directory containing scripts (e.g.
~/scripts:/opt/scripts:ro), the scripts must be executable (chmod +x) on the host. The agent runs as a non-root user inside the container, so the file permissions must allow execution by that user.Credential patterns
There are two common ways to pass credentials into agent containers: Environment variables — for service accounts with static tokens. Store tokens in~/.pylon/.env and reference them in the env block:
Security model
Pylon blocks mounting dangerous host paths to prevent container escape:/var/run/docker.sock— would let the agent spin up privileged containers/,/etc,/root— would expose sensitive system files
rw when the tool genuinely needs write access.
Example: Google Cloud credentials
Authenticate on the host, then mount the credential directory so the agent’s container can usegcloud:
gcloud inside the container, which reads the mounted credentials without needing a separate login.
Config resolution order
When Pylon runs a job it merges settings from both files, with the per-pylon file taking full priority:| Setting | Resolved from |
|---|---|
channel.type | Per-pylon channel.type -> global defaults.channel.type |
agent.type | Per-pylon agent.type -> global defaults.agent.type -> claude |
agent.auth | Per-pylon agent.auth -> global agent defaults -> oauth (Claude) |
agent.timeout | Per-pylon agent.timeout -> global docker.default_timeout -> 15m |
agent.volumes | Per-pylon agent.volumes (no global fallback) |