obelisk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseobelisk
obelisk
Search and query local Claude Code, Codex, Kimi Code, and Pi session history.
Obelisk indexes sessions, messages, tool calls, tool results, summaries,
subagents, workflows, workflow agents, parent chains, and raw JSONL lines into
SQLite + FTS5.
Obelisk has four transcript sources. Treat all of them as ordinary sessions by
default: Claude rows use , Codex rows use ,
Kimi Code rows use , and Pi rows use . Use
only when provenance matters or the user asks to scope to one provider.
Provider-specific records are projected into the same canonical tables; some
providers may not emit every kind of subagent or workflow metadata.
source='claude'source='codex'source='kimi'source='pi'sourceObelisk is a CodeAct memory layer: write a small JS query, run it locally, read
the JSON, then answer. Do not turn history into a flat document or browse entire
sessions by default.
搜索并查询本地Claude Code、Codex、Kimi Code和Pi的会话历史。
Obelisk将会话、消息、工具调用、工具结果、摘要、子代理、工作流、工作流代理、父链以及原始JSONL行索引到SQLite + FTS5中。
Obelisk有四种转录来源。默认将所有来源视为普通会话:Claude行使用,Codex行使用,Kimi Code行使用,Pi行使用。仅当来源归属很重要或用户要求限定到某一提供商时才使用参数。特定提供商的记录会被映射到相同的标准表中;部分提供商可能不会生成所有类型的子代理或工作流元数据。
source='claude'source='codex'source='kimi'source='pi'sourceObelisk是CodeAct的内存层:编写一个小型JS查询,本地运行,读取JSON,然后给出答案。默认情况下,不要将历史记录转换为扁平文档或浏览整个会话。
Quick Start
快速开始
Fast keyword search (pass a unique nonce so Obelisk can recognize your own
session in results):
bash
obelisk --search "keyword" --nonce "$(uuidgen 2>/dev/null || echo "$$.$RANDOM.$RANDOM")"Custom query:
-
Write a bounded JS query to a unique temp file — the as-typed file path is your invocation nonce:bash
qdir=$(mktemp -d /tmp/obq.XXXXXX 2>/dev/null || { d="/tmp/obq.$$.$RANDOM"; mkdir "$d"; echo "$d"; }) qfile="$qdir/query.mjs"Thename lives inside the unique directory, so the.mjstemplate always ends on themktemprun (BSDXrequires that).mktemp -
Run:bash
obelisk --query "$qfile" -
Parse JSON stdout and answer with concise evidence.
The query file runs inside . Use to emit JSON.
Query scripts are read-only: and are not available, and
only accepts read-only SELECT/WITH queries.
(async () => { ... })()returnremember()forget()sql()快速关键词搜索(传递唯一随机数,以便Obelisk能在结果中识别你自己的会话):
bash
obelisk --search "keyword" --nonce "$(uuidgen 2>/dev/null || echo "$$.$RANDOM.$RANDOM")"自定义查询:
-
将有界JS查询写入唯一的临时文件——带类型的文件路径就是你的调用随机数:bash
qdir=$(mktemp -d /tmp/obq.XXXXXX 2>/dev/null || { d="/tmp/obq.$$.$RANDOM"; mkdir "$d"; echo "$d"; }) qfile="$qdir/query.mjs"文件名位于唯一目录内,因此.mjs模板始终以mktemp序列结尾(BSDX要求如此)。mktemp -
运行:bash
obelisk --query "$qfile" -
解析JSON标准输出并以简洁的证据作答。
查询文件在中运行。使用输出JSON。查询脚本是只读的:和不可用,且仅接受只读的SELECT/WITH查询。
(async () => { ... })()returnremember()forget()sql()Your Own Session In Results
结果中的当前会话
Obelisk refreshes the index before each query, so your own live session shows
up in results. The invocation nonce (, or the unique
file path) lets Obelisk mark it: session projections in
hits and rows carry , and
holds the invoking session id when known. Treat
a session flagged as your own current context, NOT as independent
historical evidence. Resolution is newest-wins over recent matches; only a
near-simultaneous same-nonce collision (or no match at all) leaves nothing
marked and null — identity is honestly unknown.
--search --nonce--querysearch()sessions()is_invoking: trueoverview().current.session_idis_invokingcurrent.session_idObelisk会在每次查询前刷新索引,因此你的实时会话会出现在结果中。调用随机数(,或唯一的文件路径)可让Obelisk标记它:命中结果和行中的会话投影会带有,当调用会话ID已知时,会保存该ID。将标记为的会话视为你自己的当前上下文,而非独立的历史证据。解析规则为最新匹配优先;只有近乎同时发生的相同随机数冲突(或完全无匹配)才会导致无标记且为空——此时身份无法确定。
--search --nonce--querysearch()sessions()is_invoking: trueoverview().current.session_idis_invokingcurrent.session_idDefault First Pass
默认首次查询
Start with helpers, not raw SQL. For the first Obelisk query in a task, normally
call unless the user already gave an exact
, message , or absolute file path.
overview({ limit: 6 })session_iduuidFor semantic or synthesis tasks, combine orientation, memory recall, and raw
session evidence before deciding whether a detail pass is needed:
js
const map = overview({ limit: 6 });
const project = map.current.project?.project;
const topic = 'English topic terms translated from the user request';
return {
orientation: map.current_project,
prior_memories: memories({ project, query: topic, limit: 5 }),
session_evidence: search(topic.replace(/[-_]/g, ' '), { project, limit: 8 }),
};Use only as an escalation path for exact joins, aggregations, or schema
questions that helpers cannot express cleanly. Do not use raw SQL as a generic
fallback for broad retrieval.
sql()优先使用辅助函数,而非原始SQL。在任务中首次使用Obelisk查询时,除非用户已提供确切的、消息或绝对文件路径,否则通常调用。
session_iduuidoverview({ limit: 6 })对于语义或合成任务,在决定是否需要详细查询前,先结合定位信息、记忆召回和原始会话证据:
js
const map = overview({ limit: 6 });
const project = map.current.project?.project;
const topic = '从用户请求翻译而来的英文主题术语';
return {
orientation: map.current_project,
prior_memories: memories({ project, query: topic, limit: 5 }),
session_evidence: search(topic.replace(/[-_]/g, ' '), { project, limit: 8 }),
};仅当辅助函数无法清晰表达确切的连接、聚合或架构问题时,才将作为升级方案。不要将原始SQL用作通用的广泛检索 fallback。
sql()Intent Routing
意图路由
Obelisk supports a small intent prefix layer after . This is for
output intent, not retrieval architecture.
/obelisk| Intent | Description | Reference |
|---|---|---|
| Generate weekly/monthly recap card content for app handoff or share-style output. | |
Routing rules:
- If the first word is , read
recapbefore the first query. Everything afterreferences/recap/overview.mdis the recap target. Common app-generated prompts includerecap,/obelisk recap this week,/obelisk recap last week, and/obelisk recap this month; interpret these as natural period targets relative to the current date and timezone./obelisk recap last month - does not create a separate retrieval layer. It still uses
recap,overview(), helpers, andmemories()only when needed.sql() - Follow the overview's card-by-card sequence. Each card has its own retrieval pattern and writing file; retrieve that card's evidence, read that card's writing file, update the JSON, then move to the next card. Do not preload all recap references before the current card is written.
- If the first word is not , do not load
recap. Continue with Query Routing below. Do not infer recap from broad requests for weekly/monthly summaries, charts, rankings, shareable cards, or playlist-style metaphors.references/recap/overview.md
Obelisk在之后支持一个小型意图前缀层。这用于输出意图,而非检索架构。
/obelisk| 意图 | 描述 | 参考 |
|---|---|---|
| 生成用于应用交接或分享式输出的每周/每月回顾卡片内容。 | |
路由规则:
- 如果第一个词是,在首次查询前阅读
recap。references/recap/overview.md之后的所有内容都是回顾目标。常见的应用生成提示包括recap、/obelisk recap this week、/obelisk recap last week和/obelisk recap this month;将这些解释为相对于当前日期和时区的自然时间段目标。/obelisk recap last month - 不会创建单独的检索层。它仍会使用
recap、overview()、辅助函数,仅在必要时使用memories()。sql() - 遵循概述中的卡片顺序。每张卡片都有自己的检索模式和写入文件;检索该卡片的证据,读取该卡片的写入文件,更新JSON,然后进入下一张卡片。不要在当前卡片写入前预加载所有回顾参考资料。
- 如果第一个词不是,不要加载
recap。继续执行下方的查询路由。不要从对每周/每月总结、图表、排名、可分享卡片或播放列表式隐喻的广泛请求中推断回顾意图。references/recap/overview.md
Reference Map
参考地图
Use references by job, not by habit:
| Reference | Use when |
|---|---|
| Broad synthesis, progress summaries, design history, weekly/monthly reviews, approved memory write/archive/update scripts, or questions about what the user did/learned/decided/tried/abandoned. |
| Multi-step retrieval, scoped project/file/session searches, or when scope/artifact/semantic boundaries affect query design. |
| Raw SQL field and join quick reference before writing non-trivial |
| Helper signatures, option names, return fields, or exact |
| Error recovery, FTS syntax, aliases, ordering, row-shape surprises, or compact/raw tradeoffs. |
| Explicit |
按需使用参考资料,而非习惯性使用:
| 参考资料 | 使用场景 |
|---|---|
| 广泛合成、进度总结、设计历史、每周/每月回顾、已批准的记忆写入/归档/更新脚本,或关于用户做了什么/学到了什么/决定了什么/尝试了什么/放弃了什么的问题。 |
| 多步骤检索、限定范围的项目/文件/会话搜索,或范围/工件/语义边界影响查询设计的场景。 |
| 在编写非平凡的 |
| 辅助函数签名、选项名称、返回字段,或 |
| 错误恢复、FTS语法、别名、排序、行结构意外,或紧凑/原始权衡问题。 |
| 仅用于明确的 |
Query Routing
查询路由
Before writing a query, classify the task. Progressive disclosure is useful, but
skipping the relevant reference usually costs extra query rounds.
- Read before the first query for broad synthesis, progress summaries, design history, ordinary weekly/monthly reviews, or questions that ask what the user did, learned, decided, tried, or abandoned. Start from the first-pass or one-shot synthesis pattern, then run a faceted detail pass if needed.
references/query-patterns.md - Read before multi-step retrieval, scoped project/file/session searches, or synthesis/conclusion/history questions. It defines the query design frame.
references/retrieval-semantics.md - Read before raw
references/schema.mdunless the needed table/column relationship is already explicit here. It is intentionally short and SQL-focused. Do this before running the SQL, not after a missing-column error. Do not start with raw SQL for broad synthesis unless helpers cannot express the needed aggregation or join.sql() - Read when helper option names, return fields, scalar shorthand behavior, or
references/api-reference.md/remember()details are unclear.forget() - Read after an error or when FTS syntax, aliases, ordering, row shapes, or compact/raw tradeoffs are unclear.
references/pitfalls.md
If a helper row shape is unclear, first run a tiny scoped query and return
or a compact sample. Do not invent field names.
Object.keys(row)For approved memory mutations, follow the Memory Layer section below first.
Use for copyable scripts
(, , ),
and only for exact parameter semantics.
references/query-patterns.md--attuneAttune Approved MemoryForget Approved MemoryUpdate Approved Memoryreferences/api-reference.md在编写查询前,先对任务进行分类。逐步披露很有用,但跳过相关参考资料通常会增加额外的查询轮次。
- 在首次查询广泛合成、进度总结、设计历史、普通每周/每月回顾,或询问用户做了什么、学到了什么、决定了什么、尝试了什么、放弃了什么的问题前,阅读。从首次查询或一次性合成模式开始,然后在需要时运行分面详细查询。
references/query-patterns.md - 在进行多步骤检索、限定范围的项目/文件/会话搜索,或合成/结论/历史问题前,阅读。它定义了查询设计框架。
references/retrieval-semantics.md - 在使用原始前,阅读
sql(),除非所需的表/列关系已在此处明确说明。它特意设计得简短且聚焦于SQL。在运行SQL之前阅读,而不是在出现列缺失错误之后。除非辅助函数无法表达所需的聚合或连接,否则不要从原始SQL开始进行广泛合成。references/schema.md - 当辅助函数选项名称、返回字段、标量简写行为,或/
remember()细节不明确时,阅读forget()。references/api-reference.md - 出现错误后,或当FTS语法、别名、排序、行结构,或紧凑/原始权衡问题不明确时,阅读。
references/pitfalls.md
如果辅助函数的行结构不明确,先运行一个小型限定查询并返回或紧凑样本。不要自行发明字段名。
Object.keys(row)对于已批准的内存变更,首先遵循下方的内存层部分。使用获取可复制的脚本(、、),仅在需要确切参数语义时使用。
references/query-patterns.md--attuneAttune Approved MemoryForget Approved MemoryUpdate Approved Memoryreferences/api-reference.mdCore API
核心API
search(text, opts?)
search(text, opts?)search(text, opts?)
search(text, opts?)Full-text search across main messages, subagent messages, and workflow-agent
messages.
Returns:
js
[{ message: { uuid, text, content_type, is_meta, role, timestamp, model, cwd, visibility, source },
session: { id, title, project, started_at, source, is_invoking? },
rank,
context }]session.is_invokingtruecontextcontext(uuid)trace(uuid)Use to keep evidence boundaries intact:
is user/assistant visible language, is trace/debug material,
marks a tool-call message whose details live in , and
marks a tool-result message whose details live in .
is a conservative fallback. Do not treat as a user-visible
assistant conclusion. Real user input is plus ;
do not invent a separate content type.
message.content_typetextthinkingtool_usetool_callstool_resulttool_resultsunknownthinkingtype='user'content_type='text'user_messageUse to separate transcript control-plane material from
conversation evidence. marks injected caveats, command envelopes, or
other messages that entered the transcript as user-role content but should not
be treated as the user's request by default. and omit meta
messages unless is passed; and preserve
the current causal chain and expose on returned rows.
message.is_metais_meta=1search()thread()includeMeta: truecontext()trace()is_metaPi can preserve a branch that was tried and later superseded as
. Only Pi populates it: other sources either do not
record supersession in their transcripts or discard it while indexing, so an
empty inactive result never means nothing was abandoned -- only that this
source cannot say. Default helpers return only evidence. Pass
to , , , ,
, , , or only when the abandoned
path matters. Every returned message or evidence row is labeled with
; describe inactive evidence as something tried and then
superseded, never as the final decision. is reserved for
display-suppressed or transport-only records and is never returned by these
helpers, even with the option enabled.
visibility='inactive'visibleincludeInactive: truesearch()context()trace()thread()summaries()raw()fileHistory()failures()visibilityhiddenOpts:
.
{ limit, sessionId, project, after, before, cwd, source, includeMeta, includeInactive }projectLIKEsessions.projectsource'claude''codex''kimi''pi'对主消息、子代理消息和工作流代理消息进行全文搜索。
返回:
js
[{ message: { uuid, text, content_type, is_meta, role, timestamp, model, cwd, visibility, source },
session: { id, title, project, started_at, source, is_invoking? },
rank,
context }]仅当命中结果属于运行此查询的会话时,才为(参见“结果中的当前会话”);否则会被省略。
session.is_invokingtrue此处的指时间相邻项:同一会话中按时间戳排列的附近消息。它不是父链。使用或获取因果/父链上下文。
contextcontext(uuid)trace(uuid)使用保持证据边界完整:是用户/助手可见的语言,是跟踪/调试材料,标记工具调用消息,其详情位于中,标记工具结果消息,其详情位于中。是保守的 fallback。不要将视为用户可见的助手结论。真实用户输入是加上;不要自行发明单独的内容类型。
message.content_typetextthinkingtool_usetool_callstool_resulttool_resultsunknownthinkingtype='user'content_type='text'user_message使用将转录控制平面材料与对话证据分开。标记注入的警告、命令信封或其他作为用户角色内容进入转录但默认不应被视为用户请求的消息。和会省略元消息,除非传递;和会保留当前因果链并在返回行中暴露。
message.is_metais_meta=1search()thread()includeMeta: truecontext()trace()is_metaPi可以保留一个已尝试但后来被取代的分支,标记为。只有Pi会填充此字段:其他来源要么不在其转录中记录取代信息,要么在索引时丢弃该信息,因此空的非活跃结果并不意味着没有内容被放弃——仅表示该来源无法提供相关信息。默认辅助函数仅返回证据。仅当废弃路径很重要时,才向、、、、、、或传递。每个返回的消息或证据行都带有标签;将非活跃证据描述为已尝试但后来被取代的内容,而非最终决策。保留给显示抑制或仅传输的记录,即使启用选项,这些助手也永远不会返回此类记录。
visibility='inactive'visiblesearch()context()trace()thread()summaries()raw()fileHistory()failures()includeInactive: truevisibilityhidden选项:
。
{ limit, sessionId, project, after, before, cwd, source, includeMeta, includeInactive }projectsessions.projectLIKEsource'claude''codex''kimi''pi'context(uuid, opts?)
context(uuid, opts?)context(uuid, opts?)
context(uuid, opts?)Returns the full story around one indexed message:
js
{ message, parentChain, session, subagent, workflow }Use this after finds a promising message. It is the usual way to
expand vertically from one evidence point without dumping the whole session.
The target and returned ancestors must be visible by default. Pass
to follow an explicitly superseded Pi path.
search(){ includeInactive: true }返回一条索引消息的完整上下文:
js
{ message, parentChain, session, subagent, workflow }在找到有希望的消息后使用此函数。这是从一个证据点垂直扩展而无需转储整个会话的常用方式。默认情况下,目标和返回的祖先必须是可见的。传递以跟踪明确被取代的Pi路径。
search(){ includeInactive: true }sql(query, ...params)
sql(query, ...params)sql(query, ...params)
sql(query, ...params)Read-only SQL SELECT/WITH with placeholders. Returns array rows. SQL is an
escape hatch for exact structured joins and aggregations after the helper-first
surface is insufficient; it is not the default retrieval entry point.
?Before writing non-trivial SQL, read . It is the raw SQL
field/join quick reference. The executable DDL is CLI-owned and is deliberately
not duplicated in this docs-only skill. Common safe joins:
references/schema.md- does not have timestamps. Join
tool_calls.messages m ON m.uuid = tc.message_uuid - does not have timestamps. Join
tool_results.messages m ON m.uuid = tr.message_uuid - For project/session filters, join .
sessions s ON s.id = <table>.session_id - Prefer SQL-side ,
GROUP BY,COUNT,MAX, andORDER BYover hand-counting in the final answer.LIMIT
Tables: , , , , ,
, , , , .
sessionsmessagestool_callstool_resultssummariesmemoriessubagentsworkflowsworkflow_agentsmessages_fts带占位符的只读SQL SELECT/WITH。返回数组行。SQL是在辅助函数不足以满足需求时,用于精确结构化连接和聚合的逃生舱;它不是默认的检索入口点。
?在编写非平凡SQL之前,阅读。它是原始SQL字段/连接的快速参考。可执行DDL归CLI所有,不会在此仅文档化的技能中重复。常见的安全连接:
references/schema.md- 没有时间戳。连接
tool_calls。messages m ON m.uuid = tc.message_uuid - 没有时间戳。连接
tool_results。messages m ON m.uuid = tr.message_uuid - 对于项目/会话过滤器,连接。
sessions s ON s.id = <table>.session_id - 优先在SQL端使用、
GROUP BY、COUNT、MAX和ORDER BY,而非在最终答案中手动计数。LIMIT
表:、、、、、、、、、。
sessionsmessagestool_callstool_resultssummariesmemoriessubagentsworkflowsworkflow_agentsmessages_ftsStructured Helpers
结构化辅助函数
These helpers are convenience accessors over the same SQLite structure. They do
not replace , but they are the default first-pass surface. Use
when you need an exact aggregation or a join the helper does not expose.
sql()sql()All list helpers accept a bounded . Many also accept:
. Check
or a tiny sample before relying on less common
filters or return fields.
limit{ project, after, before, sessionId, sessions, branch, source }references/api-reference.md- -- compact orientation map. Returns current cwd/project if knowable, the invoking session id (
overview(opts?)) when the invocation nonce resolved, global project/source counts, and current-project recent sessions plus memory records. It is a map, not evidence.current.session_id - -- session rows, newest first.
sessions(opts?)is a SQLprojectpattern.LIKEcounts the visible canonical transcript; inactive and hidden records are excluded. The invoking session row carriesmessage_count.is_invoking: true - -- shorthand for recent sessions.
recent(n?) - -- summary rows, newest first:
summaries(opts?); inactive rows require{ id, session_id, timestamp, source, content, visibility, session_title, project }, hidden rows are never returned, andincludeInactive: trueis the summary kind rather than the transcript provider.source - -- subagent metadata plus
subagents(opts?).messageCount - -- workflow runs, newest first.
workflows(opts?) - -- workflow row plus parsed
workflowTree(runId)andresult; may include bulkyagentsandscript, so project compact fields.result_json - -- Read/Edit/Write tool calls for a file, oldest first; includes many
fileHistory(filePath, opts?)rows and labels each result withRead.visibility - -- failed tool results with tool/session context and
failures(opts?), newest first.visibility - -- parent chain from root to message.
trace(uuid, opts?) - -- session messages ordered by timestamp, omitting meta messages by default. Pass
thread(sessionId, opts?)for injected context or{ includeMeta: true }for superseded Pi history.{ includeInactive: true } - -- windowed source access for one visible message. Pi returns the selected source-message container whether it was stored directly or inside a retained tail. Inactive targets require
raw(uuid, opts?); hidden targets returnincludeInactive: true.null - -- recall memory layer. opts:
memories(opts?). Without{ query, project, sessionId, sessions, after, before, branch, limit }, returns active memory records newest first. Withquery, searchesquery/summarythrough safe FTS5 tokenization and returnspath; lower rank sorts earlier. Records may include nullable JSONrankfor explicit recall surfaces such as files. Read the file atanchorsfor full content.path
这些辅助函数是基于相同SQLite结构的便捷访问器。它们不会取代,但却是默认的首次查询入口。当需要辅助函数未暴露的精确聚合或连接时,使用。
sql()sql()所有列表辅助函数都接受有界的。许多还接受:
。在依赖不太常见的过滤器或返回字段之前,先查看或小型样本。
limit{ project, after, before, sessionId, sessions, branch, source }references/api-reference.md- -- 紧凑的定位图。返回当前可识别的cwd/项目,当调用随机数解析成功时返回调用会话ID(
overview(opts?)),全局项目/来源计数,以及当前项目的近期会话和记忆记录。它是一个导航图,而非证据。current.session_id - -- 会话行,按最新排序。
sessions(opts?)是SQLproject模式。LIKE计算可见的标准转录;排除非活跃和隐藏记录。调用会话行带有message_count。is_invoking: true - -- 近期会话的简写。
recent(n?) - -- 摘要行,按最新排序:
summaries(opts?);非活跃行需要{ id, session_id, timestamp, source, content, visibility, session_title, project },隐藏行永远不会返回,includeInactive: true是摘要类型而非转录提供商。source - -- 子代理元数据加上
subagents(opts?)。messageCount - -- 工作流运行记录,按最新排序。
workflows(opts?) - -- 工作流行加上解析后的
workflowTree(runId)和result;可能包含庞大的agents和script,因此需压缩字段。result_json - -- 文件的读取/编辑/写入工具调用记录,按最早排序;包含许多
fileHistory(filePath, opts?)行,并为每个结果标记Read。visibility - -- 带有工具/会话上下文和
failures(opts?)的失败工具结果,按最新排序。visibility - -- 从根到消息的父链。
trace(uuid, opts?) - -- 按时间戳排序的会话消息,默认省略元消息。传递
thread(sessionId, opts?)以获取注入的上下文,或传递{ includeMeta: true }以获取被取代的Pi历史记录。{ includeInactive: true } - -- 单条可见消息的窗口化源访问。Pi返回所选的源消息容器,无论它是直接存储还是保留在尾部。非活跃目标需要
raw(uuid, opts?);隐藏目标返回includeInactive: true。null - -- 召回内存层。选项:
memories(opts?)。不带{ query, project, sessionId, sessions, after, before, branch, limit }时,按最新排序返回活跃记忆记录。带query时,通过安全的FTS5分词搜索query/summary并返回path;排名越低越靠前。记录可能包含用于显式召回表面(如文件)的可空JSONrank。读取anchors处的文件以获取完整内容。path
Retrieval Contract
检索约定
Keep queries scoped, bounded, and structural.
- Scope First: classify the locator as scope, artifact, or semantic. Use the narrowest structural locator before FTS; empty scoped results are valid unless the user asks to broaden.
- Orient First: for a new task, normally call before deeper retrieval unless the user gave an exact session/message/file locator. It is a navigation map; confirm facts with
overview({ limit: 6 }),memories(), helpers, or, only when needed,search().sql() - Helper First: prefer ,
overview(),memories(),search(),sessions(),summaries(), and other helpers for first-pass retrieval. Escalate to rawfileHistory()only when helpers cannot express the needed join, grouping, or exact schema-level check.sql() - Plan Before Probe: for conclusion, broad history, failure investigation, or file evolution, write a bounded retrieval script instead of spending turns on intermediate results.
- Structure Before Text: compute counts, joins, grouping, dedupe, and projection in SQL or JS; keep runtime JSON compact, ideally under 10k-12k chars for synthesis tasks.
- Evidence Before Conclusion: return compact evidence with stable IDs (,
session_id,uuid,tool_call_id,run_id) and short snippets, then synthesize in the final answer.agent_id - Exclude Meta By Default: rows are injected/control-plane transcript material. Helpers hide them by default; raw SQL for ordinary conversation evidence should include
is_meta=1unless meta rows are the investigation target.COALESCE(m.is_meta,0)=0 - Exclude Superseded Paths By Default: ordinary evidence must use exact visible-only filtering. Opt into inactive Pi history only to explain an abandoned path, and label it as tried then superseded.
- Persist Durable Conclusions: after answering, if retrieval produced a durable conclusion that future sessions are likely to reuse and does not already cover it, explicitly offer to write a memory. Keep the offer brief. Do not write the markdown file or run
memories()until the user approves.--attune
If field, context, ordering, FTS, or helper semantics affect the query, read
before coding. If a query errors, read
before retrying.
references/retrieval-semantics.mdreferences/pitfalls.md保持查询范围明确、有界且结构化。
- 先限定范围:将定位符分类为范围、工件或语义。在使用FTS之前使用最窄的结构化定位符;空的范围结果是有效的,除非用户要求扩大范围。
- 先定位:对于新任务,除非用户提供了确切的会话/消息/文件定位符,否则通常在深度检索前调用。它是一个导航图;使用
overview({ limit: 6 })、memories()、辅助函数,或仅在必要时使用search()来确认事实。sql() - 优先使用辅助函数:首次检索优先使用、
overview()、memories()、search()、sessions()、summaries()和其他辅助函数。仅当辅助函数无法表达所需的连接、分组或精确架构级检查时,才升级到原始fileHistory()。sql() - 先规划再探测:对于结论、广泛历史、失败调查或文件演变,编写有界的检索脚本,而非在中间结果上花费轮次。
- 先结构化再文本化:在SQL或JS中计算计数、连接、分组、去重和投影;保持运行时JSON紧凑,理想情况下合成任务的JSON应在10k-12k字符以内。
- 先证据再结论:返回带有稳定ID(、
session_id、uuid、tool_call_id、run_id)和简短片段的紧凑证据,然后在最终答案中进行合成。agent_id - 默认排除元数据:行是注入的/控制平面转录材料。辅助函数默认隐藏它们;用于普通对话证据的原始SQL应包含
is_meta=1,除非元行是调查目标。COALESCE(m.is_meta,0)=0 - 默认排除被取代的路径:普通证据必须使用精确的仅可见过滤。仅在解释废弃路径时才选择非活跃Pi历史,并将其标记为已尝试但后来被取代。
- 留存持久结论:回答后,如果检索产生了未来会话可能重用的持久结论,且未涵盖该结论,则明确提出写入记忆的建议。建议要简短。在用户批准前,不要编写markdown文件或运行
memories()。--attune
如果字段、上下文、排序、FTS或辅助函数语义影响查询,在编码前阅读。如果查询出错,在重试前阅读。
references/retrieval-semantics.mdreferences/pitfalls.mdMemory Layer
内存层
Obelisk has a persistent memory layer alongside raw session data. Every
retrieval queries both layers: for prior conclusions,
and helpers for raw session evidence. Use memory as prior notes, not final
authority. If a memory record influences your answer, say naturally that it was
previously recorded, and compare it with raw session evidence when correctness
depends on it. Raw session data is the evidence layer, but one hit is not a
complete truth; query and cite it compactly.
memories()search()The memory layer is English-indexed. Use English terms in
even when the user asks in another language. Write every
in English, regardless of the current conversation language. The runtime rejects
obvious CJK text in memory queries and summaries as a guardrail.
memories({ query })remember().summaryRecall: query
to find prior conclusions relevant to the current task. Translate non-English
user requests into concise English query terms before calling .
Memory recall uses safe FTS5 tokenization over and , so
hyphens/punctuation are tokenized instead of causing raw syntax errors.
Like other list helpers, passing a string is treated as , and passing
a number is treated as . Read the file at for full content.
returns active memories only. An archived memory is
management/audit data, not recall data.
memories({ query: 'English topic terms', project: '...' })memories()summarypathMATCHsessionIdlimitpathmemories()Good memory candidates include design decisions, project conventions, abandoned
alternatives, repeated failure causes, workflow patterns, and conclusions
synthesized across multiple raw evidence points. Do not propose memory for
one-off lookups, uncertain findings, or conclusions already covered by existing
memories.
Mutation approvals: judging whether to use a memory in the current answer is
an agent decision and does not require approval. Persistent memory changes do.
If the user explicitly says a memory is wrong, outdated, should be forgotten, or
should now say something else, that request is the approval to archive or update
the exact matching memory. Do not ask for a second confirmation unless multiple
memories could match. If you notice a possible conflict yourself, explain it
briefly and ask before changing memory state.
Writing memories: after a retrieval produces a conclusion worth persisting,
propose writing a memory file. The user must approve. Flow:
- Write a markdown file using the tool (user approves).
Write - Register it via in a narrow memory-registration script:
remember()
js
return remember({
path: '.obelisk/memories/design-decision-x.md',
session_id: 'current-session-id',
message_start: 'uuid-of-first-relevant-msg',
message_end: 'uuid-of-last-relevant-msg',
anchors: [{ kind: 'file', path: 'src/path/to/file.ts' }],
summary: 'Detailed summary: what was decided, why, what alternatives were considered, and what constraints drove the choice.'
})Run the registration script with:
bash
obelisk --attune /tmp/register-memory.mjs--attuneremember()forget()search()sql()memories()--queryremember()pathproject_pathsession_id.obelisk/memories/...session_idanchorssummarymemories()The / range marks where in the conversation this
conclusion was drawn. Use it later to trace back to the original evidence.
message_startmessage_endForgetting memories: if the user says a memory is outdated, wrong, or should
be forgotten, use normal recall first to identify the exact memory ID. If there
is exactly one clear candidate, the user's request is approval to archive it. If
multiple memories could match, ask which one to forget. Then run an
script:
--attunejs
return forget({
id: 'mem-id-to-delete',
reason: 'Outdated by newer project guidance.',
});forget()deleted_atdeleted_reasonUpdating memories: updating memory is one user-approved operation:
archive the old memory with , then write and register a replacement
markdown memory with . If the user explicitly corrected the memory,
that correction is approval for the combined archive-plus-write flow. If you
discovered the mismatch yourself, ask first.
forget()remember()Obelisk在原始会话数据之外还有一个持久内存层。每次检索都会查询这两个层:用于先前的结论,和辅助函数用于原始会话证据。将内存视为先前的笔记,而非最终权威。如果记忆记录影响你的答案,自然地说明它是先前记录的,并在正确性依赖于它时与原始会话证据进行比较。原始会话数据是证据层,但单次命中并非完整事实;要紧凑地查询并引用它。
memories()search()内存层是英文索引的。即使用户用其他语言提问,在中也要使用英文术语。无论当前对话语言如何,每个都要用英文编写。运行时会拒绝记忆查询和摘要中的明显CJK文本作为防护措施。
memories({ query })remember().summary召回: 查询以找到与当前任务相关的先前结论。在调用之前,将非英语用户请求翻译成简洁的英文查询术语。记忆召回通过安全的FTS5分词对和进行搜索,因此连字符/标点会被分词,而非导致原始语法错误。与其他列表辅助函数一样,传递字符串会被视为,传递数字会被视为。读取处的文件以获取完整内容。仅返回活跃记忆。归档记忆是管理/审计数据,而非召回数据。
memories({ query: 'English topic terms', project: '...' })memories()summarypathMATCHsessionIdlimitpathmemories()良好的记忆候选包括设计决策、项目约定、废弃的替代方案、重复失败的原因、工作流模式,以及跨多个原始证据点合成的结论。不要为一次性查找、不确定的发现或已被现有记忆涵盖的结论提议写入记忆。
变更批准: 判断是否在当前答案中使用记忆是代理的决策,无需批准。持久内存变更需要批准。如果用户明确表示记忆错误、过时、应被遗忘或应更新内容,该请求即为归档或更新确切匹配记忆的批准。除非多个记忆可能匹配,否则无需再次确认。如果你自己发现可能的冲突,简要解释并在更改记忆状态前询问。
写入记忆: 检索产生值得留存的结论后,提议写入记忆文件。必须获得用户批准。流程:
- 使用工具编写markdown文件(用户批准)。
Write - 在窄范围的记忆注册脚本中通过注册:
remember()
js
return remember({
path: '.obelisk/memories/design-decision-x.md',
session_id: 'current-session-id',
message_start: 'uuid-of-first-relevant-msg',
message_end: 'uuid-of-last-relevant-msg',
anchors: [{ kind: 'file', path: 'src/path/to/file.ts' }],
summary: '详细摘要:做出了什么决策,原因是什么,考虑了哪些替代方案,以及哪些约束驱动了选择。'
})使用以下命令运行注册脚本:
bash
obelisk --attune /tmp/register-memory.mjs--attuneremember()forget()search()sql()memories()--queryremember()pathsession_idproject_path.obelisk/memories/...session_idanchorssummarymemories()message_startmessage_end遗忘记忆: 如果用户表示记忆过时、错误或应被遗忘,先使用普通召回找到确切的记忆ID。如果只有一个明确的候选,用户的请求即为归档它的批准。如果多个记忆可能匹配,询问要遗忘哪一个。然后运行脚本:
--attunejs
return forget({
id: 'mem-id-to-delete',
reason: '被更新的项目指南取代。',
});forget()deleted_atdeleted_reason更新记忆: 更新记忆是一个需要用户批准的操作:使用归档旧记忆,然后编写并注册新的markdown记忆文件。如果用户明确更正了记忆,该更正即为归档加写入组合流程的批准。如果你自己发现了不匹配,先询问。
forget()Minimal Patterns
最小模式
Search, then expand one promising hit:
js
const hits = search('auth fix', { limit: 5 });
if (!hits.length) return [];
return hits.slice(0, 3).map(h => ({
session_id: h.session.id,
session_title: h.session.title,
uuid: h.message.uuid,
snippet: h.message.text?.slice(0, 240),
}));Check helper fields before assuming names:
js
const rows = summaries({ project: '%quiet-zero%', limit: 1 });
return rows.length ? Object.keys(rows[0]) : [];Fetch message neighbors without a full thread:
js
const hit = search('runtime query', { limit: 1 })[0];
return sql(
`SELECT uuid, role, timestamp, substr(text,1,240) AS snippet
FROM messages
WHERE session_id=? AND timestamp>=?
AND COALESCE(visibility, 'visible') = 'visible'
ORDER BY timestamp LIMIT 6`,
hit.session.id,
hit.message.timestamp
);See for longer recipes.
references/query-patterns.md搜索,然后扩展一个有希望的命中结果:
js
const hits = search('auth fix', { limit: 5 });
if (!hits.length) return [];
return hits.slice(0, 3).map(h => ({
session_id: h.session.id,
session_title: h.session.title,
uuid: h.message.uuid,
snippet: h.message.text?.slice(0, 240),
}));在假设字段名之前先检查辅助函数字段:
js
const rows = summaries({ project: '%quiet-zero%', limit: 1 });
return rows.length ? Object.keys(rows[0]) : [];无需完整线程即可获取消息邻居:
js
const hit = search('runtime query', { limit: 1 })[0];
return sql(
`SELECT uuid, role, timestamp, substr(text,1,240) AS snippet
FROM messages
WHERE session_id=? AND timestamp>=?
AND COALESCE(visibility, 'visible') = 'visible'
ORDER BY timestamp LIMIT 6`,
hit.session.id,
hit.message.timestamp
);更长的示例请参见。
references/query-patterns.mdNotes
注意事项
- First run builds the index. Later runs update incrementally.
- DB location: ; old
~/.obelisk/obelisk.sqliteis copied forward if needed.~/.claude/obelisk.sqlite - Query scripts run in a sandboxed VM with no filesystem or network access from inside the script.
- Indexed text and stored tool inputs/results are truncated to 10k chars. Use for specific JSONL windows.
raw(uuid, { offset, limit })
- 首次运行会构建索引。后续运行会增量更新。
- 数据库位置:;如果需要,旧的
~/.obelisk/obelisk.sqlite会被复制过来。~/.claude/obelisk.sqlite - 查询脚本在沙箱VM中运行,脚本内部无法访问文件系统或网络。
- 索引文本和存储的工具输入/结果会被截断为10k字符。使用获取特定的JSONL窗口。
raw(uuid, { offset, limit })