Examples
Eight agents under examples/ run end to end with no SaaS account and no model key. Each has a README and a test (make test-e2e-examples; the data analyst has its own target) that runs it against recorded GitHub, Sentry, PagerDuty, Calendar and Slack servers and a fixture model, plus the real surface gateway for chat. Only the Telegram and Twilio paths need real accounts.
| Example | Shows | Path |
|---|---|---|
| Support desk | Answers from your docs, hands off to a human | examples/support-desk/ |
| PR triage | A webhook trigger, GitHub and Slack actions | examples/pr-triage-webhook/ |
| Incident responder | Two triggers and an approval node | examples/incident-responder/ |
| Daily digest | A timezone-aware schedule and a hard budget | examples/daily-digest/ |
| Telegram assistant | The surface gateway and a calendar action | examples/telegram-assistant/ |
| Voice receptionist | Twilio under a hard spend cap | examples/voice-receptionist/ |
| Data analyst | pandas in a microVM, deny-by-default egress | examples/data-analyst/ |
| Eval-gated deploy | A CI gate that blocks a regression | examples/eval-gated-deploy/ |
The REST examples assume export API=http://localhost:8080 TOKEN=<JWT or API key> and send -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json". Start the stack first (Develop locally).
Support desk
Section titled “Support desk”A webchat agent answers from your docs, shows its source, and hands the conversation to a human when it cannot answer, pinging Slack. The APIs are in Your documents and memory.
make dev-infra && make run-api # terminal 1python3 examples/support-desk/setup.py # creates the agent, uploads the docs# create an API key with scope runs:execute (Settings, API keys), then open examples/support-desk/demo.htmlAsk How do I reset my password? for a cited answer, then I want a refund: the widget shows “Connecting you to a human”. An operator replies with POST /v1/sessions/{id}/operator-messages and the reply appears in the widget. setup.py deploys over REST because it also uploads the documents and mints the widget key.
PR triage to a Slack thread
Section titled “PR triage to a Slack thread”Every opened GitHub pull request is read, triaged by a model in one line, commented on the PR, and announced in Slack with the verdict in the thread. It uses a webhook trigger, the GitHub get_pr and comment_pr actions and Slack post_message and reply_thread, in a workflow.json graph.
cd examples/pr-triage-webhookcurl -X POST $API/v1/agents -H "Authorization: Bearer $TOKEN" -d '{"name":"pr-triage-webhook","description":"PR triage","systemPrompt":"Workflow agent: see workflow.json"}'curl -X PUT $API/v1/agents/pr-triage-webhook/workflow -H "Authorization: Bearer $TOKEN" -d @workflow.jsoncurl -X POST $API/v1/agents/pr-triage-webhook/triggers -H "Authorization: Bearer $TOKEN" -d @trigger.json# -> {"id": "<trigger-id>", "secret": "<shown once>"}./send-fixture.sh $API/v1/hooks/<trigger-id> <secret> # signed pull_request.openedFor real GitHub, install the github and slack connectors, then add a repository webhook with payload URL $API/v1/hooks/<trigger-id>, content type JSON, the trigger secret and the Pull requests event. A re-sent delivery returns 200 duplicate and starts no second run. A bad signature is 401; an agent over its budget gets 402.
Incident responder with an approval
Section titled “Incident responder with an approval”A Sentry alert or PagerDuty incident is summarized with the Sentry issue and PagerDuty incident in hand, a runbook step is posted to Slack, and the run parks at an approval node. Approving posts a note on the PagerDuty incident. Denying fails the step and posts nothing. See Holds and trust for the approval mechanism.
cd examples/incident-responder# create the agent and PUT workflow.json as above, then create both triggerscurl -X POST $API/v1/agents/incident-responder/triggers -H "Authorization: Bearer $TOKEN" -d @trigger-sentry.json # and trigger-pagerduty.json./send-fixture.sh sentry $API/v1/hooks/<sentry-trigger-id> <secret># the run parks; approve or deny it:curl -X POST $API/v1/runs/<run-id>/takeover/<takeover-id>/grant -H "Authorization: Bearer $TOKEN" -d '{"notes":"go"}'curl -X POST $API/v1/runs/<run-id>/takeover/<takeover-id>/deny -H "Authorization: Bearer $TOKEN" -d '{"notes":"not now"}'Daily digest to Slack
Section titled “Daily digest to Slack”Every weekday at 09:00 New York time, the agent lists open GitHub PRs, has a model write a short digest and posts it to Slack. It is the smallest unattended agent: a schedule with a timezone, a three-node workflow and a hard budget cap.
cd examples/daily-digestpal deploy # agent + system prompt + workflow from agent.yaml# install the slack and github connectors, edit owner/repo/channel in schedule.json, then:curl -X POST $API/v1/schedules -H "Authorization: Bearer $TOKEN" -d @schedule.json # nextFireAt = next weekday 09:00 NYpal deploy covers the agent. The schedule has no deploy field, so you create it over REST. Run it now with POST /v1/runs. The scheduler polls every 60 s.
Telegram assistant
Section titled “Telegram assistant”Message a Telegram bot (or WhatsApp Cloud number) and a workflow reads your Google Calendar and answers in the same chat. It uses the surface gateway, the Telegram secret-token and WhatsApp X-Hub-Signature-256 checks (Set up PAL) and the calendar list_events action.
cd examples/telegram-assistantpal deploycurl -X POST $API/v1/runs -H "Authorization: Bearer $TOKEN" -d '{"agentName":"telegram-assistant","input":{"text":"hi"}}' # priming run# run the gateway (see the README), then setWebhook with secret_token, and message the botThe priming run is needed because the gateway starts runs over gRPC, which refuses an agent that has never had a REST run (no promoted version). Replies are plain text, once, within 3 minutes.
Voice receptionist
Section titled “Voice receptionist”A Twilio number answers inbound calls under a hard spend cap. Forged webhooks get 403. An over-budget call is declined with <Reject/> before it connects. The status callback reconciles the $0.05 reservation to the real per-started-minute cost. Details are in Set up PAL.
cd examples/voice-receptionistpal deploycurl -X PUT $API/v1/agents/voice-receptionist/budget -H "Authorization: Bearer $TOKEN" -d '{"maxCostUsdPerDay":2,"hardFail":true}'curl -X POST $API/v1/voice/numbers -H "Authorization: Bearer $TOKEN" -d @number.json # your SID, auth token, numberBudgets and voice numbers are not part of the deploy manifest, so they stay on REST. The inbound reply is a fixed greeting; the realtime conversation needs the LiveKit media worker.
Data analyst in a sandbox
Section titled “Data analyst in a sandbox”Upload a CSV, run pandas in an isolated microVM and get JSON plus a chart back; an agent then explains the result. The code that touches the data never runs in the control plane, and egress is deny-by-default. See Sandbox lifecycle.
docker build -t pal/examples/data-analyst examples/data-analyst # then use the image digest belowVM=$(curl -s -XPOST $API/v1/runtime/schedule -H "Authorization: Bearer $TOKEN" \ -d '{"imageDigest":"<sha256:...>","isolation":"untrusted","network":"allowlist_domain"}' | jq -r .vmId)curl -XPUT "$API/v1/runtime/vms/$VM/files/content?path=sales.csv" -H "Authorization: Bearer $TOKEN" --data-binary @sales.csvcurl -XPOST $API/v1/runtime/vms/$VM/exec -H "Authorization: Bearer $TOKEN" \ -d '{"command":"python","argv":["/opt/analyze.py","/workspace/sales.csv"]}'make test-e2e-analyst runs TestDataAnalystSandbox against a stack with the scheduler and runtime manager running; it is not part of make test-e2e-examples. The default tier uses the manager’s docker backend with no network and a fixture model. The files API is Firecracker-only, so on the default tier the CSV goes in through exec. The Firecracker tier (needs /dev/kvm) adds the files-API upload and an audited egress deny.
Eval-gated deploy
Section titled “Eval-gated deploy”A CI pipeline that cannot ship a worse agent. It runs an eval suite against the candidate and records it with POST /v1/eval-runs. A 422 (regressed against the pinned baseline) stops the job before pal deploy --json. A passing change is deployed, a receipt is issued with POST /v1/runs/{id}/receipt and verified at POST /v1/runs/receipts/verify. The folder holds scripts and a sample GitHub Actions workflow. See Evaluations.
cd examples/eval-gated-deployEVAL_PIN=1 scripts/eval.sh . # baseline: 3/3 cases, pinned for branch mainscripts/eval.sh candidates/regressed; echo $? # 1: HTTP 422, nothing deploysscripts/eval.sh candidates/improved && scripts/release.sh candidates/improvedThe server stores the per-case results you post and compares the mean score. The script scores each case (assert.contains) from the run output.
Limits
Section titled “Limits”- A model reply is dropped into JSON-free connector parameters, so the prompts ask for one plain line. Keep that if you edit them.
- The incident trigger templates pin the Sentry organization and the PagerDuty incident or issue id to fixture values. Edit
trigger-*.jsonfor your account. - PR comments use the PR conversation (
comment_pr). Inline review comments on a diff line are not wired.