# Complete Guide to ObservationKind Events in ai-memory: 7 Types Explained

> Explore the 7 ObservationKind events in ai-memory: UserPrompt, PreToolUse, PostToolUse, Stop, SessionStart, SessionEnd, and Other. Understand every agent interaction with this comprehensive guide.

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

---

**The ai-memory library provides seven `ObservationKind` enum variants—`UserPrompt`, `PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `SessionEnd`, and `Other`—to classify every captured agent interaction.**

The `ObservationKind` enum forms the taxonomic foundation of the ai-memory event system. Defined in [`crates/ai-memory-core/src/observation.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/observation.rs) and re-exported from `ai_memory_core::ObservationKind` [as seen in the core library](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/lib.rs#L61), this enum assigns semantic meaning to every observation stored in the memory system. Understanding these variants is essential for filtering queries, debugging agent behavior, and building analytics on session data.

## The Seven ObservationKind Variants

The `ObservationKind` enum currently defines seven distinct event types. Each variant captures a specific moment in an agent session's lifecycle.

### UserPrompt

**`UserPrompt`** marks direct input from a human user to the agent—questions, commands, or any natural-language request.

This variant appears throughout the web API and test suites. In the routes test suite, prompts are explicitly recorded as `ObservationKind::UserPrompt` [in the test assertions](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-web/tests/routes.rs#L1152). This tagging enables downstream filtering for all user-generated content versus system-generated events.

```rust
use ai_memory_core::{NewObservation, ObservationKind};

let obs = NewObservation {
    kind: ObservationKind::UserPrompt,
    body: "Explain the Rust borrowing rules".into(),
    ..Default::default()
};
store.add_observation(obs)?;

```

### PreToolUse and PostToolUse

**`PreToolUse`** and **`PostToolUse`** form a bracketing pair around any external tool invocation.

- **`PreToolUse`** fires immediately before a tool executes—capturing intent, parameters, and context
- **`PostToolUse`** fires after the tool returns—capturing results, errors, or outputs

The store operations layer logs `PreToolUse` [at the start of tool calls](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs#L6233), while integration tests validate `PostToolUse` [in session observation scenarios](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/tests/session_observations.rs#L374). This pairing enables precise latency measurement and failure attribution.

```rust
// Before the tool executes
let pre = NewObservation {
    kind: ObservationKind::PreToolUse,
    body: "Calling external API".into(),
    ..Default::default()
};
store.add_observation(pre)?;

// After the tool completes
let post = NewObservation {
    kind: ObservationKind::PostToolUse,
    body: "API returned JSON".into(),
    ..Default::default()
};
store.add_observation(post)?;

```

### Stop

**`Stop`** represents an explicit, premature termination of a running session or observation chain.

Unlike `SessionEnd` which signals normal completion, `Stop` indicates halting—whether from user cancellation, safety triggers, or resource limits. Low-level tests demonstrate this [in writer throughput scenarios](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/tests/writer_throughput.rs#L61).

### SessionStart and SessionEnd

**`SessionStart`** and **`SessionEnd`** bound the entire lifecycle of a conversation or task sequence.

- **`SessionStart`** is always the first observation in any session, emitted [by lifecycle hooks during session initialization](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/migrations.rs#L56)
- **`SessionEnd`** is always the final observation, [detected in writer finalization logic](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs#L5490)

These bookends enable session-level aggregation and ensure data integrity for long-running conversations.

### Other

**`Other`** serves as a forward-compatible fallback for unrecognized or future event types.

When parsing a kind from external input, the system gracefully degrades to `Other` [as implemented in the evals parser](https://github.com/akitaonrails/ai-memory/blob/main/evals/src/main.rs#L414):

```rust
let kind = raw_kind
    .parse::<ObservationKind>()
    .unwrap_or(ObservationKind::Other);

```

## Querying Observations by Kind

The store API accepts `ObservationKind` filters for targeted retrieval. Pass a vector of desired kinds to `list_observations`:

```rust
let user_prompts = store
    .list_observations(session_id, Some(vec![ObservationKind::UserPrompt]))?;

```

For broader analysis, combine multiple kinds:

```rust
let tool_events = store.list_observations(
    session_id,
    Some(vec![ObservationKind::PreToolUse, ObservationKind::PostToolUse])
)?;

```

## Key Source Files for ObservationKind

| File | Role |
|------|------|
| [`crates/ai-memory-core/src/observation.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/observation.rs) | Definitive enum definition and variant documentation |
| [`crates/ai-memory-core/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/lib.rs) | Public re-export at line 61 |
| [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) | Persistence logic for all seven variants |
| [`crates/ai-memory-web/tests/routes.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-web/tests/routes.rs) | Integration tests demonstrating practical usage |
| [`evals/src/main.rs`](https://github.com/akitaonrails/ai-memory/blob/main/evals/src/main.rs) | String parsing with graceful fallback to `Other` |

## Summary

- **`ObservationKind`** in ai-memory provides seven semantic event classifications: `UserPrompt`, `PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `SessionEnd`, and `Other`
- The enum lives in [`crates/ai-memory-core/src/observation.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/observation.rs) and re-exports from `ai_memory_core::ObservationKind`
- `PreToolUse`/`PostToolUse` bracket external tool calls; `SessionStart`/`SessionEnd` bracket entire sessions
- `Stop` handles explicit halting; `Other` ensures forward compatibility
- Filter queries by passing `Vec<ObservationKind>` to `list_observations`

## Frequently Asked Questions

### What happens if I receive an unknown ObservationKind string at runtime?

The `parse` implementation returns `ObservationKind::Other` as a safe fallback. This pattern appears in [evals/src/main.rs at line 414](https://github.com/akitaonrails/ai-memory/blob/main/evals/src/main.rs#L414), ensuring the system remains stable when encountering future variants or malformed input.

### Can I filter observations by multiple kinds in a single query?

Yes. The `list_observations` method accepts `Option<Vec<ObservationKind>>`, allowing you to pass several variants simultaneously. For example, passing both `PreToolUse` and `PostToolUse` retrieves the complete timeline of tool interactions.

### Does every session require both SessionStart and SessionEnd?

While not strictly enforced at the type level, the store logic expects these bookends for proper session finalization. The writer explicitly detects `SessionEnd` [in ops.rs at line 5490](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs#L5490) to trigger cleanup operations. Sessions missing `SessionEnd` may appear as "open" in monitoring dashboards.

### What distinguishes Stop from SessionEnd?

`Stop` indicates **premature termination**—a halt mid-execution—while `SessionEnd` signals **normal, successful completion**. This distinction matters for analytics: `Stop` events often correlate with user dissatisfaction or safety interventions, whereas `SessionEnd` indicates successful task completion.