Summary
Add beforeTurn, afterTurn, and onTurnError lifecycle hooks to the agent session execution loop, allowing user scripts to guard, audit, or react to individual agent turns.
Problem
Agent turns (interactive message responses, local agent runs) execute with no external interception point. There is no config-driven way to: rate-limit turns per session, log turn duration and token usage to an external system, abort a turn based on content or context, or alert on repeated turn errors.
Acceptance criteria
Implementation plan
- Locate the agent turn entry point in
src/agents/pi-embedded-runner.ts
- Add hook call sites before and after
runEmbeddedPiAgent (or equivalent turn executor)
- Re-use
runCronHooks / loadHookEntries from src/cron/hooks.ts with workflow: 'agent'
- Add
AgentHooksConfig type to src/config/types.hooks.ts or extend shared hook types
- Wire config loading through agent deps
- Add unit tests
Files affected
src/cron/hooks.ts (reuse — no changes expected)
src/config/types.hooks.ts (add AgentHooksConfig)
src/config/zod-schema.ts (Zod schema)
src/agents/pi-embedded-runner.ts (wire hook call sites)
src/agents/pi-embedded-runner.hooks.test.ts (new — tests)
Additional notes
- Natural extension of cron lifecycle hooks — same hook runner, same script contract, new
ctx.workflow = 'agent'
ctx should include: sessionKey, agentId, model, turnIndex, meta bag
- Token usage available post-turn from existing usage tracking (
src/agents/usage.ts)
Summary
Add
beforeTurn,afterTurn, andonTurnErrorlifecycle hooks to the agent session execution loop, allowing user scripts to guard, audit, or react to individual agent turns.Problem
Agent turns (interactive message responses, local agent runs) execute with no external interception point. There is no config-driven way to: rate-limit turns per session, log turn duration and token usage to an external system, abort a turn based on content or context, or alert on repeated turn errors.
Acceptance criteria
beforeTurnhook fires before agent execution begins; returning{ abort: true }skips the turnafterTurnhook fires after successful turn completion with duration, token usage, and session contextonTurnErrorhook fires when a turn fails with the error string and session contextopenclaw.jsonunder a sharedhookssection withfilter.agentIdsupportImplementation plan
src/agents/pi-embedded-runner.tsrunEmbeddedPiAgent(or equivalent turn executor)runCronHooks/loadHookEntriesfromsrc/cron/hooks.tswithworkflow: 'agent'AgentHooksConfigtype tosrc/config/types.hooks.tsor extend shared hook typesFiles affected
src/cron/hooks.ts(reuse — no changes expected)src/config/types.hooks.ts(add AgentHooksConfig)src/config/zod-schema.ts(Zod schema)src/agents/pi-embedded-runner.ts(wire hook call sites)src/agents/pi-embedded-runner.hooks.test.ts(new — tests)Additional notes
ctx.workflow = 'agent'ctxshould include:sessionKey,agentId,model,turnIndex,metabagsrc/agents/usage.ts)