asobi 0.6.1

A persistent, project-local knowledge graph CLI for AI agents.
Documentation
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
# Asobi: Usage Guide

## For humans

### Installation

From source via cargo (Rust 1.85+ toolchain required for edition 2024):

```bash
cargo install --git https://github.com/azusachino/asobi asobi
```

Prebuilt binary via `cargo-binstall` (once GitHub releases are published):

```bash
cargo binstall asobi
```

Or build locally:

```bash
git clone https://github.com/azusachino/asobi && cd asobi
make build            # graph CLI at ./target/debug/asobi
```

### Shell completion

Generate completions from the installed binary so the script always matches the version of Asobi being used:

```bash
# zsh
mkdir -p ~/.zfunc
asobi completions zsh > ~/.zfunc/_asobi
# Add this once before compinit in ~/.zshrc:
# fpath=(~/.zfunc $fpath)

# bash
mkdir -p ~/.local/share/bash-completion/completions
asobi completions bash > ~/.local/share/bash-completion/completions/asobi

# fish
asobi completions fish > ~/.config/fish/completions/asobi.fish
```

The command also supports `elvish` and `powershell`. Completions cover commands, flags, enum values, and help text; entity names remain dynamic graph data and are intentionally resolved through `search` rather than a stale completion cache.

### Workspace setup

Run once on a new machine — defaults to user-level XDG paths:

```bash
asobi init
# created  ~/.local/share/asobi/data
# created  ~/.local/share/asobi/topics
# created  ~/.local/share/asobi/config
```

The user-level workspace is a single `$XDG_DATA_HOME/asobi/` root (default `~/.local/share/asobi/`) holding the same `{data,config,topics,caches}` subtree as a project-local `.asobi/`. `XDG_DATA_HOME` is honored on every platform — macOS included. No root or elevation needed: it lives inside `$HOME` and is owned by the invoking user.

To keep a project's graph isolated and checked in alongside the code, use the local layout:

```bash
cd ~/code/my-project
asobi init --local
# writes ./asobi.toml + ./.asobi/{data,topics,config}/
```

`asobi.toml` (project-local mode):

```toml
data_dir   = ".asobi/data"
config_dir = ".asobi/config"
topics_dir = ".asobi/topics"
```

Path resolution order at runtime: project-local `asobi.toml` → project-local `.asobi/` → XDG. Both `init` modes are idempotent.

Add `.asobi/` to `.gitignore`; the `asobi.toml` itself can be checked in.

### Common workflows

**Start a work session — load prior context:**

```bash
asobi search --where status=IN_PROGRESS
asobi show "my-project:session"
```

**Store a decision (supports hierarchical naming and seeded observations):**

```bash
asobi new "project-x:architecture" "project" --obs "Switched from serde_yaml to toml crate — better error messages"
```

**Link related concepts (preserves case and dots):**

```bash
asobi new "UserPreferences" "preference"
asobi new "CLAUDE.md" "reference"
asobi link "project-x" "UserPreferences" "follows"
```

**Search (supports SQLite FTS5, segment matching, and truth filters):**

```bash
asobi search "tokio"           # finds "tokio" and "tokio-util"
asobi search "mobile"          # finds "ame:mobile-support:task-1" (segment match)
asobi search "auth*"           # prefix: matches "auth", "authentication", "authorize"
asobi search "async AND error" # both words must appear
asobi search "deploy OR ship"  # either word
asobi search "auth" --limit 25 # override the default top 100 matches
asobi search --where status=READY # find all entities with status truth set to READY
asobi search "bug" --where status=READY --where priority=high # filter by multiple truths AND the query
```

Use `graph` for full export. `search` is intentionally top-K by default so a broad term does not accidentally return the whole graph.

**End a session — persist state:**

```bash
asobi truth "my-project:session" "status" "DONE"
asobi truth "my-project:session" "last-updated" "2026-05-21"
asobi obs "my-project:session" "next: implement FTS5 index"
asobi compact  # render durable graph topics to Markdown
```

**Preview and purge stale operational state:**

```bash
# Preview only (the default): terminal sessions/tasks inactive for 30 days
asobi purge

# Narrow the policy to completed tasks older than 90 days
asobi purge --type task --status DONE --older-than 90

# Apply exactly the previewed policy
asobi purge --type task --status DONE --older-than 90 --apply
```

Purge is restricted to `session` and `task` entities. Durable knowledge and installed skills are never accepted by this command. Use `--json` for a machine-readable candidate report, and review the dry-run output before adding `--apply` to a scheduled job.

`compact` syncs only durable _knowledge_ entities (project, decisions, references, preferences) to Markdown. Volatile state (`session`, `task`) and self-indexing `skill` entities stay graph-only — query them with `search` / `show`, and use `export` / `backup` for full archival.

**Inspect the full graph:**

```bash
asobi stats                                # Quick count of entities, relations, observations
asobi graph | jq '.entities[] | select(.entityType == "session")'
```

### Backup, restore, and portable export

| Goal | Command | Includes |
| --- | --- | --- |
| Portable handoff | `asobi export -o graph.json` | Entities, observations, truths, relations |
| Scoped handoff | `asobi export --scope "proj:epic" -o epic.json` | One epic subtree |
| Full SQLite archive | `asobi backup` | Complete database, including skills and task state |

```bash
asobi import graph.json
asobi backup                       # backups/asobi-<timestamp>.db; keep newest 3
asobi backup --keep 5
asobi backup -o /secure/asobi.db   # explicit path; never overwrites
asobi restore /secure/asobi.db     # validate, save current DB, then prompt
asobi restore /secure/asobi.db --force
```

- `--keep` applies only to managed snapshots, not an explicit `-o` path.
- Snapshots are integrity-checked and owner-only on Unix.
- Restore writes `backups/pre-restore-*.db`, closes live handles, atomically replaces the database, and removes stale WAL sidecars.

Scoped export is designed for handing an epic to another agent:

- Includes each root, transitive `part_of` children, and one-hop `depends_on` targets.
- `--rationale` adds one hop of `supersedes`/`extends` from cited decisions.
- Excludes `session`, `preference`, and `standard` entities.
- Produces ordinary JSON consumed by `asobi import`.

```bash
asobi export --scope "proj:epic" --scope "proj:other-epic" -o bundle.json
asobi export --scope "proj:epic" --rationale -o bundle.json
```

**Manage truths (structured key-value attributes):**

```bash
asobi truth "project-x" "language" "rust"
asobi rm-truth "project-x" "language"
asobi history "project-x"            # all superseded truth values, newest first
asobi history "project-x" "language" # history for one truth key
```

Overwriting a truth records the previous value with its valid-time window; the current value stays a single row. History is opt-in via `history` (never shown in `search`/`graph`/`show`) and is local — JSON `export`/`import` carries current graph state only, not the change log.

**Manage skills (reusable workflows and knowledge):**

```bash
asobi skills install https://github.com/azusachino/asobi-skills --all
asobi skills
asobi skills show my-skill
asobi skills update
asobi skills remove asobi-skills
```

**Coordinate durable task work:**

```bash
asobi tasks plan "project:epic" --objective "Ship the feature" \
  --task "Implement the change" --task "Verify the result"
asobi tasks list "project:epic"
asobi tasks dispatch                 # select the first READY_TO_DISPATCH task
asobi tasks sync "project:epic:task-1" --note "make check passes" --status DONE
asobi tasks close "project:epic"
```

Use `asobi tasks --help` or `asobi tasks <command> --help` for the complete argument reference. These are graph-backed commands: status is a truth, implementation notes are observations, and child tasks link to their epic via `part_of`.

---

## For agents

### Overview

Asobi is a persistent, project-local knowledge graph. Agents use it to:

- **Persist** decisions, task state, and user preferences across sessions
- **Share** context with other agents working on the same project
- **Resume** work without re-deriving context from git history or code

All operations are CLI commands. No server to start. No authentication. Latency is <10ms for graph operations.

### Session protocol

**At session start:**

```bash
# Option A: load a specific entity
asobi show "<project>:session"

# Option B: query by status truth
asobi search --where status=IN_PROGRESS

# Option C: full graph (small projects)
asobi graph
```

**During session — record facts as you learn them:**

```bash
asobi obs "<project>" "Decided to use WAL mode for concurrent agent access"
asobi truth "<project>:session" "status" "IN_PROGRESS"
```

**At session end:**

```bash
# Update volatile state
asobi truth "<project>:session" "status" "DONE"
asobi truth "<project>:session" "last-updated" "2026-05-21"
asobi obs "<project>:session" "completed: implemented FTS5 search"
asobi obs "<project>:session" "next: add WAL mode and entity_name index"

# Archive to markdown (durable, re-indexed)
asobi compact
```

**Full session reset (next agent starts clean):**

```bash
asobi rm "<project>:session"
# Next agent creates it fresh and sets initial status
asobi new "<project>:session" "session"
asobi truth "<project>:session" "status" "IN_PROGRESS"
```

### Entity naming conventions

| Pattern | Type | Purpose |
| --- | --- | --- |
| `<project>:session` | `session` | Volatile task state — reset each session |
| `<project>:tasks` | `task` | In-progress task tracking |
| `<project>` | `project` | Stable project facts, architecture decisions |
| `UserPreferences` | `preference` | Cross-project user habits |
| `CodingStyle` | `standard` | Commit format, indentation, etc. |
| `ToolPreferences` | `preference` | Nix, make, etc. |

### Machine-readable response contract

Commands retain their existing JSON payload shapes. `asobi schema` is the compatibility promise and discovery surface:

```bash
asobi schema
asobi schema --command show
```

The schema document carries its own `schemaVersion`, independent from the storage/export `apiVersion`. Use the command-specific schema to validate and parse the corresponding payload; no extra response wrapper is required.

### Output format

Asobi operates under a **lazy-read contract** to minimize token overhead.

The payload for `graph` and `search` is a lazy JSON structure (excluding `observations` and skill `body`, only providing `truths` and `observationCount`):

```json
{
  "entities": [
    {
      "name": "string",
      "entityType": "string",
      "truths": {
        "key": "value"
      },
      "observationCount": 12
    }
  ],
  "relations": [
    {
      "from": "string",
      "to": "string",
      "relationType": "string"
    }
  ]
}
```

`show` eagerly returns all `observations` and the skill `body` (if it's a skill entity):

```json
{
  "entities": [
    {
      "name": "string",
      "entityType": "string",
      "observations": ["string", ...],
      "truths": {
        "key": "value"
      },
      "observationCount": 12,
      "body": "string"
    }
  ],
  "relations": [
    {
      "from": "string",
      "to": "string",
      "relationType": "string"
    }
  ]
}
```

Mutation commands print a one-line confirmation: `Entity 'X' created.`, `Observation added.`, etc.

### Multi-agent context handoff

When Agent A finishes and Agent B picks up:

```bash
# Agent A (end of session)
asobi obs "project-x:session" "status: BLOCKED"
asobi obs "project-x:session" "next: Agent B should implement WAL mode in src/db.rs init_db()"
asobi compact

# Agent B (start of session)
asobi show "project-x:session"
# → reads: status BLOCKED, next action, last-updated
```

No files to pass, no state to reconstruct. The graph is the handoff.

### Search tips

`search` uses SQLite FTS5 with porter stemming and BM25 ranking, followed by a name/type substring fallback. Practical implications:

- `search "run"` → matches the indexed term "run" (use the exact term when needed)
- `search "implement"` → matches the indexed term "implement"
- `search "tokio async"` → finds entities with both words (ranked higher) or either word
- `search "UserPreferences"` → exact name match via LIKE fallback (entity has no observations)
- `search "AND AND"` → invalid full-text syntax, silently falls back to LIKE, returns empty
- `search "auth" --limit 500` → return more than the default top 100 matches
- `search --where KEY=VALUE` → filters matching entities by truth values (e.g. `--where status=READY`). Can be repeated; multiple filters perform an intersection (AND condition). If a query term is also provided, it matches the intersection of the filters and the FTS/LIKE results.

For exact entity retrieval, prefer `show` over `search`:

```bash
asobi show "project-x:session" "UserPreferences"
```

`search` accepts an optional `--limit` argument. Omit it for the default top 100 matches; set it explicitly for larger ranked exports.

## Running in Sandboxed Environments (Codex, etc.)

When running in sandboxed or highly restricted environments (such as Codex, Nix build sandboxes, or certain containerized runners), the environment might impose constraints on directory write access or shared-memory creation. Asobi can be configured to run smoothly in these environments using the following techniques:

### Project-Local Workspace

Use the project-local setup to avoid writing to the global `~/.local` (XDG) directory, which may be read-only or non-existent:

```bash
asobi init --local
```

This writes an `asobi.toml` file in the current working directory and places database and configurations within the `./.asobi/` subdirectory.

### Custom Database Paths

You can override Asobi's home or database locations using environment variables:

- **`ASOBI_HOME`**: Changes the base directory under which Asobi looks for configuration, data, and topics (e.g. `ASOBI_HOME=/tmp/asobi`).
- **`ASOBI_DATABASE_URL`**: Specifies the direct path to the database file itself (e.g. `ASOBI_DATABASE_URL=/tmp/asobi-custom.db`).

### SQLite concurrency

SQLite is opened in WAL mode with foreign keys enabled and a bounded `ASOBI_BUSY_TIMEOUT` (15 seconds by default). Writes use immediate transactions, so multiple agents can read concurrently while writes serialize safely. Task dispatch claims the task and records the claim observation atomically.