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:

  1. Raw Request ParsingHookEnvelope::from_query_and_body constructs a typed envelope from query parameters (?event=…&agent=…) and the JSON payload, defined in crates/ai-memory-hooks/src/payload.rs.

  2. Assistant Message Stripping – The system removes any _ai_memory_assistant field through crates/ai-memory-hooks/src/assistant_capture.rs before storage processing begins.

  3. Capture Policy Enforcementinspect_capture_envelope evaluates the _ai_memory_capture marker against project-specific .ai-memory.toml policies. This step can drop events entirely or reduce them to metadata-only for privacy protection, particularly for sensitive file-tool arguments in crates/ai-memory-hooks/src/capture_policy.rs.

  4. Sub-agent Handling – For projects with drop_subagent enabled, the router uses a bounded LRU set (SubagentSessionSet) to accept-but-drop tail events from sub-agent sessions, preventing pollution of parent session logs.

  5. Global Ingest Semaphore – A tokio::Semaphore named DEFAULT_HOOK_INGEST_MAX_IN_FLIGHT caps concurrent ingest tasks. When saturated, the endpoint returns 429 Too Many Requests.

  6. Per-Source Rate Limiting – The IngestRateLimiter implements a token-bucket algorithm to limit events per logical source (user + session + project). Exceeding the limit triggers another 429 response.

  7. Ingest GatesIngestGates serialize overlapping retries for identical (project_id, ingest_key) pairs, eliminating race conditions between duplicate deliveries.

  8. Asynchronous Processing – After clearing semaphores and rate limits, the hook spawns async tasks calling process_envelope (or process_authorized for batch items). These functions write observations to the store, update session pages, and optionally invoke LLM-driven consolidation. Success triggers ingest_metrics.record_persisted.

  9. Metrics and Telemetry – The HookState maintains Arc<IngestMetrics> tracking accepted, dropped, rate-limited, and persisted counts, exposed through the ai-memory status CLI.

Lifecycle Hook Semantics

The system captures distinct event categories through these hooks:

Session Lifecycle Events

  • SessionStart, SessionEnd, SubagentStart, SubagentStop, and UserPromptSubmit mark session boundaries.
  • SessionEnd triggers synthesize_session_page to generate wiki summaries and optionally invokes the LLM consolidator when AI_MEMORY_CONSOLIDATE_ON_SESSION_END is enabled.

Tool Usage Tracking

  • PreToolUse and PostToolUse events 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 /handoff to 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, and GET /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 through synthesize_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →