Hooks
A hook is an address you give a CI service or other webhook sender. When an event arrives, Saggar's relay holds the result until your Mac is listening, and Saggar either opens an agent terminal to investigate the failure, triages a labeled issue, or waits for you to look first. The point is that the investigation is already underway by the time you sit back down.
Setting one up
- Open a project, choose the Automations tab, select Hooks, and click New hook.
- Saggar asks the relay for an address and shows it with a signing secret, once.
- Click Set up GitHub with agent and your own agent registers the webhook on the repository with the GitHub CLI.
If you would rather do it by hand, copy the address and the secret into the
repository's webhook settings with the content type set to JSON and the
workflow_run, issues, and pull_request_review events selected.
GitHub sends a ping when the webhook is created. The hook shows Connected in the Automations tab once it arrives.
Using another webhook sender
Any sender can use the hook if it can send JSON and sign the raw request body with HMAC-SHA256.
- Put the hex digest in the
X-Hub-Signature-256header, prefixed withsha256=. - The JSON object must include a non-empty
title. - It can also include
key,repo,branch,sha,url,conclusion, anddetail. - Events with the same
keyreplace one another while queued.
A service with fixed payloads or a different signing scheme needs a small adapter to reshape and sign the request. The first accepted event marks the hook as connected.
GitHub issue triage
| Label | What the agent does |
|---|---|
saggar | Reads the issue with the GitHub CLI, checks it against the repository, and posts one concise triage comment. It then stops. |
saggar:act | Authorizes implementation. The agent works on a new branch in a sibling worktree, opens a pull request that closes the issue, and comments back with the result. It never pushes directly to the target branch. |
Both labels send the issue through the same review or automatic-investigation flow.
The label is the authorization boundary. The relay carries only the issue number, title, URL, repository, author, and intent; it drops the body and comments. The agent fetches those separately and treats them as untrusted problem reports, never as instructions.
Requested pull request changes
When a reviewer submits a formal Request changes review, Saggar fetches the review and its inline comments with the GitHub CLI. The agent groups concrete fixes, disagreements, resolved points, and questions, then comments on the pull request and stops.
Review prose does not cross the relay and cannot authorize changes. Add
saggar:act to the pull request before the review is submitted to let the
agent address clear feedback on the existing pull request branch. Forked pull
requests, unsafe branch names, and product decisions stop at triage.
Review first, investigate, or fix
Each hook has one of three modes.
| Mode | What happens when a run fails |
|---|---|
| Review first | The default. The run lands in the Activity tab as Needs you, with Investigate and Dismiss beside it, and the Automations tab wears a count in the project landing. |
| Investigate automatically | An agent terminal opens the moment the failure arrives, without stealing the screen. The agent reads the failure and reports back; it changes nothing unless you ask it to in that terminal. |
| Fix automatically | One step further: the agent may commit and push a fix. |
Either way the terminal is titled after the workflow and branch so it is easy to find in the Project menu.
Settings that apply to every hook
Two choices apply to every hook at once and live in Settings under Agents, in the Automation pane. Each hook keeps its own mode either way.
- Investigate with picks the agent a hook opens, defaulting to the last agent you launched.
- Pause automatic launches holds every failure an automatic hook would have acted on in the Activity tab, with a note saying why, until you turn it off.
What the agent is told
The prompt the agent receives is Saggar's own. It quotes the repository, workflow, branch, commit, and run URL as data and asks the agent to read the failed steps with the GitHub CLI.
The terminal opens in your checkout, which may be mid-edit, so the prompt
declares that directory read-only: no edits, no stash, no branch switch. A fix
is made in a sibling worktree cut at the failing commit, and pushed to the
branch only when your checkout isn't on it; otherwise the agent pushes a
hook/fix- branch named for the commit and opens a pull request, so your
local branch never falls behind its remote without warning.
A passing run on the same branch retires an earlier failure that was still waiting, and a repeat failure while an agent is already on it is held rather than doubled up.
This is what the handoff looks like. A Swift CI run failed on main, the hook opened a terminal titled after it, and the agent had pulled the failed log and traced the cause to a missing repository secret before anyone read the notification. The last step of the prompt matters as much as the first: a flaky, infrastructural, or judgment-shaped failure ends in a summary, not a push.
When the Mac is away
The relay keeps undelivered events for up to a week and hands them over the next time the Mac connects. Runs of the same workflow on the same branch replace one another while the Mac is away, so you come back to the latest result, not the history.
Sleep still wins: a hook cannot wake a Mac, so a closed lid means the investigation starts when you open it.
Transparency
Every delivery leaves a record in the project's Activity tab with its verdict: investigating, needs you, skipped, superseded, connected, or dismissed. Every delivery is also written to the remote-control audit log, so nothing arrives silently.
What the relay knows
Hooks ride the same relay and the same subscription as remote control, and the Mac still never listens on your network. Unlike a remote-control request, a webhook reaches the relay in the clear, because an external service sent it.
The relay keeps a small digest of it, a few named fields rather than the payload, and only a delivery signed with the hook's secret is accepted. Deleting a hook closes its address for good.
Ideas for hooks
A useful hook says that something deserves investigation or a decision, not merely that something happened. The generic endpoint can receive these signals today when the sender, or a small adapter, reshapes and signs them. Native support for more GitHub event types may follow the same model as CI runs, labeled issues, and requested pull request changes.
- Pull request review requested: run targeted checks, inspect the diff, flag risks, and prepare a review.
- Merge conflict introduced: explain the conflicting intent before anyone chooses whether an agent should resolve it.
- Dependency update opened: read the release notes, look for breaking changes, run the affected checks, and recommend a verdict.
- Deployment failed: separate code failures from infrastructure failures and connect the result to the responsible change.
- Sentry regression: correlate a new error with recent deployments and commits, then update one issue rather than opening a flock.
- Support escalation: turn a report into a reproduction recipe and likely owner without copying sensitive customer data into a prompt.
- Scheduled hygiene: find stale pull requests, unanswered issues, broken documentation links, or abandoned branches once a week.
These patterns tend to deepen through the same four steps: record the event, triage it, propose a response, then act only when the hook's configuration or an explicit signal grants that authority. Receiving an event should never grant more permission by accident.