Resolve
aichat resolve turns a session name, a full
ID, a partial ID (prefix, middle, or suffix
fragment), or a session-file name fragment (e.g.
a codex rollout timestamp) into one canonical session
record — for both Claude Code and Codex. It is built
so an agent can resolve a session non-interactively,
but it prints a readable panel for humans too.
This is distinct from the interactive
Search TUI and the legacy find
commands: it does not browse, it resolves a single
identifier to a single answer.
aichat resolve <query> [--agent claude|codex] \ [--home PATH] [--json | --pretty]| Option | Description |
|---|---|
<query> | Session name (/rename), full or partial id, or a filename fragment. |
--agent | claude (default) or codex. |
--home | Overrides $CLAUDE_CONFIG_DIR / $CODEX_HOME and the default homes. |
--json | Force JSON output. |
--pretty | Force the human-readable panel. |
Output auto-detects its destination: JSON when
piped or captured (agent-facing), a Rich panel on a
terminal. Pass --json / --pretty to override.
What a “name” is
Section titled “What a “name” is”The name is the title you set with /rename inside a
session:
- Claude: the
custom-titlerecorded in the transcript — not the auto-generatedai-title. - Codex: the
thread_namerecorded in the home-levelsession_index.jsonl. When a thread has no explicit name, thetitlecolumn of the Codexthreadsdatabase is used instead — that one is auto-captured from your first message, not chosen by you.
Match precedence
Section titled “Match precedence”The query is resolved through ordered tiers; the first non-empty tier wins:
| Tier | Match | matched_by |
|---|---|---|
| 1 | exact full ID | id |
| 2 | exact name | name |
| 3 | ID prefix | partial-id |
| 4 | ID substring (middle or suffix) | id-substring |
| 5 | session-file name substring | filename |
| 6 | name substring | name |
So an exact ID or name is never shadowed by an incidental substring match, and an ID prefix match always beats a mid-ID substring match. The filename tier ranks above name substrings because filename fragments are structural: a timestamp fragment identifies one rollout file, while session names are free text that may incidentally quote the same fragment (dozens of sessions can mention a timestamp in their first message) and would otherwise drown the precise match.
ID tiers (3–4) require at least 4 characters from
the hex/dash id charset; the filename tier (5)
requires at least 4 characters. The filename tier is
what makes codex rollout fragments like
2026-03-25T14-50 (the timestamp in the rollout
file name) or a rollout-2026-03-25... prefix
resolvable. Queries are always matched as literal
substrings — never as glob patterns — and a query
containing a path separator (/, \) or a glob
metacharacter (*, ?, [, ]) matches nothing
in any tier.
Result
Section titled “Result”On a unique match, resolve prints one JSON object
and exits 0:
{ "agent": "claude", "session_id": "a15f9ced-88e9-43d7-9e2c-4a10d01f1644", "name": "session-finder", "directory": "/Users/you/Git/claude-code-tools", "home": "/Users/you/.claude", "session_file": ".../a15f9ced-....jsonl", "matched_by": "name", "modified": "2026-07-14T11:00:08-04:00", "archived": false}| Field | Description |
|---|---|
agent | claude or codex |
session_id | The resolved session UUID |
name | /rename title, or null |
directory | Session working directory |
home | Resolved home that was searched |
session_file | Absolute path to the session file |
matched_by | id, partial-id, id-substring, name, or filename |
modified | Session file mtime (ISO-8601) |
archived | Codex archived flag (false for Claude) |
The same lookup in other commands
Section titled “The same lookup in other commands”You rarely need to call resolve by hand first. These commands accept the
same queries directly:
aichat <session>andmenutrim,smart-trim,trim-in-place, andresumeexport,export-claude,export-codex,info, andcopymove,delete,query,clone,rollover, andlineagefind-original,find-derived, andport
trim-in-place and the two agent-specific exporters constrain the resolver to
the agent named by the command. move-account uses the
same tiers across several source homes and includes the source home in its
picker.
# All of these name one sessionaichat move session-finder ~/Git/other-repoaichat info a15f9cedaichat lineage 88e9-43d7Except for the constrained variants above, these commands search both
agent homes and detect the agent themselves. Where a command offers
--agent, the option narrows the search. It may come before or after the
session argument, and --agent=codex works as well as --agent codex.
Pass a session file path and no home is searched at
all: the agent comes from the file’s own content, and
--agent then requires the file to be that agent’s.
A file that sits inside an agent home but does not
read as a session is rejected, rather than trusted
because of where it lives.
In an interactive terminal, an ambiguous action query opens a Rich table with
the candidates newest first. Choose a number to continue with that session, or
enter q to cancel. Ctrl-C and end-of-input also cancel before the command
changes anything. Non-interactive and JSON callers still fail deterministically
with the candidate list instead of guessing or prompting.
Home overrides
Section titled “Home overrides”--claude-home and --codex-home before the
subcommand apply to any of these commands, and carry
through the interactive menus into whatever action
you pick:
aichat --claude-home ~/.claude-work info my-sessionresume also takes both flags itself; trim and
smart-trim take their own --claude-home. A
command-local flag wins over the root-level one.
The lookup avoids the resolver’s full scan whenever it safely can, because that scan reads every transcript in both homes — on a home with a few thousand sessions it costs on the order of ten seconds.
- A unique full id normally answers in well under a second. It is the top match tier, so no weaker tier can outrank it and nothing else has to be read.
- A partial id costs a second or two: before trusting a filename match, the lookup rules out a session whose exact name is that same string, since an exact name outranks a partial id.
- A name, or anything else, goes through the full scan.
None of this changes which session you get — it only changes how much work is done to be sure of it.
port uses the same resolver and picker. It has no --agent, so
use --claude-home and --codex-home to choose the searched homes.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Resolved — one match, record printed |
1 | Not found, or an input/home error |
2 | Ambiguous — multiple matches |
On an ambiguous query, resolve exits 2 and
prints the candidates (newest first) so the caller
can disambiguate:
{"error": "ambiguous", "query": "tmux-fix", "agent": "claude", "match_count": 2, "candidates": [ /* full records */ ]}Expected input errors — an empty or missing query, an
unsupported --agent, or a --home that is not a
directory — exit 1 with a structured
{"error": ..., "detail": ...} object, never a
traceback.
Examples
Section titled “Examples”# By /rename name (pretty panel in a terminal)aichat resolve session-finder
# By partial id, as JSON for an agentaichat resolve a15f9ced --json
# By a MID-ID fragment (id-substring tier)aichat resolve 88e9-43d7 --json
# A Codex session by its rollout timestamp fragment# (filename tier)aichat resolve 2026-03-25T14-50 --agent codex --json
# A Codex session by nameaichat resolve "my codex thread" --agent codex --json
# Search a non-default homeaichat resolve <id> --home ~/.claude-rja --json
# Agent-facing: captured output is JSON automaticallyaichat resolve session-finder | jq .session_file