> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Sessions

> Ranked full-text search across past session transcripts from the terminal

Search every stored session transcript from the terminal — ranked by relevance, with a snippet centred on each match.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Ranked Session Search"
        Q[💬 Query] --> S[🗃️ SqliteSessionStore]
        S --> R{🎯 FTS5 + bm25}
        R --> D[🧹 Cross-store dedup]
        D --> O[📊 Ranked results + snippets]
    end
    classDef query fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef store fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef rank fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    class Q query
    class S store
    class R,D rank
    class O result
```

## Quick Start

An agent recalls past sessions through the `session_search` tool — the CLI reaches the **same engine** from your terminal.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="recall-agent",
    instructions="Search past sessions when the user asks about earlier decisions.",
    tools=["session_search"],
)
agent.start("What did we decide about the billing migration?")
```

**1. Search your sessions**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai session search "billing migration"
```

Prints a table of matching sessions ranked by score, each with a snippet centred on the match:

```
              Search: billing migration
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ ID                   ┃ Title           ┃ Score ┃ Snippet                                        ┃ When              ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩
│ zeta                 │ Zeta            │ 5.0   │ we need a billing migration migration migr…   │ 2026-06-10T14:32… │
│ alpha                │ Alpha           │ 2.0   │ one mention of migration here                  │ 2026-06-09T11:04… │
└──────────────────────┴─────────────────┴───────┴────────────────────────────────────────────────┴───────────────────┘
```

An empty result prints:

```
No sessions matched: billing migration
```

**2. Widen the search**

Return more sessions and more context around each hit:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai session search "billing migration" --limit 10 --window 8
```

**3. Get machine-readable output**

Add the global `--json` flag for a structured result:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai --json session search "billing migration"
```

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "query": "billing migration",
  "results": [
    {
      "session_id": "zeta",
      "title": "Zeta",
      "when": "2026-06-10T14:32:00Z",
      "snippet": "we need a billing migration migration migr…",
      "score": 5.0,
      "anchor_index": 12,
      "messages": [
        {"index": 11, "role": "user", "content": "...", "timestamp": "...", "archived": true},
        {"index": 12, "role": "assistant", "content": "...", "timestamp": "...", "archived": false}
      ]
    }
  ]
}
```

Each result is `SessionHit.as_dict()` — the same shape as the [Cross-Session Recall Discovery return](https://praison.ai/docs/features/cross-session-recall.md#return-shapes).

Each message carries an `archived` boolean — `true` marks a turn recalled from `archived_messages` (compacted out of the active window by the default `retention="compact"` policy). See [Recall Across Compacted History](https://praison.ai/docs/features/cross-session-recall.md#recall-across-compacted-history).

***

## How It Works

`session search` delegates to `SqliteSessionStore` — the same FTS5/bm25 engine as the `session_search` agent tool — instead of a substring scan.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant CLI as praisonai CLI
    participant Stores as canonical_cli_stores()
    participant Sqlite as SqliteSessionStore
    User->>CLI: session search "billing migration"
    CLI->>Stores: enumerate project + global stores
    loop Each store
        CLI->>Sqlite: SqliteSessionStore(session_dir=…)
        Sqlite-->>CLI: hits with FTS5/bm25 score + snippet
    end
    CLI->>CLI: collapse duplicates by session_id (keep higher score)
    CLI->>CLI: sort by (score, when) desc, truncate to --limit
    CLI-->>User: table (or JSON) of ranked hits
```

The command iterates the CLI's canonical stores via `canonical_cli_stores()` — the same helper `session resume` / `show` / `delete` / `export` use — so id resolution stays consistent across every sub-command. See [Session Resume](https://praison.ai/docs/cli/session-resume.md).

| Step | What happens |
| - | - |
| Enumerate stores | Walks the project-scoped store then the global default store via `canonical_cli_stores()` |
| Index per store | Opens a `SqliteSessionStore(session_dir=…)` and runs `search(query, limit, window)` |
| Rank | FTS5/bm25 scoring with snippets and lineage dedup, applied inside each store |
| Cross-store dedup | Collapses duplicate `session_id`s across stores, keeping the higher-scoring copy |
| Sort & truncate | Sorts by `(score desc, when desc)` and keeps the top `--limit` hits |

### Cross-store dedup

A session resumed from the global default store keeps a project-side shadow, so the **same id** can match in both canonical stores. Without dedup those duplicate rows each consume a slot of `--limit` and crowd out distinct sessions. The command collapses by `session_id`, keeping the higher-scoring copy — mirroring the lineage dedup the store already applies inside a single directory.

> [!NOTE]
>
> Search never breaks: if a store can't be indexed, that store is skipped and the remaining hits are still returned. One bad transcript on disk (unreadable, malformed JSON, or invalid UTF-8) is also skipped — so you don't need to clean up `~/.praisonai/sessions/` before running the command. See [Cross-Session Recall → Resilience to Corrupt Transcripts](https://praison.ai/docs/features/cross-session-recall.md#resilience-to-corrupt-transcripts).

### Compacted history stays searchable

The CLI walks the same archived + active projection as the `session_search` agent tool. A detail rolled into `archived_messages` under `retention="compact"` is still recallable via `praisonai session search` — hits on archived turns come back with `archived: true` in each message entry (JSON mode) so the compaction boundary stays visible.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# The detail was rolled into archived_messages weeks ago — still findable from the terminal:
praisonai session search "deploy token XZ99" --limit 5
```

See [Cross-Session Recall → Recall Across Compacted History](https://praison.ai/docs/features/cross-session-recall.md#recall-across-compacted-history).

***

## Flags

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai session search <query> [--limit/-n N] [--window/-w N]
```

| Argument / Flag | Type | Default | Description |
| - | - | - | - |
| `query` | `str` (positional, required) | — | Free-text query to search across session transcripts |
| `--limit`, `-n` | `int` | `5` | Maximum number of matching sessions to return |
| `--window`, `-w` | `int` | `5` | Number of messages to include around each hit |
| `--json` (global) | flag | off | Print `{"query": ..., "results": [...]}` instead of a table |

**Text mode** prints a table with columns `ID | Title | Score | Snippet | When`. **JSON mode** prints `{"query": "...", "results": [...]}` where each result is `SessionHit.as_dict()`.

***

## Common Patterns

### From an agent tool to the terminal

The `session_search` agent tool and `praisonai session search` share the same store — pick whichever fits your workflow.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Same engine (SqliteSessionStore / FTS5+bm25) — from the terminal:
praisonai session search "billing migration" --limit 5 --window 5
```

### Pipe JSON into a script

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai --json session search "auth refactor" \
  | jq -r '.results[] | "\(.score)\t\(.session_id)\t\(.snippet)"'
```

### Resume the top hit

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
SID=$(praisonai --json session search "billing migration" | jq -r '.results[0].session_id')
praisonai session resume "$SID"
```

***

## Best Practices

> [accordion] Keep --window small for a quick scan
>
> Start with the default `--window 5`. Widen only when you need more surrounding context after finding the right session — then `session resume` it.

> [accordion] Treat scores as relative rankings
>
> Scores are FTS5/bm25 ranks, not probabilities. A `5.0` beats a `2.0`, but says nothing absolute — read the snippets to confirm the match. Compaction count no longer skews a session's rank — the synthetic `retention="compact"` summary is kept for context in each hit but excluded from scoring (PraisonAI PR [#6112](https://github.com/MervinPraison/PraisonAI/pull/6112)).

> [accordion] Raise --limit when duplicates are expected
>
> Cross-store dedup collapses same-id shadows, but distinct sessions on the same topic still compete for slots. Raise `--limit` when a topic spans many sessions.

> [accordion] Use --json to automate
>
> The `--json` output is `SessionHit.as_dict()` per result — pipe it into `jq` to feed ids straight into `session resume`, `show`, or `export`.

***

## Related

> [card] [Session (CLI)](https://praison.ai/docs/cli/session.md)
>
> List, resume, show, delete, export, and share sessions

> [card] [Session Resume](https://praison.ai/docs/cli/session-resume.md)
>
> Continue a session with full state restored

> [card] [Cross-Session Recall](https://praison.ai/docs/features/cross-session-recall.md)
>
> The same engine as an agent tool (`session_search`)

> [card] [Session Store](https://praison.ai/docs/features/session-store.md)
>
> SqliteSessionStore — FTS5 + bm25 recall index


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.