Understanding Lifecycle Hooks in ai-memory: How Agent Events Are Captured
Lifecycle hooks in ai-memory are HTTP endpoints that capture every observable AI agent event through a validated pipeline of capture-policy enforcement, rate-limiting, and asynchronous storage into SQLite and wiki pages.
The ai-memory project, developed by akitaonrails, implements a disciplined event-ingestion system through specialized lifecycle hooks. These hooks serve as the exclusive entry point for recording agent activities, transforming raw tool usage and session data into searchable, immutable observations. Understanding how these lifecycle hooks in ai-memory capture agent events reveals the architecture behind reliable AI session tracking and privacy-aware data retention.
Core Lifecycle Hook Endpoints
Three HTTP endpoints in crates/ai-memory-hooks/src/router.rs expose the hook interface:
POST /hook – Captures single events like tool use or session transitions. Returns 202 Accepted immediately while processing occurs asynchronously.
POST /hook/batch – Ingests multiple spooled events in one request. Each item in the batch undergoes the same validation and rate-limiting checks as individual requests.
GET /handoff – Retrieves pending session handoffs for newly started agents. Returns markdown content if a handoff exists, or an empty response, atomically marking the handoff as accepted to ensure one-to-one transfer semantics.
The Event-Capture Pipeline
When an agent emits an event, the system executes a rigorous nine-stage pipeline before persistence:
-
Raw Request Parsing –
HookEnvelope::from_query_and_bodyconstructs a typed envelope from query parameters (?event=…&agent=…) and the JSON payload, defined incrates/ai-memory-hooks/src/payload.rs. -
Assistant Message Stripping – The system removes any
_ai_memory_assistantfield throughcrates/ai-memory-hooks/src/assistant_capture.rsbefore storage processing begins. -
Capture Policy Enforcement –
inspect_capture_envelopeevaluates the_ai_memory_capturemarker against project-specific.ai-memory.tomlpolicies. This step can drop events entirely or reduce them to metadata-only for privacy protection, particularly for sensitive file-tool arguments incrates/ai-memory-hooks/src/capture_policy.rs. -
Sub-agent Handling – For projects with
drop_subagentenabled, the router uses a bounded LRU set (SubagentSessionSet) to accept-but-drop tail events from sub-agent sessions, preventing pollution of parent session logs. -
Global Ingest Semaphore – A
tokio::SemaphorenamedDEFAULT_HOOK_INGEST_MAX_IN_FLIGHTcaps concurrent ingest tasks. When saturated, the endpoint returns 429 Too Many Requests. -
Per-Source Rate Limiting – The
IngestRateLimiterimplements a token-bucket algorithm to limit events per logical source (user + session + project). Exceeding the limit triggers another 429 response. -
Ingest Gates –
IngestGatesserialize overlapping retries for identical(project_id, ingest_key)pairs, eliminating race conditions between duplicate deliveries. -
Asynchronous Processing – After clearing semaphores and rate limits, the hook spawns async tasks calling
process_envelope(orprocess_authorizedfor batch items). These functions write observations to the store, update session pages, and optionally invoke LLM-driven consolidation. Success triggersingest_metrics.record_persisted. -
Metrics and Telemetry – The
HookStatemaintainsArc<IngestMetrics>tracking accepted, dropped, rate-limited, and persisted counts, exposed through theai-memory statusCLI.
Lifecycle Hook Semantics
The system captures distinct event categories through these hooks:
Session Lifecycle Events
SessionStart,SessionEnd,SubagentStart,SubagentStop, andUserPromptSubmitmark session boundaries.SessionEndtriggerssynthesize_session_pageto generate wiki summaries and optionally invokes the LLM consolidator whenAI_MEMORY_CONSOLIDATE_ON_SESSION_ENDis enabled.
Tool Usage Tracking
PreToolUseandPostToolUseevents capture tool invocations. The capture policy may reduce file-tool arguments to metadata-only, protecting sensitive path information while preserving operational context.
Handoff Mechanism
- New agents call
GET /handoffto retrieve context from previous sessions. The atomic acceptance ensures exactly-once handoff semantics, preventing duplicate context injection.
Practical Code Examples
Capture a single tool-use event:
curl -X POST "http://127.0.0.1:49374/hook?event=PreToolUse&agent=Claude" \
-H "Content-Type: application/json" \
-d '{
"session_id":"s-123",
"cwd":"/home/user/project",
"tool_family":"file",
"tool_name":"open",
"path":"/home/user/project/main.rs",
"_ai_memory_capture":"{...}"
}'
The server replies 202 Accepted. Processing occurs asynchronously.
Batch ingestion for spooled events:
curl -X POST "http://127.0.0.1:49374/hook/batch" \
-H "Content-Type: application/json" \
-d '[
{"url":"http://127.0.0.1:49374/hook?event=PreToolUse&agent=Claude","body":{"session_id":"s-123","tool_family":"file","path":"/a.txt"}},
{"url":"http://127.0.0.1:49374/hook?event=PostToolUse&agent=Claude","body":{"session_id":"s-123","tool_family":"file","path":"/a.txt","outcome":"success"}}
]'
Returns a HookBatchAck JSON object indicating committed items.
Retrieve a session handoff:
curl "http://127.0.0.1:49374/handoff?agent=Claude&session_id=s-123"
Returns markdown content if available, empty otherwise.
Summary
- Lifecycle hooks in ai-memory provide the exclusive HTTP interface for agent event ingestion through
POST /hook,POST /hook/batch, andGET /handoff. - The capture pipeline enforces validation, privacy policies via
.ai-memory.toml, and multi-layered rate limiting before asynchronous storage. - Global and per-source limits prevent resource exhaustion using semaphores and token-bucket algorithms, returning 429 when exceeded.
- Session semantics include atomic handoffs, sub-agent isolation via
SubagentSessionSet, and automatic wiki page generation throughsynthesize_session_page. - All events ultimately persist to SQLite through the single-writer architecture in
crates/ai-memory-store/src/writer.rs.
Frequently Asked Questions
What happens when the lifecycle hook rate limit is exceeded?
When the IngestRateLimiter token bucket depletes or the global tokio::Semaphore saturates, the endpoint immediately returns 429 Too Many Requests. The agent should implement exponential backoff and retry logic, as the hook does not queue requests beyond the concurrent task limit defined in DEFAULT_HOOK_INGEST_MAX_IN_FLIGHT.
How does ai-memory protect sensitive data in tool arguments?
The inspect_capture_envelope function in crates/ai-memory-hooks/src/capture_policy.rs checks the _ai_memory_capture marker against project-specific policies. File-tool arguments can be configured to Drop entirely or persist as MetadataOnly, stripping actual content while preserving operation records. This protects sensitive paths and data while maintaining observability.
Can lifecycle hooks handle high-throughput agent sessions?
Yes, through the batch endpoint POST /hook/batch and the SubagentSessionSet LRU cache. The batch endpoint allows agents to spool events during offline operation, while the bounded LRU set prevents sub-agent spam from overwhelming parent session logs. The IngestGates mechanism also deduplicates retries to reduce load on the SQLite writer.
Where are captured events ultimately stored?
After processing through process_envelope, events persist to SQLite via crates/ai-memory-store/src/writer.rs, which maintains a single-writer invariant ensuring atomic indexing within transactions. Additionally, session summaries generate markdown wiki pages for human-readable context retrieval and handoff operations through synthesize_session_page.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →