docs(readme): rewrite for dual-surface product (skill + app) and workspace structure
Rewrite README to reflect the current state of the project: - Describe both surfaces: skill (agent-first retrieval) and app (human browser). - Add Codex support section (unified schema, source tagging, child-thread mapping). - Update Structure tree to match the packages/core workspace layout with all TypeScript modules (providers, persist, tx, write-coordinator, writer-lease). - Document generated build outputs (packages/core/dist, dist/obelisk-skill). - License badge corrected to AGPL-3.0 (skill artifact is MIT; source is AGPL). - Skill invocation examples updated to /obelisk-skill. - Add recap flow documentation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8af0f9a31d
commit
410b0a8df3
@@ -7,186 +7,185 @@
|
|||||||
|
|
||||||
[](https://github.com/tommy0103/obelisk/stargazers)
|
[](https://github.com/tommy0103/obelisk/stargazers)
|
||||||
[](https://github.com/tommy0103/obelisk/releases)
|
[](https://github.com/tommy0103/obelisk/releases)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
|
|
||||||
Every past session, subagent, and workflow -- queryable by your agent.
|
Every past Claude Code and Codex session -- queryable by your agent, browsable by you.
|
||||||
|
|
||||||
**Humans should not browse session history. Agents should query it.**
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
## Two sides of the same index
|
||||||
|
|
||||||
|
Obelisk has two sides that share one SQLite index:
|
||||||
|
|
||||||
|
**Skill side** — an agent skill that lets coding agents search and query their own session history. The agent writes JS queries, runs them locally, answers in plain language.
|
||||||
|
|
||||||
|
**App side** — an Electron desktop app for humans to browse sessions, manage memories, view usage stats, and see weekly recap cards.
|
||||||
|
|
||||||
|
Both read from the same `~/.obelisk/obelisk.sqlite` database. The indexer reads Claude Code transcripts from `~/.claude/projects` and Codex transcripts from `~/.codex/sessions`.
|
||||||
|
|
||||||
|
## Codex support
|
||||||
|
|
||||||
|
Obelisk indexes Claude Code and Codex into the same SQLite schema instead of keeping separate databases. Rows carry a `source` value (`claude` or `codex`), and Codex IDs are prefixed with `codex:` so they cannot collide with Claude session IDs.
|
||||||
|
|
||||||
|
Codex root threads become normal Obelisk sessions. Codex child threads are attached through the same `subagents` table when parent-thread metadata is available. Codex does not emit Claude-style workflow metadata, so workflow tables may be empty for Codex-only history.
|
||||||
|
|
||||||
|
For live app refresh, Obelisk watches `~/.claude/projects` and `~/.codex/sessions`. It does not watch the whole `~/.codex` root. Codex's `session_index.jsonl` is used as lightweight title/update metadata during indexing, not as the message transcript source.
|
||||||
|
|
||||||
|
## Skill: agent-first retrieval
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src=".github/assets/demo.png" alt="Obelisk in action" width="540">
|
<img src=".github/assets/demo.png" alt="Obelisk App" width="720">
|
||||||
<br />
|
|
||||||
<p>Ask in plain language. The agent writes the query, runs it, answers.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Not a session browser
|
You can use obelisk like:
|
||||||
|
|
||||||
Most history tools help humans find old chats.
|
|
||||||
|
|
||||||
Obelisk is built for agents. It exposes past work as structured data: sessions,
|
|
||||||
messages, tool calls, subagents, workflows, file history, failures, parent
|
|
||||||
chains, and human-approved markdown memories. The agent writes the query, runs
|
|
||||||
it locally, and answers in plain language.
|
|
||||||
|
|
||||||
You don't manage history. You ask questions about past work.
|
|
||||||
|
|
||||||
## Why Obelisk
|
|
||||||
|
|
||||||
| Session library | Obelisk |
|
|
||||||
|---|---|
|
|
||||||
| Find an old chat | Answer a question about past work |
|
|
||||||
| Human browses snippets | Agent writes and runs a query |
|
|
||||||
| Search result list | Structured context and reasoning |
|
|
||||||
| Sessions as documents | Sessions as queryable memory |
|
|
||||||
| Good for recall | Good for investigation |
|
|
||||||
|
|
||||||
## What you can ask
|
|
||||||
|
|
||||||
```
|
```
|
||||||
/obelisk 上次 auth bug 最后到底改了哪些文件,为什么这么改
|
/obelisk-skill 上次 auth bug 最后到底改了哪些文件,为什么这么改
|
||||||
/obelisk 这个文件最近在哪些 sessions 里被反复修改
|
/obelisk-skill 这个文件最近在哪些 sessions 里被反复修改
|
||||||
/obelisk 找出最近失败的 tool calls,它们分别发生在哪些任务里
|
/obelisk-skill 找出最近失败的 tool calls,它们分别发生在哪些任务里
|
||||||
/obelisk 那个 review workflow 的 subagents 各自结论是什么
|
/obelisk-skill 那个 review workflow 的 subagents 各自结论是什么
|
||||||
/obelisk 我之前有没有试过这个方案,结果为什么放弃了
|
/obelisk-skill recap this week
|
||||||
```
|
```
|
||||||
|
|
||||||
Anything Claude Code has done before -- sessions, tool calls, subagents, workflows -- becomes structured, queryable memory. Ask in your own words.
|
### Install
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx skills add tommy0103/obelisk-skill
|
npx skills add tommy0103/obelisk-skill
|
||||||
```
|
```
|
||||||
|
|
||||||
Or manually: copy `obelisk/` into your project's `.claude/skills/`.
|
Or manually: copy `obelisk-skill/` into your project's `.claude/skills/`
|
||||||
|
|
||||||
Then in any Claude Code session:
|
Then in any Claude Code session:
|
||||||
|
|
||||||
```
|
```
|
||||||
/obelisk <your question>
|
/obelisk-skill <your question>
|
||||||
```
|
```
|
||||||
|
|
||||||
First run builds the index (~5 seconds for 100 sessions). After that it rebuilds incrementally.
|
First run builds the index (~5 seconds for 100 sessions). After that it rebuilds incrementally.
|
||||||
|
|
||||||
### Requires
|
### How it works
|
||||||
|
|
||||||
- Node.js 22+ (uses built-in node:sqlite with FTS5)
|
|
||||||
- Claude Code with skills support.
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
```
|
```
|
||||||
You ask a question
|
You ask a question
|
||||||
↓
|
↓
|
||||||
Agent writes a JS query against the SQLite index
|
Agent writes a JS query against the SQLite index
|
||||||
↓
|
↓
|
||||||
Runs it via node runtime.mjs --query <script>
|
Runs it via node $SKILL_DIR/scripts/runtime.js --query <script>
|
||||||
↓
|
↓
|
||||||
Reads the JSON result, answers you in natural language
|
Reads the JSON result, answers in natural language
|
||||||
```
|
```
|
||||||
|
|
||||||
When a retrieval produces a memory worth keeping, the agent proposes a markdown
|
Core API: `search()`, `context()`, `sql()`, plus structured helpers (`sessions`, `memories`, `summaries`, `workflows`, `failures`, `fileHistory`, etc).
|
||||||
memory file. After user approval, it registers that file with the narrow
|
|
||||||
`runtime.mjs --attune <script>` runtime, which exposes only memory mutation
|
|
||||||
helpers such as `remember()` and `forget()`.
|
|
||||||
|
|
||||||
Memory is a synthesis cache, not a replacement for raw sessions. The agent can
|
### Memory layer
|
||||||
decide whether to use, ignore, or verify a memory during an answer. Persistent
|
|
||||||
changes still require human approval, but explicit corrections count: if you say
|
|
||||||
a memory is wrong, outdated, or should be replaced, the agent can archive or
|
|
||||||
update the exact matching record without a second confirmation.
|
|
||||||
|
|
||||||
**The core idea: don't make humans browse, tag, or organize sessions.**
|
When a retrieval produces a conclusion worth keeping, the agent proposes a markdown memory file. After user approval, it registers the file with `runtime.js --attune <script>`. Memories are recalled via `memories()` in future sessions — a synthesis cache, not a replacement for raw evidence.
|
||||||
Don't invent a rigid query DSL either.
|
|
||||||
|
|
||||||
Agents can write code. So Obelisk gives them a small local query runtime over
|
## App: A surface for human
|
||||||
your past work.
|
|
||||||
|
|
||||||
The agent starts from a small core API, then uses structured shortcuts and
|
A companion desktop app for browsing what the skill indexes.
|
||||||
references only when the question needs them:
|
|
||||||
|
|
||||||
**Core primitives** — the main CodeAct surface:
|
<div align="center">
|
||||||
|
<img src=".github/assets/app-screenshot.png" alt="Obelisk App" width="720">
|
||||||
|
</div>
|
||||||
|
|
||||||
- `search(text)` — FTS5 full-text search, returns matches with surrounding context plus message `content_type` and `is_meta`
|
- **Sessions** — browse all sessions with search, project filtering, readable tool calls (diffs, terminal output, file viewers)
|
||||||
- `context(uuid)` — full story around a message (parent chain, subagent/workflow metadata)
|
- **Memory** — list and detail views for registered memory files
|
||||||
- `sql(query, ...params)` — read-only SQL for structured queries
|
- **Activity** — GitHub-style heatmap, weekly/cumulative token charts
|
||||||
|
- **Recap** — shareable weekly/monthly recap cards with archetype theming
|
||||||
|
- **Settings** — data source configuration, auto-refresh, rebuild index
|
||||||
|
|
||||||
**Structured shortcuts** — overview, session, memory, summary, subagent,
|
macOS only. Download from [Releases](https://github.com/tommy0103/obelisk/releases).
|
||||||
workflow, file-history, failure, raw-window, and parent-chain helpers over the
|
|
||||||
same SQLite data.
|
|
||||||
|
|
||||||
**References** — agent reads on demand when the task needs deeper structure:
|
|
||||||
|
|
||||||
- `references/schema.md` — full SQLite schema and API reference
|
|
||||||
- `references/query-patterns.md` — copyable CodeAct recipes for common retrieval tasks
|
|
||||||
- `references/retrieval-semantics.md` — query design frame for scoped and synthesis retrieval
|
|
||||||
- `references/recap/overview.md` — optional `/obelisk recap` card-by-card entrypoint
|
|
||||||
- `references/recap/pattern1-cover.md` and `references/recap/writing1-cover.md`
|
|
||||||
- `references/recap/pattern2-thinking.md` and `references/recap/writing2-thinking.md`
|
|
||||||
- `references/recap/pattern3-vibe.md` and `references/recap/writing3-vibe.md`
|
|
||||||
- `references/recap/pattern4-workflow.md` and `references/recap/writing4-workflow.md`
|
|
||||||
- `references/recap/pattern5-closing.md` and `references/recap/writing5-closing.md`
|
|
||||||
- `references/pitfalls.md` — scope, FTS, ordering, compact/raw, and field-name traps
|
|
||||||
|
|
||||||
The executable SQLite schema lives in `scripts/schema.sql`; `references/schema.md`
|
|
||||||
is the human/agent explanation of that contract.
|
|
||||||
|
|
||||||
The design is progressive disclosure with guardrails: the main skill keeps the
|
|
||||||
core contract and high-risk pitfalls visible, while longer recipes and the full
|
|
||||||
schema stay out of the first prompt until the agent needs them.
|
|
||||||
The optional recap references are only for the explicit `/obelisk recap` intent;
|
|
||||||
they are not part of the ordinary retrieval path. `references/recap/overview.md`
|
|
||||||
drives a card-by-card loop: read one card's retrieval pattern, gather that
|
|
||||||
card's evidence, read its writing reference, update the JSON, then continue.
|
|
||||||
This keeps schema, taste, and query planning from competing in one large prompt.
|
|
||||||
|
|
||||||
## What gets indexed
|
## What gets indexed
|
||||||
|
|
||||||
| Layer | Source | What's captured |
|
| Layer | Source | What's captured |
|
||||||
|-------|--------|----------------|
|
|-------|--------|----------------|
|
||||||
| **Sessions** | `<project>/<sessionId>.jsonl` | Title, project, timestamps, git branch |
|
| **Sessions** | Claude `<project>/<sessionId>.jsonl`; Codex `sessions/YYYY/MM/DD/*.jsonl` | Title, project, timestamps, git branch, source |
|
||||||
| **Messages** | user + assistant turns | Full text, model, token usage, parent chain |
|
| **Messages** | user + assistant turns | Full text, model, token usage, parent chain |
|
||||||
| **Tool calls** | every tool invocation | Tool name, input, file paths touched |
|
| **Tool calls** | every tool invocation | Tool name, input, file paths |
|
||||||
| **Subagents** | `subagents/agent-<id>.jsonl` | Agent type, description, full conversation |
|
| **Subagents** | Claude `subagents/agent-<id>.jsonl`; Codex child threads | Agent type, description, full conversation |
|
||||||
| **Workflows** | `workflows/wf_<runId>.json` | Script, structured result, agent count |
|
| **Workflows** | Claude `workflows/wf_<runId>.json` | Script, result, agent count |
|
||||||
| **Workflow agents** | `subagents/workflows/wf_<runId>/` | Per-agent transcripts linked to workflow |
|
| **Workflow agents** | Claude `subagents/workflows/wf_<runId>/` | Per-agent transcripts |
|
||||||
| **Memories** | markdown files registered by the agent after user approval | Prior conclusions linked to source sessions/messages and optional anchors |
|
| **Memories** | registered markdown files | Conclusions linked to source sessions |
|
||||||
|
|
||||||
Full-text search via FTS5 covers message text across every session layer and ranked memory recall over registered memory summaries, while the SQLite tables preserve the structure agents need for investigation.
|
Full-text search via FTS5 covers all layers.
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.claude/skills/obelisk/
|
packages/core/ # @obelisk/core npm workspace (TypeScript + ESM)
|
||||||
├── SKILL.md # Skill definition + simple API + examples
|
├── src/
|
||||||
├── scripts/
|
│ ├── providers/
|
||||||
│ ├── schema.sql # Executable SQLite schema
|
│ │ ├── types.ts # Provider + IndexRecord contract
|
||||||
│ └── runtime.mjs # Indexer + query runtime (zero deps)
|
│ │ ├── claude.ts # Claude Code adapter (line-incremental)
|
||||||
└── references/
|
│ │ └── codex.ts # Codex adapter (full-reparse)
|
||||||
├── schema.md # Full table schema + advanced API reference
|
│ ├── persist.ts # Binding-agnostic record writer (upsert/merge)
|
||||||
├── query-patterns.md # Copyable retrieval recipes
|
│ ├── tx.ts # Write transaction + connection config
|
||||||
├── retrieval-semantics.md # Query design frame for retrieval semantics
|
│ ├── write-coordinator.ts # Bounded retry policy
|
||||||
├── recap-patterns.md # Compatibility pointer to references/recap/overview.md
|
│ ├── writer-lease.ts # Cross-process single-writer lease (SQLite lock DB)
|
||||||
├── recap-writing.md # Compatibility pointer to per-card recap writing docs
|
│ ├── core.ts # buildIndex / searchText / executeQuery / executeAttune
|
||||||
├── recap/
|
│ ├── indexer.ts # Skill orchestration (discover → persist → finalize)
|
||||||
│ ├── overview.md
|
│ ├── parsing.ts # Pure helpers (node:sqlite-free, app-consumable)
|
||||||
│ ├── pattern1-cover.md
|
│ ├── db.ts # node:sqlite lifecycle + migrations
|
||||||
│ ├── writing1-cover.md
|
│ ├── query.ts # Query/attune sandbox API (helpers)
|
||||||
│ ├── pattern2-thinking.md
|
│ ├── runtime.ts # Thin CLI shell (--build/--search/--query/--attune)
|
||||||
│ ├── writing2-thinking.md
|
│ └── schema.sql # SQLite schema (single source of truth)
|
||||||
│ ├── pattern3-vibe.md
|
├── package.json
|
||||||
│ ├── writing3-vibe.md
|
└── dist/ # Generated package JS, declarations, and schema
|
||||||
│ ├── pattern4-workflow.md
|
|
||||||
│ ├── writing4-workflow.md
|
references/ # Agent-readable docs (progressive disclosure)
|
||||||
│ ├── pattern5-closing.md
|
├── schema.md
|
||||||
│ └── writing5-closing.md
|
├── api-reference.md
|
||||||
└── pitfalls.md # Scope, FTS, ordering, and compactness traps
|
├── query-patterns.md
|
||||||
|
├── retrieval-semantics.md
|
||||||
|
├── pitfalls.md
|
||||||
|
├── recap-patterns.md
|
||||||
|
├── recap-writing.md
|
||||||
|
└── recap/ # Per-card pattern + writing references
|
||||||
|
├── overview.md
|
||||||
|
├── pattern1-cover.md … pattern5-closing.md
|
||||||
|
└── writing1-cover.md … writing5-closing.md
|
||||||
|
|
||||||
|
app/ # Electron desktop app (electron-vite + Vue)
|
||||||
|
├── src/main/ # TypeScript main process (consumes shared core)
|
||||||
|
├── src/preload/ # CJS preload (sandbox)
|
||||||
|
├── src/renderer/ # Vue renderer
|
||||||
|
└── electron.vite.config.ts
|
||||||
|
|
||||||
|
packaging/ # Skill publish infrastructure
|
||||||
|
├── skill-package.json
|
||||||
|
├── skill-README.md
|
||||||
|
├── skill-LICENSE # MIT (relicensed for the skill artifact)
|
||||||
|
└── publish-skill.sh
|
||||||
|
|
||||||
|
SKILL.md # Skill definition (installed with the artifact)
|
||||||
|
CONTEXT.md # Project glossary
|
||||||
|
docs/adr/ # Architecture decision records (0001–0006)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The optional `/obelisk recap` flow is loaded only for explicit `/obelisk recap` intent.
|
||||||
|
It starts at `references/recap/overview.md` and proceeds card-by-card:
|
||||||
|
|
||||||
|
- `references/recap/pattern1-cover.md` + `references/recap/writing1-cover.md`
|
||||||
|
- `references/recap/pattern2-thinking.md` + `references/recap/writing2-thinking.md`
|
||||||
|
- `references/recap/pattern3-vibe.md` + `references/recap/writing3-vibe.md`
|
||||||
|
- `references/recap/pattern4-workflow.md` + `references/recap/writing4-workflow.md`
|
||||||
|
- `references/recap/pattern5-closing.md` + `references/recap/writing5-closing.md`
|
||||||
|
|
||||||
|
### Generated build outputs
|
||||||
|
|
||||||
|
- `packages/core/dist/` is produced by `npm run build:core`. It is the compiled
|
||||||
|
`@obelisk/core` package: JavaScript, type declarations, and `schema.sql`.
|
||||||
|
- `dist/obelisk-skill/` is produced by `npm run build:skill`. It is the
|
||||||
|
install-ready skill artifact: readable plain JavaScript under `scripts/`,
|
||||||
|
`SKILL.md`, references, and the skill package metadata.
|
||||||
|
|
||||||
|
Both directories are generated and should not be edited by hand. The Electron
|
||||||
|
app imports `packages/core/src/` directly so electron-vite can bundle Core.
|
||||||
|
|
||||||
## Implementation Notes
|
## Implementation Notes
|
||||||
|
|
||||||
The index rebuilds incrementally — only new or modified JSONL files are re-parsed.
|
The index rebuilds incrementally — only new or modified JSONL files are re-parsed.
|
||||||
@@ -204,4 +203,4 @@ Zero npm dependencies. Uses Node 22's built-in node:sqlite with FTS5. The entire
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT @tommy0103
|
AGPL-3.0 @tommy0103
|
||||||
|
|||||||
Reference in New Issue
Block a user