1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# aise example config
#
# Write a starting config from it, with every setting but the state paths commented out:
# aise config init
# Print this example:
# aise config example
#
# Most users can leave this file absent. Built-in defaults are the same values shown here for
# tunables. `aise config init` writes every setting commented out except the database and cache
# paths: uncomment a line to change it, and later releases' defaults keep applying to the rest.
# Provider paths are commented out below so a restored config keeps platform-specific built-in
# discovery unless you deliberately override paths.
#
# Durable settings use one precedence rule on every supported surface:
# explicit CLI/API argument > AI_SESSION_SEARCH_* environment variable > this file > typed default.
# Use `aise config origins` to see the source selected for database, cache, threads, and refresh.
# Canonical operational variables are AI_SESSION_SEARCH_CONFIG, AI_SESSION_SEARCH_DATABASE,
# AI_SESSION_SEARCH_CACHE_DIR, AI_SESSION_SEARCH_THREADS, and
# AI_SESSION_SEARCH_INDEX_REFRESH.
[]
# After ordinary interactive CLI output, check at most once per interval for the
# latest completed stable GitHub release. MCP and library calls never check.
= true
= 24
# End-to-end timeout for the infrequent request. Explicit `aise package check|update`
# uses a longer bounded timeout and reports failures.
= 1000
[]
# After an upgrade by any package manager, the first command (including `aise integrations status`
# and the MCP server) rewrites installed ai-session-search skill files and instruction blocks that
# still match what aise wrote, so upgrading never needs `aise integrations install`. Anything you
# edited is left alone and reported once. It runs when the install included the skill.
= true
[]
# Optional explicit state paths. Relative values resolve from ~/.ai-session-search/.
# Unset, they follow the platform data/cache defaults; set db_path to reuse an existing database
# without moving a large index.
# db_path = "/absolute/path/to/index.db"
# cache_dir = "/absolute/path/to/cache"
# Implicit read refresh policy: auto, before-query, or existing-only.
= "auto"
# SQLite busy timeout for normal CLI/MCP reads and writes.
= 5000
# Timeout for automatic pre-read reindex refreshes. If SQLite is still busy after this,
# aise serves the existing valid index instead of failing the read.
= 10000
# After one process completes automatic refresh, other read commands skip refresh for
# this many milliseconds and stay read-only.
= 1500
[]
# CLI default for session-level `aise list` and `aise search` when
# `--limit` is omitted. An explicit `--limit 0` requests every matching session.
# Does not affect message search or MCP page sizes.
= 50
# Prefer sessions from the current repository when ranking session-level search.
= true
[]
# Ranking weights for session-level search (`aise search`, `aise tui`, MCP `search_sessions`).
# They do not decide which sessions match, only the order the matches come back in: a session
# is a hit if any haystack contains the whole query, contains one of its tokens, or fuzzy-matches
# it. Message search does not use these.
#
# Six haystacks are scored per session: title, summary, cwd, repo root, preview, transcript.
# A caseless substring hit on the whole query adds that haystack's weight.
= 600
= 450
# cwd and repo root share this one.
= 350
= 250
# The transcript body, and any haystack not named above.
= 100
# Added once per query token found in a haystack, so a two-token query matching both in the
# title adds it twice there.
= 40
# Added once when a query has more than one token and every token matched somewhere.
= 150
# Recency adds `(recency_max_days - age_in_days) * recency_weight`, with the age clamped to the
# range, so a session touched today gets the full 180 and one older than the window gets 0.
# A session with no recorded update time gets nothing either way.
= 2
= 90
# Added when the session's repo root equals the invoking repository, and only while
# [search].prefer_current_repo is true.
= 200
[]
# Optional shared page size for message search. Omission preserves each surface's
# contract: Rust, CLI, and Python return all literal/regex/no-text matches when no
# purpose or call limit applies; MCP uses [mcp].search_messages_limit. Fuzzy search
# always requires a finite page. Request every result explicitly with all_results
# rather than using zero.
# default_limit = <positive integer>
# Maximum Unicode scalar characters in each automatic selected-field match excerpt.
# This is presentation-only and does not change matching, ranking, or pagination.
# match_evidence_max_chars = 220
[]
# Default neighboring messages added after hit selection. A per-call value wins, and a purpose
# bundle outranks this. Commented out like every other optional key in this file: omitting them
# and writing an explicit 0 resolve to the same window and differ only in the origin
# `aise config origins` reports, so the file no longer records a choice the reader did not make.
# context_before = 0
# context_after = 0
[]
# Optional hard ceilings. Omission preserves current runtime behavior and does not
# introduce an implicit unlimited value or a new numeric ceiling.
# max_hits_per_page = <positive integer>
# Maximum total neighboring messages before plus after each returned hit.
# max_context_neighbors_per_hit = <positive integer>
[]
# `all` preserves current unrestricted behavior. `allowed-roots` is opt-in and is
# enforced below adapters; a restricted invocation with no authoritative roots fails closed.
= "all"
= []
= false
# Optional versioned purpose bundles fill only omitted soft preferences. They cannot
# change query interpretation, caller filters, authority, or hard budgets. No built-in
# purpose ships without labeled replay evidence.
# [search.purposes.descriptive-purpose-name]
# version = <positive integer>
# operation = "message-search"
#
# [search.purposes.descriptive-purpose-name.preferences]
# default_limit = <positive integer>
# context_before = <nonnegative integer>
# context_after = <nonnegative integer>
# receipt_level = "none" | "summary" | "full"
# include_refs = <boolean>
# lines_per_message = <signed integer>
# match_evidence_max_chars = <positive integer>
[]
# Maximum simultaneous read-only SQLite tool calls per MCP server process. "auto" admits half the
# available logical CPUs, rounded up, because fuzzy reads share a separate host-sized worker pool.
# "host" admits one call per logical CPU; a positive integer sets an exact cap.
= "auto"
# MCP defaults apply only when an MCP tool call omits the matching argument.
# Explicit tool arguments always win. These matter because MCP responses usually go
# straight into an agent context window.
# Default `search_sessions.limit`: session-level search page size.
= 10
# Default `list_sessions.limit`: recent-session page size.
= 20
# Default `search_messages.limit`: message-hit page size. Must be at least 1 so
# pagination always makes progress. Sized against max_tool_result_chars below: at the
# measured per-result cost this lands an ordinary call near half the ceiling, leaving
# room for a long matched message and for detail=full or parsed_references, which
# measured 4.8x and 2.7x and compose.
= 15
# Default `run_skill_capability` message-classification page size. Smaller than the CLI and
# Python default (`[capabilities.message_classification].limit`) on purpose: an MCP result goes
# straight into an agent context window and each correction row carries a whole
# user message.
= 20
# Ceiling on one serialized MCP CallToolResult, in characters. A call that would exceed it
# returns an actionable error naming what fits instead; nothing is silently trimmed, so no
# response arrives with results, context, evidence, include groups or receipts quietly
# removed. 48,000 is Codex's model-facing result cap, and Codex is the only measured client
# that truncates from the middle with no marker -- a smaller cap that announces its overflow,
# like Gemini CLI's 40,000, loses nothing and is not the one to defend against. Override per
# registration with AI_SESSION_SEARCH_MAX_TOOL_RESULT_CHARS in that server's env block.
# MCP tools/call only: the CLI, Rust and Python surfaces return every result by design.
= 48000
# Default `get_session.transcript_lines`: positive=head, negative=tail,
# 0=entire transcript. The bounded tail default keeps transcript responses small
# enough for an agent context window while showing how a session ended; callers
# pass explicit values to see how it started or to fetch everything. Does not
# affect focused `message_seq` calls.
= -40
# Default `lines_per_message` for `search_messages` hits/context and `get_session`
# focused `message_seq` output: caps each individual message's content to this many
# lines (positive=head, negative=tail, 0=full content). Distinct from
# `get_session_transcript_lines`, which windows one whole session transcript. This
# changes presentation only, never matches, ranking, result count, pagination,
# context membership, or reference extraction.
= 0
# Default `preview_chars` for concise MCP hit/context previews and `get_session`
# summary or focused-message output. Explicit tool-call values win. Does not affect
# transcript output. Must be at least 1.
= 220
# Aggregate compact evidence: positive=first, negative=last, 0=all. The bounded default protects
# agent context; zero is available explicitly for pipelines that consume complete structured data.
= -12
# Default `query_session_index.max_cell_chars`: truncates long string cells in MCP
# JSON responses only. It does not change SQL execution or CLI `db query` output.
# 0 disables MCP string-cell truncation.
= 1000
# MCP raw-SQL execution timeout in milliseconds. 0 disables interruption and is
# the default until representative valid-query/concurrency calibration justifies
# a finite availability guard. This never applies to indexed search tools.
= 0
[]
# Internal MCP presentation budgets. These affect only generated tool descriptions,
# not search/query results. They exist to keep tool descriptions concise while still
# giving agents enough live schema context to form valid SQL.
= 4
= 12
# What each MCP client accepts before it truncates or drops what the server sends. Every row
# ships with the value measured from that client's own source at a pinned version, recorded in
# docs/development/mcp-client-limits-and-measured-evidence.md, so this table is only for a client
# that has since moved. Set a row by the name `aise mcp schema-budget` reports; an unknown name
# is rejected rather than ignored, so a typo cannot leave the shipped budget quietly in force.
#
# A config file is per machine while these numbers are per client, so an MCP registration can
# instead set its own in its `env` block:
# AI_SESSION_SEARCH_CLIENT_LIMIT_CODEX_INPUT_SCHEMA_BYTES=6000
#
# [mcp.client_limits]
# codex-input-schema-bytes = 6000
[]
# Default transcript lines for `aise show` when `--transcript-lines` is omitted:
# positive=head, negative=tail, 0=entire transcript. A bounded default keeps long
# sessions skimmable; use `--transcript-lines 0` explicitly when you really want
# the full transcript.
= -40
# Default `aise messages search/get/timeline --lines-per-message`: caps each
# individual message's content to this many lines (positive=head, negative=tail,
# 0=full content). Distinct from `show_transcript_lines`, which windows one whole
# session transcript. This changes presentation only and never discards results.
= 0
# Default compact preview characters for `aise messages evidence` when
# `--preview-chars` is omitted. Does not affect full JSON message content.
# Must be at least 1.
= 220
# Aggregate records for show --summary and messages evidence: positive=first, negative=last,
# 0=all. This affects presentation only.
= -12
[]
# Native CLI/Rust default maximum rows for raw read-only SQL. MCP currently uses
# this row default too, but has a separate execution-time guard above. 0 means
# unlimited rows and can produce huge output.
= 100
# Native CLI/Rust raw-SQL timeout in milliseconds. 0 (the default) disables
# interruption; pass a finite value explicitly when the caller wants a deadline.
= 0
[]
# Worker threads for data-parallel scans. 0 = auto, 1 = sequential.
= 0
[]
# Directories scanned for Agent Skill packages. Each entry is either a skill directory (one
# holding SKILL.md) or a directory containing skill directories. `~` is expanded.
#
# These are DISCOVERY roots, not the install destinations `aise integrations install` writes to:
# install writes the same bundled skill to three client roots, so scanning those would find three
# copies of one name. Discovery is not activation: a skill found here changes nothing until it is
# selected by `aise skills <name-or-path>` or a repeatable `--skill`.
= []
# Parent directory `aise skills create` writes into when --output-dir is omitted. Unset = require
# the flag rather than guess where a new directory belongs.
# authoring_root = "~/.claude/skills"
[]
# Default native CLI and Python result count. 0 = every match. An explicit CLI --limit wins.
= 50
[]
# Optional slash-command filters for `aise planning`. Empty = count every slash command.
= []
# Default `aise planning --limit`. 0 = every command.
= 50
# Default `aise vocab --limit`. 0 = unlimited.
= 50
# Default `aise repeats` output and phrase-mining controls. Command-line flags win.
# Zero means all groups/examples; minimum matches and phrase widths must be at least 1.
= 50
# Representative examples serialized per repeat group. Aggregate match and session counts remain
# complete. The table has always shown at most three examples; use 0 for every matching message.
= 3
= 2
= 2
= 5
[]
# Interactive TUI (`aise tui`) pacing and step behavior.
# Total preview body budget: the transcript summary's sections scale proportionally to
# their weights (first prompt, first reply, final prompt, final reply), each floored at one
# line so a small budget cannot erase a bookend. The 1.0.0rc2 name `preview_lines` is still
# accepted; when both are set, `preview_body_lines` wins.
= 34
# Idle wake interval for the TUI event loop, in milliseconds (minimum 1). Every key redraws
# immediately; this value paces settled idle turns, while active worker output is checked sooner.
# Values must fit the platform monotonic clock; unrepresentable intervals are rejected.
= 150
# Milliseconds an edited query must stay unchanged before it becomes a search. Typing never
# waits on this: every keystroke echoes immediately and the search runs off the input thread.
# 0 searches on every keystroke, and Enter searches the current query at once whatever the
# value. Raise it on a large index, where one search costs seconds and a typed burst would
# otherwise start a scan per character that the next keystroke cancels.
= 150
# Rows the selection moves for PageDown/PageUp in the session list.
= 10
# Rendered rows the preview scrolls for K/J (and Shift+Up/Shift+Down). Rows, not transcript
# lines: a
# long line occupies several rows once the pane wraps it.
= 5
# Rendered rows the preview scrolls for Ctrl-d/Ctrl-u.
= 15
# Provider label column width in the session list. Normal panes clamp to the longest label;
# exceptionally narrow panes clamp to their actual interior and may truncate labels.
= 9
# Percent of the body width for the session-list pane; the preview pane gets the remainder.
= 45
# Whether the TUI draws characters outside ASCII: box borders, the ellipsis, and the preview's
# section rules and elision markers. "auto" reads LC_ALL, LC_CTYPE, then LANG and falls back to
# ASCII only when one of them names an encoding that cannot carry them (C, POSIX, or a charset
# that is not UTF-8); an unset locale keeps the box drawing. "on" and "off" decide it outright.
= "auto"
# Whether the TUI colours anything. "auto" honours NO_COLOR (set and non-empty, whatever the
# value) and TERM=dumb. Emphasis that does not need colour is drawn either way: the selected row
# carries a marker, and bold survives.
= "auto"
# What each key press means. Name only the actions you want to change: the rest keep the
# defaults shown here, the same way a [providers.<name>] table overrides only the fields it
# names. An action set to [] is deliberately unbound, and the status bar stops advertising it.
#
# A binding is a single character, f1 through f35, or one of enter, esc, tab, backtab,
# backspace, delete, insert, space, up, down, left, right, home, end, pageup, pagedown — with
# any of ctrl, alt, shift, super joined to it by +. Shift is not written for a capital letter:
# "G" is the binding, because a terminal may or may not report the shift flag beside it. For the
# same reason a chorded letter ignores its case, so "ctrl+c" and "ctrl+C" are one binding.
#
# A command may be reached by as many keys as you list, so adding your own keeps the shipped
# one. Listing a key an action already has is a repeat and is kept once; the same key on two
# commands reachable from one mode is a conflict and is refused.
#
# `interrupt` is answered in both modes and takes two presses: the first says so in the status
# bar and the second quits. It exists because a full-screen terminal application turns off the
# terminal's own interrupt character, so nothing else would stop it. Binding both `quit` and
# `interrupt` to nothing is refused, because it would leave no way out.
#
# [ui.keys]
# interrupt = ["ctrl+c"]
# quit = ["q", "esc"]
# enter_search = ["/"]
# leave_search = ["enter", "esc"]
# move_down = ["j", "down"]
# move_up = ["k", "up"]
# page_down = ["pagedown"]
# page_up = ["pageup"]
# top = ["g"]
# bottom = ["G"]
# cycle_provider = ["p"]
# cycle_session_kind = ["f"]
# cycle_time_window = ["s"]
# toggle_warnings_only = ["w"]
# preview_scroll_down = ["J", "shift+down"]
# preview_scroll_up = ["K", "shift+up"]
# preview_page_down = ["ctrl+d"]
# preview_page_up = ["ctrl+u"]
# resume = ["enter", "r"]
# help = ["?"]
#
# The search box's own editing. Typing a character is not bound here, because it is the text
# itself; everything a reader presses to change the text or move the caret is.
# clear_query = ["ctrl+u"]
# delete_backward = ["backspace"]
# delete_forward = ["delete"]
# delete_word_backward = ["ctrl+w"]
# cursor_left = ["left"]
# cursor_right = ["right"]
# cursor_start = ["home", "ctrl+a"]
# cursor_end = ["end", "ctrl+e"]
# Uncomment provider tables only when you want to disable a provider or replace the platform
# defaults with explicit paths. If `paths` is absent, aise uses built-in OS-aware defaults;
# explicit `paths = []` means search no roots for that enabled provider.
#
# [providers.claude]
# enabled = true
# paths = ["~/.claude/projects"]
#
# [providers.claude-desktop]
# enabled = true
# paths = [
# "~/Library/Application Support/Claude/local-agent-mode-sessions",
# ]
#
# [providers.codex]
# enabled = true
# paths = ["~/.codex/sessions"]
#
# [providers.cursor]
# enabled = true
# paths = ["~/.cursor/projects"]
#
# [providers.antigravity]
# enabled = true
# paths = [
# "~/.gemini/antigravity-cli/brain",
# "~/.gemini/antigravity/brain",
# ]
#
# [providers.pi]
# enabled = true
# paths = ["~/.pi/agent/sessions"]
#
# [providers.prime-agent]
# enabled = true
# paths = ["~/.prime/agent/sessions", "~/.prime/agent/session-artifacts"]
#
# [providers.aistudio]
# enabled = true
# paths = []
#
# [providers.gemini-cli]
# enabled = true
# paths = ["~/.gemini/tmp"]