Install any skill in seconds. Free to start, no credit card required.
Get Started Free →A logical analysis and reasoning tool for AI. Use when decomposing documents into structured knowledge, querying entities and relations, validating consistency, or indexing files. Trigger on "remember", "what do I know about", "link X to Y", "show dependencies", "analyze this document", entity CRUD, or cross-skill data access.
.claude/skills/x-cmd-ondb/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 1253% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 1869% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 2792% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 318% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 160% | 0% |
A typed vocabulary + constraint system for representing knowledge as a verifiable graph. The TSV log is the protocol — query it with AWK, Python, JS, or SQLite.
Ondb is a logical analysis and reasoning tool for AI. It gives AI the ability to decompose unstructured content into structured knowledge, reason along relationship chains, and validate logical consistency.
Everything is an entity with a type, properties, and relations to other entities. All mutations are appended as TSV lines to a log file.
Entity: { id, type, properties }
Relation: { from_id, relation_type, to_id, properties }Multiple ondb instances are the default approach. Each sub-domain, each article, each analysis perspective can have its own independent ondb instance. This is by design — small focused ondb instances are easier to reason about, validate, and maintain.
Index files in a project. The ondb instance points to files but doesn't duplicate their content.
bashx ondb add --datadir memory/ --type Document --name "API Design" --id doc_api \ -- path=docs/api-design.md x ondb add --datadir memory/ --type Person --name "Alice" --id p1 x ondb link --datadir memory/ --from doc_api --rel authored_by --to p1
Decompose an article into structured knowledge. The ondb instance IS the analysis result.
bashx ondb add --datadir kb/ --type Pattern --name "Saga" --id saga x ondb add --datadir kb/ --type Problem --name "Distributed Consistency" --id prob_dc x ondb add --datadir kb/ --type Article --name "Saga Deep Dive" --id art_001 \ -- path=articles/saga.md x ondb link --datadir kb/ --from saga --rel solves --to prob_dc x ondb link --datadir kb/ --from art_001 --rel covers --to saga
After modeling 50 articles, you can reason: "What patterns solve distributed consistency?" → find Saga → find related articles → find complementary patterns.
Model the same codebase from different angles in one ondb instance. Type = concept, each with distinct required props.
bash# Architecture perspective x ondb add --datadir code/ --type Module --name "auth" --id mod_auth -- path=src/auth/ # OOP perspective x ondb add --datadir code/ --type Class --name "JWTAuth" --id cls_jwt -- file=src/auth/jwt.py # API perspective x ondb add --datadir code/ --type Endpoint --name "POST /login" --id ep_login # Cross-perspective reasoning x ondb link --datadir code/ --from ep_login --rel handled_by --to cls_jwt x ondb link --datadir code/ --from cls_jwt --rel belongs_to --to mod_auth # Query across perspectives: which module handles POST /login? # Endpoint → Class → Module (two hops)
Lightweight structured data lives directly in an ondb instance. No external files needed.
bashx ondb add --datadir work/ --type Task --name "Fix auth bug" --id t1 \ -- status=open priority=high x ondb add --datadir work/ --type Task --name "Write tests" --id t2 \ -- status=open x ondb link --datadir work/ --from t1 --rel blocks --to t2 x ondb query --datadir work/ --type Task --where status=open
bashx ondb add --datadir notes/ --type Event --name "Sprint Planning" --id ev1 \ -- date=2026-05-27 path=notes/2026-05-27-sprint.md x ondb add --datadir notes/ --type Person --name "Bob" --id p2 x ondb link --datadir notes/ --from ev1 --rel attended_by --to p2 \ -- role=facilitator
Ondb rewards deliberate design but can also be used casually:
| | Casual | Designed | |---|---|---| | Schema | None | Formal constraints | | Types | Free-form | Clear concept system | | Reasoning | Weak (find things) | Strong (chain inference) | | Best for | Quick memory | Long-term knowledge base |
When merging multiple perspectives, each type must be a clear concept with no ambiguity. Rule: same type name = same concept, always. If "Service" could mean a code module or a runtime process, split into Module and Process.
bash# In schema.tsv (flat TSV, no JSON/YAML): type Module req Module path type Process req Process port type Service req Service kind enum Service kind module,process
Schema directives: type, req (required), forbid (forbidden), enum (allowed values), rel (relation), rfrom/rto (allowed types), rcard (cardinality), racyclic (no cycles).
Multiple ondb instances are good — each is a complete, independent analysis. Integrating into a main ondb instance is only needed when sub-domains share same-level semantics that require deep joint reasoning.
analysis/
auth/ondb.tsv ← complete analysis of auth domain, usable standalone
api/ondb.tsv ← complete analysis of API design, usable standalone
arch/ondb.tsv ← complete dependency analysis, usable standalone
main/ondb.tsv ← refactored integration for cross-domain reasoningNo merge needed: query each sub-domain separately, combine results manually.
Merge needed: when concepts from different domains relate at the same semantic level, and split ontologies cannot express the cross-domain relationships.
# Cross-domain chain: only visible after integration
POST /login → handled_by → JWTAuth → uses_pattern → Saga → solves → Consistency
# The merge is NOT data concatenation. It is:
# 1. Refactor sub-domain's concept system to align with main ondb instance
# 2. Re-examine facts and relations in the broader context
# 3. Write curated results into main ondb instance<datadir>/ # specified via --datadir flag
├── ONDB.DESC.txt # Required. What this ondb instance is about
├── ONDB.SKILL.md # Optional. Skill description + usage methods + experience
├── rule/ # Optional. LLM self-check rules for semantic consistency
│ ├── consistency.yml # e.g. no orphan links, consistent type naming
│ └── naming.yml # e.g. naming conventions for types and relations
├── snapshot.<epoch_ms> # Compact snapshot (current state as TSV directives)
├── log.<epoch_ms> # Incremental log after snapshot
├── ondb.tsv # Initial log (deleted after first compact)
└── ondb.db # Optional. SQLite materialized viewONDB. prefix serves as a directory marker — seeing it tells you this is an ondb directory| Trigger | Action | |---------|--------| | "Remember that..." | x ondb add | | "What do I know about X?" | x ondb get --id X | | "Link X to Y" | x ondb link | | "Show all tasks for project Z" | x ondb linked --id Z | | "What depends on X?" | x ondb linked --id X --direction incoming | | Skill needs shared state | Read/write TSV log |
Default file: ondb.tsv in current directory.
# Comments start with #, empty lines ignored
add Person pers_001 1716816000000 name Alice email alice@example.com
add Project proj_001 1716816000001 name Website Redesign status active
add Task task_001 1716816000002 title Fix bug status open priority high
link proj_001 has_task task_001 1716816000003
link pers_001 assigned_to task_001 1716816000004
set task_001 1716816000005 status done
rm task_002 1716816000006
unlink proj_001 has_task task_002 1716816000007| Directive | Fields | Meaning | |-----------|--------|---------| | add | type, id, epoch_ms, key val pairs... | Create entity with properties | | set | id, epoch_ms, key val pairs... | Update entity properties | | rm | id, epoch_ms | Delete entity | | link | from, rel, to, epoch_ms, key val pairs... | Create relation | | unlink | from, rel, to, epoch_ms | Remove relation |
\t\n\\bash# Auto-generated ID (pers_001, pers_002, ...) x ondb add --type Person --name Alice # Explicit ID x ondb add --type Project --name "My Project" --id proj_001 # With properties x ondb add --type Task --name "Write docs" priority=high due=2026-06-01
bash# Get single entity x ondb get --id p_001 # List all entities x ondb ls # List by type x ondb ls --type Task # Filter by property values (multiple --where for AND) x ondb query --type Task --where status=open x ondb query --type Task --where status=open --where priority=high # Note: --where falls back to AWK when JS/Python backend is active # JSON output x ondb ls --type Task --json x ondb get --id p_001 --json
bash# Create relation x ondb link --from proj_001 --rel has_task --to task_001 # View relations (outgoing) x ondb linked --id proj_001 # View relations (incoming — who links TO this entity) x ondb linked --id task_001 --direction incoming # Filter by relation type x ondb linked --id proj_001 --rel has_task # Both directions x ondb linked --id p_001 --direction both
linked returns relation metadata. related returns the full entity on the other side.
bash# What projects does task_001 belong to? x ondb related --id task_001 --rel has_task --direction incoming # What tasks are in proj_001? x ondb related --id proj_001 --rel has_task --direction outgoing # JSON output x ondb related --id proj_001 --rel has_task --json
Output (TSV):
has_task task_001 Task title=Fix bug status=open
has_task task_002 Task title=Write docs status=doneOutput (JSON):
json[ {"relation":"has_task","entity":{"id":"task_001","type":"Task","props":{"title":"Fix bug","status":"open"}}}, {"relation":"has_task","entity":{"id":"task_002","type":"Task","props":{"title":"Write docs","status":"done"}}} ]
bash# Update properties x ondb set --id task_001 status=done # Delete entity x ondb rm --id task_002 # Remove relation x ondb unlink --from proj_001 --rel has_task --to task_002
bash# Check graph integrity and schema constraints x ondb validate x ondb validate x ondb validate --datadir memory/ --schema memory/schema.tsv
What validate checks:
racyclic (e.g. blocks)Validation is separate from write — run it after batch changes or before committing.
Compress the append-only log into a snapshot. Old snapshots and logs are cleaned up automatically.
bash# Compact current directory x ondb compact # Compact specific directory x ondb compact --datadir memory/
Output: snapshot.<epoch_ms> containing the current state as TSV directives. After compact, new changes go to log.<epoch_ms>.
bash# Library paths for custom queries x ondb libpath # → /path/to/ondb/lib x ondb libpath awk # → .../lib/awk/ontology.awk x ondb libpath py # → .../lib/py x ondb libpath js # → .../lib/js x ondb libpath sqlite # → .../lib/sqlite/README.md # SQLite db path for direct SQL access x ondb dbpath --datadir memory/ # → memory/ondb.db
# x ondb ls
pers_001 Person Alice
proj_001 Project Website Redesign
task_001 Task Fix bug
# x ondb get --id pers_001
id pers_001
type Person
ctime 1716816000000
mtime 1716816000000
prop name=Alice
prop email=alice@example.com
# x ondb linked --id proj_001
has_task task_001 Taskbash# x ondb ls --json [{"id":"pers_001","type":"Person","name":"Alice"},...] # x ondb get --id pers_001 --json {"id":"pers_001","type":"Person","properties":{"name":"Alice","email":"alice@example.com"}} # x ondb linked --id proj_001 --json [{"rel":"has_task","id":"task_001","type":"Task"}]
| Type | Key Properties | Use Case | |------|---------------|----------| | Person | name, email, phone | People and contacts | | Organization | name, type | Companies, teams | | Project | name, status | Work containers | | Task | title, status, priority | Actionable work items | | Goal | description, target_date | Objectives | | Event | title, start, end | Calendar items | | Document | title, path, url | Files and links | | Note | content, tags | Freeform notes | | Location | name, address | Places |
| Relation | From | To | Meaning | |----------|------|----|---------| | has_task | Project | Task | Project contains task | | has_owner | Project/Task | Person | Ownership | | assigned_to | Task | Person | Assignment | | member_of | Person | Organization | Membership | | blocks | Task | Task | Dependency | | depends_on | Task/Project | Task/Project | Dependency | | mentions | Document/Note | Any | Reference |
The ondb TSV log is compatible with x digraph when using di/done/fail directives alongside add/link:
bash# In the same log file, you can mix ondb and digraph directives add Task task_001 1716816000000 title Setup CI add Task task_002 1716816000001 title Run tests link task_001 blocks task_002 1716816000002 di task_001 task_002 # digraph dependency done task_001 # mark as completed # Then use digraph to find next executable tasks x digraph next -f ondb.tsv
Model multi-step plans as a sequence of graph operations:
Plan: "Schedule team meeting and create follow-up tasks"
1. x ondb add --type Event --name "Team Sync" --id event_001
2. x ondb link --from proj_001 --rel has_event --to event_001
3. x ondb add --type Task --name "Prepare agenda" --id task_010
4. x ondb link --from event_001 --rel has_task --to task_010
5. x ondb add --type Task --name "Send summary" --id task_011
6. x ondb link --from task_010 --rel blocks --to task_011When working with existing ondb data, append changes instead of overwriting files. This preserves history and avoids clobbering prior definitions. The set and rm commands always append — they never modify existing lines.
> Note: add, set, link, and rm do not validate schema at write time. Validation is done separately via x ondb validate. This makes writes fast and atomic — the TSV log accepts anything, and correctness is checked on demand.
x cawk) — zero dependencies, fastest for <2000 entitiesAWK is the recommended and default path. Each sub-domain ondb instance stays small by design — AWK replay is millisecond-level for thousands of entities.
SQLite mode exists for one specific case: a single domain with a genuinely large dataset (e.g. 50k contacts, 10k indexed documents). In this case, AWK replay becomes slow and SQLite provides indexed O(log n) queries.
SQLite mode is NOT for:
SQLite is a materialized view — it is automatically generated from the TSV log on first query. No manual setup needed. To force a rebuild, delete ondb.db and .lines files.
ondb is a protocol — the TSV log is the authority. You can read and query it with any language.
bash# Get library base directory x ondb libpath # → /path/to/ondb/lib # Get specific language paths x ondb libpath awk # → .../lib/awk/ontology.awk x ondb libpath py # → .../lib/py x ondb libpath js # → .../lib/js x ondb libpath sqlite # → .../lib/sqlite/README.md
| Environment | Recommended Backend | Why | |-------------|---------------------|-----| | Default (no special setup) | AWK | Zero dependencies, fastest for <2000 entities | | Python available | Python | Best balance, rich data structures | | Node.js/Bun available | JS (Bun) | Modern JS, fast startup | | ondb.db exists | SQLite | Direct SQL, indexed queries |
bash# Check what you have which python3 && echo "Python available" which bun && echo "Bun available" which sqlite3 && ls ondb.db && echo "SQLite available" # AWK is always the fallback
Extract data with SQLite (fast indexed query), then process with AWK:
bash# Step 1: SQLite extracts raw data DBPATH=$(x ondb dbpath) sqlite3 "$DBPATH" -separator '\t' " SELECT l.from_id, l.to_id, p.value FROM links l JOIN entities e ON e.id = l.to_id LEFT JOIN props p ON p.entity_id = l.to_id AND p.key = 'name' WHERE l.rel = 'blocks' " > /tmp/blocking.tsv # Step 2: AWK post-processes (counts, filters, formats) awk -F'\t' ' { count[$1]++; blocked[$1] = blocked[$1] " " $3 } END { for (task in count) print task " blocks " count[task] " tasks:" blocked[task] } ' /tmp/blocking.tsv
When to use: Complex SQL query + simple post-processing. SQLite does the heavy lifting, AWK does the formatting.
Extract with SQL, analyze with Python:
bashDBPATH=$(x ondb dbpath) sqlite3 "$DBPATH" -csv " SELECT e.id, e.type, p.key, p.value FROM entities e LEFT JOIN props p ON p.entity_id = e.id WHERE e.type IN ('Task', 'Project') " | python3 -c " import sys, csv from collections import defaultdict entities = defaultdict(dict) for row in csv.reader(sys.stdin): eid, etype, key, val = row entities[eid]['type'] = etype if key: entities[eid][key] = val # AI custom analysis: find projects with no open tasks for eid, e in entities.items(): if e['type'] == 'Project': # ... custom logic print(eid, e.get('name', '')) "
When to use: Need Python data structures (dicts, sets) for complex analysis after SQL extraction.
Process redo.tsv directly without SQLite:
bash# Find all tasks blocked by overdue tasks # (no SQLite needed — works on any POSIX system) awk -F'\t' ' # Pass 1: load all tasks $1=="add" && $2=="Task" { tasks[$3] = 1 for (i=5; i<=NF; i+=2) { if ($i == "due") due[$3] = $(i+1) if ($i == "status") status[$3] = $(i+1) } } # Pass 2: find blocking relationships $1=="link" && $3=="blocks" && tasks[$2] && tasks[$4] { if (status[$2] == "open" && due[$2] < "2026-05-30") print "OVERDUE: " $2 " blocks " $4 } ' ondb.tsv
When to use: Simple analysis on raw log, no setup needed, works everywhere.
bashDBPATH=$(x ondb dbpath) # Extract summary stats sqlite3 "$DBPATH" -json " SELECT type, COUNT(*) as cnt FROM entities GROUP BY type " | bun -e " const data = JSON.parse(await Bun.stdin.text()); const total = data.reduce((s, r) => s + r.cnt, 0); console.log('Total entities:', total); for (const row of data) { const pct = ((row.cnt / total) * 100).toFixed(1); console.log(row.type + ': ' + row.cnt + ' (' + pct + '%)'); } "
When to use: JSON output → JS processing for dashboards, reports, web APIs.
See each README.md for complete API reference and schema check examples:
bashcat "$(dirname "$(x ondb libpath awk)")/README.md" # AWK API cat "$(x ondb libpath py)/README.md" # Python API cat "$(x ondb libpath js)/README.md" # JS API cat "$(x ondb libpath sqlite)" # SQLite guide
When built-in commands are not enough, write custom code:
python# Example: find orphaned tasks (no parent project) LIBPATH=$(x ondb libpath py) python3 -c " import sys; sys.path.insert(0, '$LIBPATH') from ontology import Ondb ondb = Ondb() with open('ondb.tsv') as f: ondb.load(f) for eid, e in ondb.entities.items(): if e['type'] == 'Task': parents = ondb.related(eid, 'has_task', 'incoming') if not parents: print(f'Orphaned: {eid}') "
bash# Example: find documents mentioning API awk -F'\t' ' $1=="add" && $2=="Document" && index($0,"API") { docs[$3]=1 } $1=="link" && $3=="authored_by" && docs[$2] { print $4 " authored " $2 } ' ondb.tsv
Rule: Built-in commands for quick operations. Custom code for complex graph logic.
WAL 模式(Write-Ahead Logging)已启用。
ondb 的 SQLite 实例使用 PRAGMA journal_mode=WAL 作为默认配置,原因:
busy_timeout=5000ms),避免 database is locked 错误⚠️ 已知限制:
-wal 和 -shm 临时文件(checkpoint 后自动清理)-shm 文件),某些网络文件系统不支持 mmap 或文件锁,可能导致数据损坏。如部署到 NFS,需测试 PRAGMA journal_mode=DELETE 是否更稳定-wal 文件膨胀。ondb 的查询都是短连接,此问题不显著.db + .db-wal 文件,或使用 SQLite 的 .backup 命令| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 7,056 | 9,160 | +30% | 1 | 1 | 0% | 616 | 8,337 | +1253% | 0 | 0 | — |
case-02 | fail→pass | 13,066 | 7,353 | -44% | 1 | 1 | 0% | 354 | 6,969 | +1869% | 0 | 0 | — |
case-03 | fail→pass | 8,278 | 2,375 | -71% | 1 | 1 | 0% | 238 | 6,883 | +2792% | 0 | 0 | — |
case-04 | fail→pass | 12,714 | 3,824 | -70% | 1 | 1 | 0% | 1,722 | 7,195 | +318% | 0 | 0 | — |
case-05 | fail→pass | 29,417 | 4,275 | -85% | 1 | 1 | 0% | 2,804 | 7,277 | +160% | 0 | 0 | — |
case-06 | fail→pass | 15,429 | 6,360 | -59% | 1 | 1 | 0% | 2,480 | 7,547 | +204% | 0 | 0 | — |
case-07 | fail→pass | 7,948 | 3,789 | -52% | 1 | 1 | 0% | 1,014 | 7,061 | +596% | 0 | 0 | — |
case-08 | fail→pass | 26,647 | 5,680 | -79% | 1 | 1 | 0% | 1,414 | 7,658 | +442% | 0 | 0 | — |
case-09 | fail→pass | 29,615 | 3,885 | -87% | 1 | 1 | 0% | 4,988 | 7,040 | +41% | 0 | 0 | — |
case-10 | fail→pass | 12,820 | 4,394 | -66% | 1 | 1 | 0% | 2,055 | 7,299 | +255% | 0 | 0 | — |
case-11 | fail→pass | 43,644 | 13,981 | -68% | 1 | 1 | 0% | 1,965 | 8,068 | +311% | 0 | 0 | — |
case-12 | fail→pass | 12,081 | 7,868 | -35% | 1 | 1 | 0% | 1,884 | 7,804 | +314% | 0 | 0 | — |
case-13 | fail→pass | 15,711 | 3,931 | -75% | 1 | 1 | 0% | 2,544 | 6,989 | +175% | 0 | 0 | — |
case-14 | fail→pass | 15,983 | 5,688 | -64% | 1 | 1 | 0% | 2,704 | 7,433 | +175% | 0 | 0 | — |
case-15 | fail→pass | 36,749 | 9,195 | -75% | 1 | 1 | 0% | 3,259 | 7,940 | +144% | 0 | 0 | — |
case-16 | pass→pass | 17,624 | 20,496 | +16% | 1 | 1 | 0% | 1,910 | 8,348 | +337% | 0 | 0 | — |
case-17 | fail→pass | 9,089 | 5,317 | -42% | 1 | 1 | 0% | 1,319 | 7,074 | +436% | 0 | 0 | — |
case-18 | fail→pass | 9,968 | 3,204 | -68% | 1 | 1 | 0% | 1,654 | 7,107 | +330% | 0 | 0 | — |
case-19 | pass→pass | 12,942 | 6,024 | -53% | 1 | 1 | 0% | 2,047 | 7,568 | +270% | 0 | 0 | — |
case-20 | pass→fail | 15,168 | 22,844 | +51% | 1 | 1 | 0% | 2,877 | 10,792 | +275% | 0 | 0 | — |
case-21 | pass→pass | 11,061 | 13,037 | +18% | 1 | 1 | 0% | 2,084 | 8,426 | +304% | 0 | 0 | — |
case-22 | pass→pass | 9,390 | 7,343 | -22% | 1 | 1 | 0% | 1,701 | 8,060 | +374% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 18 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +73 percentage points is the difference between those two pass rates over the 18 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.