# Explore and query recordings

Canonical: https://hypaware.ai/docs/querying

After [setup](https://hypaware.ai/docs/cli/index.md), use your AI agent to explore your recordings. You can
start a question with `hyp ask` or ask the client you already have open to use
HypAware. Search and SQL commands are also available below. To generate or share
a report, see [reports](https://hypaware.ai/docs/reports/index.md).

Queries use this host's recordings by default. To search recordings in
HypAware Cloud, including other hosts and your team, tell your agent to use
`--remote` on its query commands. This uses your default remote target;
`--remote <target>` selects another. See [remote access](https://hypaware.ai/docs/team-setup/index.md#manage-remote-access)
to configure a target and sign in.

## Explore recordings with your agent

Choose either option below.

### Ask your client directly

In an existing client session, ask it to use HypAware:

> Use HypAware to find the session where we fixed the authentication bug.

You can also ask it to search remote logs:

> Use HypAware to search my remote logs for the session where we fixed the authentication bug.

HypAware's skills are installed automatically during setup and attach for
supported clients. They let your agent search recorded sessions and query the
logs. If the skills are missing, see [client skills](https://hypaware.ai/docs/clients/index.md#install-client-skills).

### Use hyp ask

From your terminal, ask a question about your recordings:

```sh
hyp ask "Use HypAware to search my remote logs for sessions about connection refused this week."
```

`hyp ask` opens a recorded AI client (Claude Code or Codex) and asks it to look
up the answer in HypAware. If both are configured and available, you can choose
which one to use.

## See what is available

<!-- agent: Use HypAware to tell me what is recorded on this host: which datasets, how fresh, and a summary of models, tokens, and tools. Over MCP, read the datasets with query_sql. -->
```sh
hyp cache status
hyp query overview
hyp query schema ai_gateway_messages
```
```output
What HypAware has recorded
2026-09-01 to 2026-09-06 (5 active days, 1,565 rows)
────────────────────────────────────────
Input is prompt sent fresh; cached is prompt served from (or written to) the cache.
Output is what the model generated. Input + cached is the whole prompt.
Share bars split ▒ input from █ output; cache is excluded.

Which providers and models you use, by volume

  provider   model              input      cached   output  share
  anthropic  claude-opus-5-5   25,252  64,078,478  263,270  ▒▒████████████████
  openai     gpt-6.1-sol       61,926     612,992    1,284  ▒▒▒█
  anthropic  claude-haiku-5-5  20,423           0    1,273  █
```

Over MCP, read the same datasets with `query_sql`.

Cache status lists local datasets and freshness. The overview summarizes models,
tokens, repositories, and tools over the period printed in its heading. Its
default window adapts to the amount of data; use `--days 7` for a chosen window,
`--json` for structured output, or `--sql` to inspect its queries.

`ai_gateway_messages` contains message **parts**: one message can contribute
several text, tool-call, or tool-result rows. A row count is not a count of
sessions, messages, or API requests. Other datasets depend on enabled sources;
inspect their schema before writing SQL.

## Find a conversation

The bundled `@hypaware/grep` plugin searches recorded messages. Standard capture
setups enable it; an explicit `enabled: false` entry keeps it disabled. An
existing configuration gains it automatically on startup. When the migration
can save the change it backs the config up first, leaving a timestamped
`.bak-` copy beside `hypaware-config.json`; otherwise search still works for
that process, and a read-only config logs a warning that the change could not
be saved.

<!-- agent: Use HypAware to find sessions mentioning connection refused, newest first, and show me the daemon-related sessions from the first week of September 2026. Over MCP, use grep_search. -->
```sh
hyp query grep "connection refused" --limit 20
hyp query grep "daemon" --from 2026-09-01 --to 2026-09-07 --format json
```
```output
date        session_id                            column        message_id                            part_id                                 snippet
----------  ------------------------------------  ------------  ------------------------------------  --------------------------------------  --------------------------------------------------------------------------------
2026-09-07  5bb16021-a2a1-433d-91a0-6afc69732b6d  content_text  99651a15-be1f-428a-85ff-56a0183a7a4c  99651a15-be1f-428a-85ff-56a0183a7a4c#0  ...daemon log: connect ECONNREFUSED 127.0.0.1:4318 (connection refused)
2026-09-05  1e56b730-1ce4-46f8-b7fc-7961a4087ada  content_text  39cf0bc2-2d8b-4c25-a752-54c9cbbd497e  39cf0bc2-2d8b-4c25-a752-54c9cbbd497e#0  ...the gateway is down, so every request fails with connection refused until the
2026-09-05  1e56b730-1ce4-46f8-b7fc-7961a4087ada  content_text  559ea13b-be2e-464c-ae03-aabcd78838ae  559ea13b-be2e-464c-ae03-aabcd78838ae#0  ...curl: (7) Failed to connect to localhost port 4318: Connection refused\n
```

Over MCP, use `grep_search`.

Replace the dates with the period you need. Search is a case-insensitive
substring match unless you pass `--regex`. Each hit identifies a session,
message, and part, with newest hits first. One part can match several columns.

Search covers `content_text`, `tool_name`, `session_id`, `conversation_id`,
`agent_id`, `model`, `cwd`, `git_branch`, and `git_remote`. It does not search
system prompts or tool arguments. Inspect those with SQL when needed.

Take a `session_id` from a hit and read its conversation:

<!-- agent: Use HypAware to read the full conversation for session SESSION_ID in order. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select message_index, part_index, role, part_type, content_text, tool_name
  from ai_gateway_messages
  where session_id = 'SESSION_ID'
  order by message_index, part_index
  limit 100" --format json
```

A `session_id` filter alone can read every day of the cache, because the cache
is partitioned by `date`. If you know the days the session ran, add
`and date >= 'FIRST_DAY' and date <= 'LAST_DAY'` so only those days are read.
Cover every day: a session can cross midnight, and rows outside the range are
silently left out.

To inspect that session's tool calls:

<!-- agent: Use HypAware to list every tool call in session SESSION_ID with its arguments. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select message_index, tool_name, tool_args
  from ai_gateway_messages
  where session_id = 'SESSION_ID' and part_type = 'tool_call'
  order by message_index
  limit 50" --format json
```

Over MCP, every SQL query in this section runs with `query_sql`.

## Summarize a known period

Use explicit date bounds so the result has a clear scope. This counts sessions
and parts per client per day; a session spanning days can count on each day.

<!-- agent: Use HypAware to count sessions per client per day for the first week of September 2026. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select date, client_name,
    count(distinct session_id) as sessions, count(*) as parts
  from ai_gateway_messages
  where date >= '2026-09-01' and date < '2026-09-08'
  group by date, client_name
  order by date desc, client_name" --format markdown
```

Over MCP, every SQL query in this section runs with `query_sql`.

For token summaries, start with `hyp query overview --days 7 --sql` and its
existing usage extraction. Token usage is stored in structured attributes;
do not assume every message part has usage or represents another request.

> **Tip:** Keep scans economical: choose dates or a session before selecting large text
> fields. Use `LIMIT` for exploration and select only the columns you need.

## Find the turns a person typed

A `role = 'user'` text row is not always something a person typed. Skill
expansions, system reminders, tool output echoes, task notifications, messages
from other agents, interrupts, and compaction summaries are recorded as user
text too. Since HypAware 1.48.0, Claude Code and Codex rows record who
submitted the turn:

- Claude Code and Claude Desktop:
  `JSON_EXTRACT_STRING(attributes, '$.claude.origin.kind') = 'human'`.
  `attributes.claude.prompt_source` adds how the turn was submitted: `typed`,
  `queued`, `suggestion_accepted`, `sdk`, or `system`. A `'human'` turn can be
  any of the first three; add
  `JSON_EXTRACT_STRING(attributes, '$.claude.prompt_source') = 'typed'` to keep
  only turns typed at the prompt. A headless `claude -p` turn has
  `prompt_source = 'sdk'` and no `origin`.
- Codex: `JSON_EXTRACT_STRING(attributes, '$.codex.content_item_kinds')`
  contains `"user.text"`.

This counts typed turns per client per day:

<!-- agent: Use HypAware to count the turns a person typed per client per day for the week of 2026-11-02. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select date, client_name, count(*) as typed_turns
  from ai_gateway_messages
  where date >= '2026-11-02' and date < '2026-11-09'
    and role = 'user' and part_type = 'text'
    and (JSON_EXTRACT_STRING(attributes, '$.claude.origin.kind') = 'human'
      or JSON_EXTRACT_STRING(attributes, '$.codex.content_item_kinds') like '%\"user.text\"%')
  group by date, client_name
  order by date desc, client_name" --format markdown
```

Not every other row is unlabeled. Claude Code gives task notifications, peer
messages, and coordinator turns their own `origin.kind` (`task-notification`,
`peer`, `coordinator`), and leaves tool results, subagent prompts, skill
expansions, interrupts, and compaction summaries with no `origin` at all.
Codex labels injected blocks with other kinds, such as
`agents_md.instructions` and `environments.environment_context`. Filter on
`= 'human'` and `"user.text"`; a row with some label is not a typed turn.

The labels need HypAware 1.48.0 or later on the machine that recorded the row,
Claude Code 2.1.241 or later, and Codex 0.151.0 or later. Rows recorded before
that never get a label, and maintenance does not add one later, so a
label-only count is low for every earlier day and every machine that has not
upgraded. Check coverage first:

<!-- agent: Use HypAware to compare user text rows with labeled typed turns per client per day since 2026-10-01. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select date, client_name, count(*) as user_rows,
    sum(case when JSON_EXTRACT_STRING(attributes, '$.claude.origin.kind') = 'human'
      or JSON_EXTRACT_STRING(attributes, '$.codex.content_item_kinds') like '%\"user.text\"%'
      then 1 else 0 end) as typed_turns
  from ai_gateway_messages
  where date >= '2026-10-01' and role = 'user' and part_type = 'text'
  group by date, client_name
  order by date desc, client_name" --format markdown
```

A day with user rows but no typed turns most likely predates the label. On a
remote target, add `gateway_id` to the grouping to find the machines that have
not upgraded.

For those days, estimate Claude Code typed turns from the text. This keeps
main-thread rows and drops the common injected prefixes:

<!-- agent: Use HypAware to estimate typed Claude Code turns per day for October 2026 from the message text. Over MCP, run the same SQL with query_sql. -->
```sh
hyp query sql "select date, count(*) as estimated_typed_turns
  from ai_gateway_messages
  where date >= '2026-10-01' and date < '2026-11-01'
    and client_name = 'claude' and role = 'user' and part_type = 'text'
    and coalesce(is_sidechain, false) = false
    and (agent_id is null or agent_id = '')
    and (user_type is null or user_type in ('external', 'user'))
    and (entrypoint is null or entrypoint <> 'sdk-cli')
    and content_text not like '<%'
    and content_text not like '[%'
    and content_text not like 'Base directory for this skill%'
    and content_text not like 'Tool loaded.%'
    and content_text not like 'Skill /%'
    and content_text not like 'Re-invocation of %'
    and content_text not like 'Another Claude session sent%'
    and content_text not like 'The user sent a new message while%'
    and content_text not like 'This session is being continued%'
    and content_text not like 'From my HypAware history%'
    and content_text not like 'Message Type:%'
  group by date
  order by date desc" --format markdown
```

Report these counts as estimates. The filter still counts smoke prompts and
pasted documents, and it drops a typed message that starts with a bracket.
Codex has no reliable text rule before the label. Count its main-thread user
text rows (`client_name = 'codex' and role = 'user' and part_type = 'text' and
coalesce(is_sidechain, false) = false`) and say that they include injected
blocks.

Over MCP, every SQL query in this section runs with `query_sql`.

## Save complete results

Terminal output truncates long cells and limits the displayed byte count.
Notices on standard error explain omitted data. Write to a file when you need
complete results from your query:

<!-- agent: Use HypAware to export the full conversation for session SESSION_ID to session.jsonl, without truncation. Over MCP, run the same SQL with query_sql and save the rows it returns to session.jsonl. -->
```sh
hyp query sql "select message_index, part_index, role, content_text
  from ai_gateway_messages where session_id = 'SESSION_ID'
  order by message_index, part_index" --format jsonl --output ./session.jsonl
```

Over MCP, run the same SQL with `query_sql`; the agent saves the rows itself,
since `--output` is a local option.

`--output` avoids terminal display truncation; it does not remove a SQL `LIMIT`.
Available formats include `table`, `json`, `jsonl`, and `markdown`. Keep stderr
separate from JSON output so freshness and privacy notices remain visible.

> **Caution:** Local-only rows can be withheld depending on the querying session's privacy
> class. `--include-local-only` explicitly includes them in local results, so use
> it only where the output can remain private. See [privacy controls](https://hypaware.ai/docs/privacy/index.md).

## Query a remote target

<!-- agent: Use HypAware to search our team's remote recordings for connection refused this week and count sessions per day. Over MCP, use grep_search and query_sql on our team's server. -->
```sh
hyp remote list
hyp query grep "connection refused" --remote team --limit 20
hyp query sql "select date, count(distinct session_id) as sessions
  from ai_gateway_messages
  where date >= '2026-09-01' and date < '2026-09-08'
  group by date order by date" --remote team --format json
```

Over MCP, use `grep_search` and `query_sql` on your team's server, either on
`/v1/mcp` or through `hyp mcp serve --remote`.

Replace `team` with a configured target. A bare `--remote` uses the default.
For target configuration and query-only sign-in, see
[remote access](https://hypaware.ai/docs/team-setup/index.md#manage-remote-access).

`hyp cache status` and `hyp query overview` describe local state. They are
not a remote inventory. A remote can have different datasets, retention, and
permissions; query it directly to establish what is available. To see a remote
dataset's columns, add `--remote` to `hyp query schema`, which resolves the
target the same way `hyp query sql` does. The remote enforces visibility and
rejects `--include-local-only`.

## Follow relationships in the activity graph

When `@hypaware/context-graph` is active, project local recordings before
walking relationships:

<!-- agent: Use HypAware's activity graph to show which sessions touched src/app.js, two hops in. Over MCP, use graph_neighbors. -->
```sh
hyp graph project
hyp query graph neighbors src/app.js --type File --direction in --depth 2 --limit 25
```

Over MCP, use `graph_neighbors`.

Replace the example file with one from your recorded work. A seed can be a node
ID, natural key, or label. An ambiguous seed needs a type or exact ID. A file can
have both a repository-relative identity and an absolute-path identity.

<!-- @ref LLP 0564#skill-evidence [explains]: a ran edge is skill evidence, not proof the skill executed -->
Use the graph for questions such as which sessions touched a file or show skill
evidence for a skill. Skill evidence says how the session reached the skill
(an invocation requested, its instructions supplied, or its file read or
searched), not that the skill ran or succeeded. A `Session` node's natural key is the `session_id` to use in the SQL
examples above. The `node` and `edge` datasets are also queryable with SQL.
Remote graph traversal uses `--remote`; projecting the local graph does not
refresh the remote's graph.

<!-- @ref LLP 0491#guidance: agents discover specific remote files before reading indexed session evidence -->
## Explore the team's history

The shipped Claude and Codex query skills teach agents to search the team
server's graph for specific filenames, follow those files to promising sessions,
search a small batch of sessions, and verify the original conversation. If the
first batch misses, the agent refines the file leads before expanding its search.
The server's session index accelerates eligible session-scoped reads.

This uses existing remote tools:

<!-- agent: Use HypAware's team graph to find the file nodes for FEATURE, the sessions that touched them, and what those sessions said about TERM. Over MCP, use query_sql, graph_neighbors and grep_search on our team's server. -->
```sh
hyp query sql "SELECT node_id, natural_key, label FROM node WHERE node_type = 'File' AND LOWER(natural_key) LIKE '%<feature>%' ORDER BY natural_key LIMIT 40" --remote team --format json
hyp query graph neighbors <file-node-id> --type File --direction in --edge-type touched --depth 1 --limit 50 --remote team --json
hyp query grep "<term>" --session-id <session-id> --remote team --format json
```

Over MCP, the three steps are `query_sql`, `graph_neighbors` and `grep_search`
on your team's server.

Replace placeholders with terms and IDs from the question and results. A
Session node's `natural_key` is the message dataset's `session_id`. Read the
surrounding messages with session-scoped remote SQL, or use the remote
`session_evidence` MCP tool when advertised. File names and graph links are
leads, not proof of what was decided. Check incomplete results and later
relevant sessions before concluding whether a decision still stands.

Team retrieval needs no replicated graph or additional client plugin. The
server maintains the graph. This host's own capture graph remains available
for local activity questions. If remote graph data is unavailable, use remote
message searches and disclose that coverage limit.

## Connect an MCP client

See [Connect an MCP client](https://hypaware.ai/docs/mcp/index.md) for local and remote setup, with a
config block for each client.

## Vector search and graph enrichment

With `@hypaware/vector-search` enabled, use `hyp vector status` to inspect
indexes and `hyp query vector search` for similarity search. See the
[vector search reference](https://hypaware.ai/docs/cli-reference/index.md#hyp-query-vector-search) for query
syntax and index selection.

The optional graph-enrichment plugin adds further relationships to the activity
graph. Use `hyp enrichment status` to inspect its state, then consult the
[enrichment reference](https://hypaware.ai/docs/cli-reference/index.md#enrich-the-activity-graph) for proposal,
curation, and backfill operations.
