Menu
popagent
publicLatest change 1ce5ab5f17eefb3cef070f9d98b28f2bb1e5c879 - Secure agent secrets behind origin-bound browser use by AkurAI Build
# Hooks
Popagent exposes managed, versioned HTTP lifecycle hooks. The implementation is
`src/hooks.ts`; Mastra adapters are in `src/hook-lifecycle.ts`; audit persistence
is in `src/hook-audit.ts`.
## Events
| Event | Timing | Allowed outcomes |
|---|---|---|
| `SessionStart` | Persistent session creation or first resume in a server process | `pass` |
| `TaskStart` | After a queued background task is claimed | `pass` |
| `UserPromptSubmit` | Before recall and model execution | `pass`, `deny`, `modify` |
| `SubagentStart` | Immediately before specialist delegation | `pass`, `deny`, `modify` |
| `PreToolUse` | Immediately before every Mastra tool | `pass`, `deny`, `modify` |
| `PostToolUse` | After successful tool execution | `pass` |
| `PostToolUseFailure` | After failed tool execution | `pass` |
| `SubagentStop` | After specialist delegation finishes | `pass` |
| `TaskStop` | After a background task completes, fails, cancels, or is interrupted | `pass` |
| `Stop` | After a complete model response, before accepting completion | `pass`, `continue` |
| `StopFailure` | Provider, stream, or framework failure | `pass` |
| `SessionEnd` | Immediately before permanent session deletion | `pass` |
`Stop` continuation maps to a Mastra processor retry and is capped by
`maxProcessorRetries: 3`. `SubagentStart` can deny delegation or replace its
prompt; `SubagentStop` receives the bounded specialist response. Failed
delegations also return bounded failure feedback to the supervisor so it can
recover or report the limitation. `TaskStart` and `TaskStop` share one generated
turn ID for correlation. `SessionEnd` fires for
permanent deletion, before the session transcript and matching Mastra thread
data are removed. Archiving is reversible display state and does not end the
session.
## Configuration
`POPAGENT_HOOKS` contains one strict JSON document:
```json
{
"version": 1,
"hooks": {
"PreToolUse": [
{
"id": "tool-policy",
"type": "http",
"url": "https://hooks.example.com/popagent",
"matcher": ["remember", "useBrowserSecret"],
"timeoutMs": 2000,
"failureMode": "closed"
}
]
}
}
```
Every configured hostname must appear exactly in the comma-separated
`POPAGENT_HOOK_ALLOWED_HOSTS`. HTTPS is mandatory. Hook requests do not inherit
server credentials or arbitrary headers.
Matchers use exact Mastra runtime registry keys, not the hyphenated `createTool`
IDs. Tool events match tool keys such as `getTime`, `remember`,
`useBrowserSecret`, and `webSearch`; delegation events match specialist IDs such
as `researcher`, `implementer`, and `reviewer`.
Each request receives `schemaVersion`, stable event/session/turn/tool-call IDs,
model, timestamp, and event-specific `detail`. Responses are strict JSON with
`schemaVersion: 1` and one event-supported outcome. Each `additionalContext`
field and the combined context from all handlers in one dispatch are capped at
16 KiB UTF-8; reasons are capped at 2 KiB UTF-8 and responses at 64 KiB.
Response streams are cancelled as soon as they exceed the cap. Handlers are
capped at 30 seconds; the default timeout is two seconds.
## Execution rules
- Gate and mutation handlers run sequentially in declaration order. Prompt or
tool-input mutation becomes the next handler's input.
- `UserPromptSubmit`, `SubagentStart`, `PreToolUse`, and `Stop` fail closed by
default and may be configured open. Observational events always fail open;
configuration rejects
`failureMode: "closed"` for them. Transport, timeout, malformed-response, and
event-outcome failures all use the same event/handler failure mode.
- Fail-closed `Stop` hooks can block turn completion after the processor's retries
are exhausted.
- `UserPromptSubmit` and `SubagentStart` replacements must be strings.
`PreToolUse` replacements must be argument objects and still pass the tool's
normal schema validation.
- A prompt replacement collapses every text fragment in the latest user message
into one replacement while preserving non-text attachments and tool parts.
- Background tasks emit correlated `TaskStart`, prompt, delegation, tool,
response, failure, and `TaskStop` events. They do not emit `SessionStart` or
`SessionEnd`, which track persistent chat creation/resume and deletion.
- `PostToolUse` is observational. Mastra's after-tool hook cannot replace tool
output, so post-tool mutation and added context are not accepted.
- Hook decisions are persisted in `popagent_hook_runs`; audit write failures are
logged but never change the handler outcome or its configured failure mode.
Raw event payloads and model transcripts are not copied into that table.
- Audit rows are cleaned both after writes and by the daily global maintenance
job: records older than 30 days are removed and each session is capped at 500.
Permanent session deletion removes that session's audit rows.
- `GET /api/sessions/:id/hooks` returns the latest 500 audit records in
chronological order. The UI groups records by stable turn ID in a collapsible
per-turn timeline.
- Hook calls never recursively emit hooks.
- `useBrowserSecret` hook payloads contain only a credential name and browser
element reference before use, then name/origin/success metadata after use.
Plaintext is resolved and consumed below the tool and hook boundaries.
- Retired `storeSecret`, `recallSecret`, and `updateSecret` payloads are redacted
to the literal `[redacted]` before PreToolUse or PostToolUse dispatch.
- Hooks are server-managed environment configuration. User and session content
cannot define executable hooks.
## Contract tests
`src/hooks.test.ts` owns ordering, matching, mutation, failure-mode, audit
isolation, aggregate byte-budget, and schema contracts using an isolated
transport. `src/hook-audit.test.ts` owns persistence bounds and deletion.
Affected server tests own route integration.