# SessionEnd Hook Synthesis vs finalize-session Command: Key Differences in ai-memory

> Discover the key differences between SessionEnd hook synthesis and finalize-session command in ai-memory. Understand their distinct trigger methods and agent compatibility for optimal use.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: deep-dive
- Published: 2026-08-25

---

**Both mechanisms produce identical SessionEnd outcomes—deterministic summary pages, handoff rows, and optional LLM consolidation—but differ fundamentally in trigger method and agent compatibility.**

The `akitaonrails/ai-memory` repository provides two distinct pathways to terminate sessions and generate persistence artifacts. Understanding when to rely on automatic **SessionEnd hook synthesis** versus when to invoke the **`finalize-session` command** ensures reliable session management across diverse AI agent integrations.

## What Is SessionEnd Hook Synthesis?

**SessionEnd hook synthesis** is an automatic server-side process triggered when compatible agents emit a genuine `SessionEnd` lifecycle hook. This mechanism operates without manual intervention, capturing the end-of-session event as part of the standard observability pipeline.

The implementation resides in [`crates/ai-memory-hooks/src/router.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-hooks/src/router.rs), where the hook router receives the payload, validates the session ownership, and initiates the synthesis logic. When the server detects a valid `SessionEnd` observation from agents like **Claude Code**, **Cursor**, or **Gemini CLI**, it immediately generates the session summary page and handoff row. If the `AI_MEMORY_CONSOLIDATE_ON_SESSION_END` environment variable is enabled, the system also queues an LLM-driven consolidation job automatically.

## What Is the finalize-session Command?

The **`finalize-session` command** is a manual CLI utility designed for agents that lack reliable automatic SessionEnd hooks. Located in [`crates/ai-memory-cli/src/commands/finalize_session.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/finalize_session.rs), this sub-command synthesizes a SessionEnd observation on behalf of the user by POSTing a synthetic event to the server.

This command is essential for integrations with **Codex**, **Antigravity CLI**, **Pool**, and **Kiro CLI**, which do not emit true session termination signals. After the final interaction turn, users explicitly run the command to trigger the same processing pipeline that automatic hooks utilize.

## Critical Differences in Trigger Mechanisms

The distinction between these approaches centers on initiation responsibility and session scope.

| Aspect | SessionEnd Hook Synthesis | finalize-session Command |
|--------|---------------------------|--------------------------|
| **Trigger Source** | Automatically initiated by the agent's lifecycle hook | Manually executed by the user or automation script |
| **Agent Compatibility** | Claude Code, Cursor, Gemini CLI, and other hook-capable clients | Codex, Antigravity CLI, Pool, Kiro CLI, and hook-less clients |
| **Ownership Validation** | Strictly uses the owner that generated the hook; auto-expires older automatic hand-offs for that specific owner | Supports `--all-owners` flag for root-only recovery across any user's open sessions |
| **Target Precision** | Processes the active session associated with the hook payload | Supports `--session-id <uuid>` to target specific open sessions when multiple exist |

## Scope and Privilege Variations

Automatic synthesis maintains strict session ownership boundaries. When the server receives a hook in [`crates/ai-memory-hooks/src/router.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-hooks/src/router.rs), it scopes the auto-hand-off to the same owner and current working directory (cwd), preventing cross-contamination between users.

Conversely, the CLI command provides elevated recovery options. The `--all-owners` flag requires root privileges and allows administrators to synthesize SessionEnd events for any abandoned open session in the system. This makes `finalize-session` a critical tool for system maintenance and garbage collection scenarios where automatic hooks never fired.

## Implementation Architecture

Both mechanisms converge on identical server-side processing despite different entry points.

The automatic path flows through the hook router, which handles the incoming observation and delegates to the synthesis engine. This occurs in real-time as the agent terminates its session.

The manual path constructs a synthetic `SessionEnd` observation struct within [`crates/ai-memory-cli/src/commands/finalize_session.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/finalize_session.rs), then POSTs it to the server's ingestion endpoint. Once received, the server processes this synthetic observation through the same synthesis path as legitimate hooks, ensuring behavioral parity.

## Practical Usage Examples

Execute these commands based on your agent's capabilities.

Automatic handling requires no action for compatible agents:

```bash

# No command needed—Claude Code automatically emits SessionEnd

# Server processes via crates/ai-memory-hooks/src/router.rs

```

Manual finalization for hook-less agents:

```bash

# Finalize the default active session for Codex

ai-memory finalize-session --agent codex

# Target a specific session by UUID when multiple sessions are open

ai-memory finalize-session --session-id 4f2e1d9b-7a6c-4b19-8c3a-9f5e2d1c8a57

# Root-only recovery: synthesize SessionEnd for any open session owned by any user

ai-memory finalize-session --all-owners

```

All examples trigger the same downstream effects: deterministic summary page generation, handoff row creation, and optional LLM consolidation if `AI_MEMORY_CONSOLIDATE_ON_SESSION_END` is enabled.

## Summary

- **SessionEnd hook synthesis** provides automatic, agent-initiated session termination for compatible clients like Claude Code and Cursor, implemented in [`crates/ai-memory-hooks/src/router.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-hooks/src/router.rs).
- **`finalize-session`** offers manual, user-initiated termination for agents lacking true hooks, implemented in [`crates/ai-memory-cli/src/commands/finalize_session.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/finalize_session.rs).
- Both mechanisms generate identical artifacts: session summary pages, handoff rows, and optional LLM consolidation jobs.
- The CLI command supports advanced recovery options including `--session-id` targeting and `--all-owners` root-level intervention that automatic synthesis cannot provide.
- Choose automatic synthesis for hook-capable agents; use the CLI command for Codex, Antigravity CLI, Pool, Kiro CLI, and recovery scenarios.

## Frequently Asked Questions

### When should I use finalize-session instead of relying on automatic hooks?

Use `ai-memory finalize-session` when working with agents that do not emit true SessionEnd lifecycle events, such as **Codex**, **Antigravity CLI**, **Pool**, or **Kiro CLI**. Run the command immediately after your final interaction turn to synthesize the session termination. If your agent is **Claude Code**, **Cursor**, or **Gemini CLI**, automatic synthesis in [`crates/ai-memory-hooks/src/router.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-hooks/src/router.rs) handles termination without manual intervention.

### Can finalize-session target sessions owned by other users?

Yes, but only with root privileges. The `--all-owners` flag allows administrators to synthesize SessionEnd events for any open session regardless of ownership, making it suitable for system recovery and garbage collection. Without this flag, the command respects standard ownership boundaries and only processes sessions belonging to the executing user.

### Does finalize-session produce exactly the same output as automatic SessionEnd hooks?

Yes. Both mechanisms create identical deterministic session summary pages, handoff rows, and trigger LLM consolidation jobs when `AI_MEMORY_CONSOLIDATE_ON_SESSION_END` is enabled. The CLI command in [`crates/ai-memory-cli/src/commands/finalize_session.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/finalize_session.rs) constructs a synthetic observation that the server processes through the same synthesis path as genuine hooks received by [`crates/ai-memory-hooks/src/router.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-hooks/src/router.rs).

### What happens if I run finalize-session on a session that already ended?

The server validates session state before processing. If the targeted session is already closed or the UUID does not exist among open sessions, the command will fail with an error indicating no matching open session was found. Use `--session-id` to specify exact targets when multiple sessions are active, or omit it to finalize the default active session for the specified agent.