feat(cli): extract Obelisk runtime into npm package
Add @obelisk-apps/cli with the existing build, search, query, and attune contract plus official skill installation. Separate the docs-only skill artifact, bootstrap installer, release layout, cross-platform CI, and package-level regression coverage.
This commit is contained in:
@@ -0,0 +1,469 @@
|
||||
# Obelisk -- Helper API Reference
|
||||
|
||||
Detailed reference for globals available inside `obelisk --query` and
|
||||
`obelisk --attune` scripts.
|
||||
|
||||
- Use `references/schema.md` for raw SQL table/field/join checks.
|
||||
- Use `references/query-patterns.md` for copyable retrieval plans.
|
||||
- Use `references/retrieval-semantics.md` for query design and scope choices.
|
||||
- Use `references/pitfalls.md` after runtime errors or confusing row shapes.
|
||||
|
||||
Query scripts run inside an async IIFE with a 30-second timeout. Use `return` to
|
||||
emit JSON. `--query` scripts are read-only. `--attune` scripts expose only
|
||||
memory mutation helpers.
|
||||
|
||||
## Query API Reference
|
||||
|
||||
### Read Helpers
|
||||
|
||||
These globals are available only in `obelisk --query` scripts:
|
||||
|
||||
```js
|
||||
sql, search, context, trace, thread, raw,
|
||||
overview, sessions, recent, summaries, memories,
|
||||
subagents, workflows, workflowTree, fileHistory, failures
|
||||
```
|
||||
|
||||
All list helpers accept bounded `limit` options. Many helpers also accept
|
||||
`project`, `sessionId`, `sessions`, `after`, `before`, `branch`, and `source`
|
||||
when the underlying table can express that scope. Passing a string to many list
|
||||
helpers is treated as `sessionId`; passing a number is treated as `limit`.
|
||||
|
||||
### Mutation Helpers
|
||||
|
||||
These globals are available only in `obelisk --attune` scripts:
|
||||
|
||||
```js
|
||||
remember, forget
|
||||
```
|
||||
|
||||
`--attune` does not expose `search()`, `sql()`, `memories()`, or other read
|
||||
helpers. If you need IDs, discover them first with a normal `--query` script.
|
||||
|
||||
---
|
||||
|
||||
## Core Helpers
|
||||
|
||||
#### `search(text, opts?)`
|
||||
|
||||
Full-text search across all indexed message text using FTS5.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `text` | `string` | FTS5 query string |
|
||||
| `opts.limit` | `number` | Max results, default 20 |
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over `sessions.project` |
|
||||
| `opts.after` | `string` | ISO lower bound on message timestamp |
|
||||
| `opts.before` | `string` | ISO upper bound on message timestamp |
|
||||
| `opts.cwd` | `string` | SQL `LIKE` filter over `messages.cwd` |
|
||||
| `opts.source` | `string` | `"claude"`, `"codex"`, or omitted/all |
|
||||
| `opts.includeMeta` | `boolean` | Include `is_meta=1` rows, default false |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<{
|
||||
message: { uuid, text, content_type, is_meta, role, timestamp, model, cwd, source },
|
||||
session: { id, title, project, started_at, source },
|
||||
rank,
|
||||
context
|
||||
}>
|
||||
```
|
||||
|
||||
`context` is temporal neighbor context in the same session, not a parent chain.
|
||||
Use `context(uuid)` or `trace(uuid)` for causal/parent-chain expansion. Lower
|
||||
FTS rank sorts earlier; prefer returned order unless deliberately inspecting
|
||||
FTS ranking.
|
||||
|
||||
Valid FTS5 syntax in `text` is honored. Input that FTS5 would reject as
|
||||
malformed (for example a hyphenated term like `foo-bar`) does not error: it
|
||||
falls back to safe per-token quoting — the same tokenization `memories()` uses —
|
||||
so ordinary text never crashes the query.
|
||||
|
||||
#### `context(uuid)`
|
||||
|
||||
Full indexed context around one message.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | `string` | Message UUID |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ message, parentChain, session, subagent, workflow } | null
|
||||
```
|
||||
|
||||
`parentChain` contains ancestors, not temporal neighbors. If the message belongs
|
||||
to a subagent or workflow agent, `subagent` or `workflow` is populated when the
|
||||
metadata exists.
|
||||
|
||||
#### `sql(query, ...params)`
|
||||
|
||||
Read-only SQL helper with positional `?` bindings.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `query` | `string` | `SELECT` or `WITH` statement |
|
||||
| `...params` | `any` | Bind values |
|
||||
|
||||
Returns `Array<object>`.
|
||||
|
||||
Write statements are rejected. Use `references/schema.md` before non-trivial SQL
|
||||
joins, and use `--attune` with `remember()` / `forget()` for memory mutation.
|
||||
|
||||
---
|
||||
|
||||
## Orientation And Lists
|
||||
|
||||
#### `overview(opts?)`
|
||||
|
||||
Compact orientation map for choosing retrieval scope. It is not evidence: it
|
||||
does not return snippets, full messages, or markdown memory contents.
|
||||
|
||||
Passing a string is treated as `project`. Passing a number is treated as
|
||||
`limit`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.project` | `string` | Project slug or SQL `LIKE` pattern to use as current scope |
|
||||
| `opts.limit` | `number` | Max recent sessions in `current_project.sessions`, default 8 |
|
||||
| `opts.projectLimit` | `number` | Max global project rows, default 20 |
|
||||
| `opts.memoryLimit` | `number` | Max memories in `current_project.memories`, default 100 |
|
||||
|
||||
If `opts.project` is absent, `overview()` tries to identify the current project
|
||||
from `process.cwd()` against `sessions.project_path`, then from exact
|
||||
`messages.cwd` matches. It does not guess the current session.
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{
|
||||
current: {
|
||||
cwd,
|
||||
project: {
|
||||
project,
|
||||
project_path,
|
||||
source: 'opts' | 'cwd_project_path' | 'cwd_messages',
|
||||
confidence: 'exact' | 'inferred' | 'unknown'
|
||||
} | null
|
||||
},
|
||||
current_project: {
|
||||
project,
|
||||
project_path,
|
||||
session_total,
|
||||
sessions: [
|
||||
{ id, title, project, project_path, started_at, ended_at, git_branch, message_count, source }
|
||||
],
|
||||
memory_total,
|
||||
memories: [
|
||||
{ id, path, anchors, summary, session_id, project, created_at }
|
||||
]
|
||||
} | null,
|
||||
projects: [
|
||||
{
|
||||
project,
|
||||
project_path,
|
||||
session_count,
|
||||
memory_count,
|
||||
last_session_at,
|
||||
last_memory_at,
|
||||
recent_branches
|
||||
}
|
||||
],
|
||||
totals: {
|
||||
projects,
|
||||
sessions,
|
||||
memories,
|
||||
sources: [{ source: 'claude' | 'codex', session_count, last_session_at }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Confirm facts with `memories()`, `search()`, other helpers, or `sql()`.
|
||||
|
||||
#### `sessions(opts?)`
|
||||
|
||||
Session rows ordered by `ended_at` descending. Passing a number is treated as
|
||||
`limit`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over `sessions.project` |
|
||||
| `opts.after` | `string` | ISO lower bound on `started_at` |
|
||||
| `opts.before` | `string` | ISO upper bound on `started_at` |
|
||||
| `opts.limit` | `number` | Max rows, default 50 |
|
||||
| `opts.branch` | `string` | Exact git branch |
|
||||
| `opts.source` | `string` | `"claude"`, `"codex"`, or omitted/all |
|
||||
| `opts.sessionId` | `string` | Exact session ID |
|
||||
| `opts.sessions` | `string[]` | Restrict to session IDs |
|
||||
|
||||
Returns `Array<session_row>`.
|
||||
|
||||
#### `recent(n?)`
|
||||
|
||||
Shorthand for `sessions({ limit: n })`. Default `n` is 10.
|
||||
|
||||
Returns `Array<session_row>`.
|
||||
|
||||
#### `summaries(opts?)`
|
||||
|
||||
Session summary rows ordered by summary `timestamp` descending. Passing a string
|
||||
is treated as `sessionId`; passing a number is treated as `limit`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.sessions` | `string[]` | Restrict to session IDs |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over source session project |
|
||||
| `opts.after` | `string` | ISO lower bound on summary timestamp |
|
||||
| `opts.before` | `string` | ISO upper bound on summary timestamp |
|
||||
| `opts.branch` | `string` | Exact source session branch |
|
||||
| `opts.source` | `string` | Provider filter through joined session |
|
||||
| `opts.limit` | `number` | Max rows, default 100 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<summary_row & { session_title, project }>
|
||||
```
|
||||
|
||||
`summaries.source` is the summary kind, such as `away_summary`; it is not the
|
||||
provider source.
|
||||
|
||||
#### `memories(opts?)`
|
||||
|
||||
Active registered markdown memory records. Passing a string is treated as
|
||||
`sessionId`; passing a number is treated as `limit`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.query` | `string` | English recall query over `summary` and `path` |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over `memories.project` |
|
||||
| `opts.sessionId` | `string` | Restrict to one source session |
|
||||
| `opts.sessions` | `string[]` | Restrict to source session IDs |
|
||||
| `opts.after` | `string` | ISO lower bound on `created_at` |
|
||||
| `opts.before` | `string` | ISO upper bound on `created_at` |
|
||||
| `opts.branch` | `string` | Exact source session branch |
|
||||
| `opts.source` | `string` | Provider filter through the source session |
|
||||
| `opts.limit` | `number` | Max rows, default 50 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<memory_row & { rank?: number }>
|
||||
```
|
||||
|
||||
Archived memories are omitted. Without `query`, rows are newest first. With
|
||||
`query`, rows are ordered by safe FTS rank first, then `created_at` descending.
|
||||
Lower rank sorts earlier. Translate non-English requests into concise English
|
||||
query terms before calling `memories()`. Read the markdown file at `path` for
|
||||
full content.
|
||||
|
||||
---
|
||||
|
||||
## Structural Expansion Helpers
|
||||
|
||||
#### `trace(uuid)`
|
||||
|
||||
Walk the `parent_uuid` chain from a message to the conversation root.
|
||||
|
||||
Returns `Array<message>` ordered root-first.
|
||||
|
||||
#### `thread(sessionId, opts?)`
|
||||
|
||||
Messages in a session ordered by timestamp.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `sessionId` | `string` | Session ID |
|
||||
| `opts.includeMeta` | `boolean` | Include injected/control-plane rows, default false |
|
||||
|
||||
Returns `Array<message>`. Use `thread()` as a last resort; prefer targeted
|
||||
search/context or compact SQL projections.
|
||||
|
||||
#### `raw(uuid, opts?)`
|
||||
|
||||
Windowed access to the original JSONL line for one indexed message. Use this
|
||||
when indexed text, tool inputs, or tool results were truncated and you need the
|
||||
raw source.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | `string` | Message UUID |
|
||||
| `opts.offset` | `number` | Character offset into the JSONL line, default 0 |
|
||||
| `opts.limit` | `number` | Max characters, default 10000 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ text, totalLength, offset, limit, hasMore } | null
|
||||
```
|
||||
|
||||
`raw()` resolves main-session, subagent, workflow-agent, and Codex JSONL paths
|
||||
from indexed metadata.
|
||||
|
||||
---
|
||||
|
||||
## Agent And Workflow Helpers
|
||||
|
||||
#### `subagents(opts?)`
|
||||
|
||||
Subagent metadata plus message counts. Passing a string is treated as
|
||||
`sessionId`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over source session project |
|
||||
| `opts.source` | `string` | Provider filter |
|
||||
| `opts.limit` | `number` | Max rows, default 100 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<{ ...subagent_row, messageCount }>
|
||||
```
|
||||
|
||||
#### `workflows(opts?)`
|
||||
|
||||
Workflow run rows ordered newest first. Passing a string is treated as
|
||||
`sessionId`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over source session project |
|
||||
| `opts.after` | `string` | ISO lower bound on workflow timestamp |
|
||||
| `opts.before` | `string` | ISO upper bound on workflow timestamp |
|
||||
| `opts.source` | `string` | Provider filter |
|
||||
| `opts.limit` | `number` | Max rows, default 100 |
|
||||
|
||||
Returns `Array<workflow_row>`.
|
||||
|
||||
#### `workflowTree(runId)`
|
||||
|
||||
Lightweight execution tree for one workflow run. It parses `result_json` and
|
||||
adds per-agent message counts. It does not load agent messages.
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ ...workflow_row, result: object | null, agents: Array<{ ...workflow_agent_row, messageCount }> } | null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Evidence Helpers
|
||||
|
||||
#### `fileHistory(filePath, opts?)`
|
||||
|
||||
Tool calls that touched one file, ordered oldest first. Includes `Read` rows as
|
||||
well as `Edit`/`Write`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `filePath` | `string` | Absolute file path |
|
||||
| `opts.after` | `string` | ISO lower bound |
|
||||
| `opts.before` | `string` | ISO upper bound |
|
||||
| `opts.source` | `string` | Provider filter |
|
||||
| `opts.limit` | `number` | Max rows, default 200 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<{
|
||||
toolCall: { id, message_uuid, name, input_json },
|
||||
session: { id, title, project },
|
||||
timestamp
|
||||
}>
|
||||
```
|
||||
|
||||
Use raw SQL with `ORDER BY m.timestamp DESC` when you need newest-first file
|
||||
history.
|
||||
|
||||
#### `failures(opts?)`
|
||||
|
||||
Failed tool results with tool/session context and the next three messages after
|
||||
the failure. Passing a string is treated as `sessionId`.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `opts.sessionId` | `string` | Restrict to one session |
|
||||
| `opts.project` | `string` | SQL `LIKE` pattern over source session project |
|
||||
| `opts.after` | `string` | ISO lower bound on result message timestamp |
|
||||
| `opts.before` | `string` | ISO upper bound on result message timestamp |
|
||||
| `opts.source` | `string` | Provider filter |
|
||||
| `opts.limit` | `number` | Max rows, default 50 |
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
Array<{ toolCall, result, session, nextMessages }>
|
||||
```
|
||||
|
||||
Use SQL for precise counts and grouping; treat `failures()` as compact evidence,
|
||||
not a counting primitive.
|
||||
|
||||
---
|
||||
|
||||
## Memory Mutation Helpers
|
||||
|
||||
#### `remember(record)`
|
||||
|
||||
Register a human-approved markdown memory file. Available only in
|
||||
`obelisk --attune` scripts.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `record.path` | `string` | Existing markdown file path |
|
||||
| `record.summary` | `string` | Required English retrieval summary |
|
||||
| `record.session_id` | `string` | Source session ID, if known |
|
||||
| `record.message_start` | `string` | First relevant source message UUID |
|
||||
| `record.message_end` | `string` | Last relevant source message UUID |
|
||||
| `record.project` | `string` | Project slug override |
|
||||
| `record.anchors` | `array` or JSON `string` | Optional recall anchors |
|
||||
|
||||
Relative paths resolve against the source session `project_path` when
|
||||
`session_id` is provided, otherwise against the runtime cwd. `remember()`
|
||||
validates that `path` exists and is a regular file, rejects obvious CJK text in
|
||||
`summary`, stores the normalized absolute path, and accepts nullable `anchors`.
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ id, path, project, anchors, created_at }
|
||||
```
|
||||
|
||||
#### `forget(record)`
|
||||
|
||||
Archive a human-approved memory record. Available only in
|
||||
`obelisk --attune` scripts.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `record.id` | `string` | Exact memory ID |
|
||||
| `record.reason` | `string` | Required archive reason |
|
||||
|
||||
`forget()` sets `deleted_at` and `deleted_reason`. It does not delete the
|
||||
markdown file at `path`. Active recall helpers omit archived rows.
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ id, deleted_at, deleted_reason } |
|
||||
{ id, deleted_at, deleted_reason, already_deleted: true }
|
||||
```
|
||||
|
||||
### Memory Mutation Approval
|
||||
|
||||
Agents may decide whether to use, ignore, or verify memory in a single answer
|
||||
without approval. Approval is required only for persistent memory mutations.
|
||||
|
||||
When the user explicitly says a memory is wrong, outdated, should be forgotten,
|
||||
or should say something else, that utterance is approval to mutate the exact
|
||||
matching memory. If multiple memories could match, ask the user to choose.
|
||||
|
||||
Updating is not in-place: archive the old record with `forget()`, then write and
|
||||
register a replacement markdown file with `remember()` under the same approval.
|
||||
Reference in New Issue
Block a user