i-self 0.4.3

Personal developer-companion CLI: scans your repos, indexes code semantically, watches your activity, and moves AI-agent sessions between tools (Claude Code, Aider, Goose, OpenAI Codex CLI, Continue.dev, OpenCode).
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
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# i-self Features

A deeper tour of every subcommand than the [README](README.md): what it
actually does, when to use it, worked examples, and known limitations.
Where the README is a reference card, this is the manual.

> **Versioning note.** This document targets **0.4.x**. Earlier 1.0.0
> releases advertised features that were stubs; the [CHANGELOG]CHANGELOG.md
> entry for 0.4.0 lists the breaking changes that made everything below
> actually work. Anything still flagged "stub" or "best-effort" is called
> out explicitly here.

## Contents

- [Code intelligence]#code-intelligence
  - [Repo scanning & profile (`setup`)]#repo-scanning--profile-setup
  - [Semantic search & RAG (`index`, `query`, `ask`)]#semantic-search--rag-index-query-ask
  - [Code review (`review`)]#code-review-review
  - [Skills & learning (`skills`, `learn`)]#skills--learning-skills-learn
- [Cross-agent session sharing]#cross-agent-session-sharing
- [Activity monitoring (`monitor`, `track`)]#activity-monitoring-monitor-track
- [Automation rules (`automate`)]#automation-rules-automate
- [Vulnerability scanner (`vuln`)]#vulnerability-scanner-vuln
- [Cloud sync (`sync`)]#cloud-sync-sync
- [Web dashboard / REST API (`dashboard`, `api`)]#web-dashboard--rest-api-dashboard-api
- [Snippets (`snippet`)]#snippets-snippet
- [Messaging (`message`)]#messaging-message
- [Team aggregation (`team`)]#team-aggregation-team
- [Built-in analyzers (`plugin`)]#built-in-analyzers-plugin
- [Things that look like features but aren't]#things-that-look-like-features-but-arent

---

## Code intelligence

### Repo scanning & profile (`setup`)

Walks every repo it can find — across GitHub, GitLab, Bitbucket, and
local directories — and builds a "developer profile" stored at
`~/.i-self/profile.json`. The profile records languages, framework usage,
commit cadence, and patterns the analyzer pulled out of your code.

```bash
i-self setup                        # interactive wizard
i-self refresh                      # rescan, picks up new repos and recent commits
i-self status                       # show what's been profiled
```

Tokens for each VCS go in `~/.i-self/config.toml`:

```toml
github_token   = "ghp_..."
gitlab_token   = "..."
bitbucket_token = "..."
```

**Limitations.** Forks and archived repos are skipped by default —
override with `include_forks = true` / `include_archived = true` in
config. Initial scan of a large GitHub account can take several minutes;
subsequent `refresh` runs are incremental.

### Semantic search & RAG (`index`, `query`, `ask`)

`index` chunks source files and embeds them; `query`/`search` finds
similar chunks; `ask` runs RAG (retrieval-augmented generation) by
fetching relevant chunks and feeding them to the configured LLM.

```bash
i-self index ./my-project
i-self query "where do we handle retry logic?"
i-self search "auth middleware" --top-k 20 --language rust
i-self ask "Why does the websocket reconnect?" --use-rag
```

**Embedding backend selection.** When `OPENAI_API_KEY` is set, embeddings
go through `text-embedding-3-small` at 384 dimensions (real semantic
embeddings). Without a key, a hash-bucket fallback is used and a loud
warning is logged at startup — search will degrade to keyword matching.

**Vector-space safety.** Embeddings are tagged with the producing model
in `~/.i-self/embeddings/manifest.json`. If you toggle `OPENAI_API_KEY`
between runs, the index refuses to mix vectors from different backends —
loads return empty and the warning tells you to re-run `i-self index`.

**Limitations.** No incremental reindexing yet — `i-self index` always
re-embeds the whole tree. Expensive on big monorepos. Chunking is
boundary-aware (function / class headers) but not language-server-aware,
so very long functions get split mid-body.

### Code review (`review`)

Runs the configured LLM over a diff or a code blob, with your developer
profile injected as context so the review reflects your conventions.

```bash
i-self review code --code "$(cat src/foo.rs)" --language rust
i-self review pr --base main --head HEAD                # against current git diff
```

Built-in analyzer plugins (security patterns, performance patterns, doc
coverage) run alongside the LLM and surface deterministic findings.

### Skills & learning (`skills`, `learn`)

`skills` extracts a proficiency profile from your code and (optionally)
gap-analyzes it against a job profile.

```bash
i-self skills profile               # what you do well
i-self skills gap "Senior Backend Engineer (Python, AWS, Kafka)"
i-self learn paths                  # recommended courses / books / projects
```

**Limitations.** Skill levels are heuristic (lines-of-code × recency × variety),
not benchmarked. Treat the gap analysis as a conversation starter, not a
verdict.

---

## Cross-agent session sharing

The headline feature added in 0.4.x. Discover AI-agent transcripts on
disk, render them to a portable format, and **import them into a different
agent** so a conversation started in one tool can continue in another.

### Provider matrix

| Tool | List | Load | Import (write) | On-disk format |
|---|:-:|:-:|:-:|---|
| **Claude Code** |||| `~/.claude/projects/<encoded-cwd>/<uuid>.jsonl` |
| **Aider** |||| `<project>/.aider.chat.history.md` |
| **Goose** (Block) |||| `~/.config/goose/sessions/<id>.jsonl` |
| **OpenAI Codex CLI** |||| `~/.codex/sessions/YYYY/MM/DD/rollout-<uuid>.jsonl` |
| **Continue.dev** |||| `~/.continue/sessions/<id>.json` (or legacy `sessions.json`) |
| **OpenCode** |||| `~/.local/share/opencode/storage/session/{info,message}/` |
| **Generic OpenAI JSON** | ✅* ||| any dir set via `ISELF_GENERIC_DIR` |
| **Clipboard** (paste-into) | n/a | n/a || stdout (pipe to `pbcopy`/`xclip`/`Set-Clipboard`) |
| **Copilot Chat / Cline / Cursor** ||| clipboard only | not file-addressable |

*The generic provider only enumerates when `ISELF_GENERIC_DIR` is set,
because we don't want to scan random JSON files in your home dir.

Per-target data directory overrides: `ISELF_GOOSE_DIR`, `ISELF_CODEX_DIR`,
`ISELF_CONTINUE_DIR`, `ISELF_OPENCODE_DIR`, `ISELF_AIDER_SEARCH_ROOTS`
(colon-separated), `ISELF_GENERIC_DIR`.

### Discovering, exporting, uploading

```bash
# Newest-first list across every supported provider
i-self share ls
i-self share ls --provider claude-code --since 7d         # filters: h/d/w

# Export to portable JSON (the canonical interchange format)
i-self share export <id> --format json --output session.json

# Render for human reading
i-self share export <id> --format markdown
i-self share export <id> --format html               # self-contained, no external assets

# Strip secrets that look like API keys, tokens, passwords
i-self share export <id> --format markdown --redact

# Upload to S3 + presigned URL (reuses your i-self sync config)
i-self share upload <id> --format html --expires-in 86400
```

**Secret redaction** ([src/share/redact.rs](src/share/redact.rs)) catches
high-recall patterns: OpenAI / Anthropic / GitHub / GitLab / Slack / Stripe /
Google API keys, AWS access-key + secret pairs, generic JWTs, `Bearer ...`
headers, `password=...` assignments. Each match becomes
`[REDACTED:<kind>]`. **Not a substitute for human review** — your session
can still leak business logic, customer names, schema information.

### Importing — the cross-agent magic

```bash
# Continue a Claude Code session in Aider
i-self share export <claude-id> --format json --output s.json
i-self share import s.json --target aider --project /path/to/repo

# Or hand off in either direction
i-self share import s.json --target claude-code
i-self share import s.json --target goose
i-self share import s.json --target codex
i-self share import s.json --target continue
i-self share import s.json --target generic-openai

# For tools without addressable on-disk storage (Copilot, Cline, Cursor)
i-self share import s.json --target clipboard | pbcopy            # macOS
i-self share import s.json --target clipboard | xclip -selection clipboard
i-self share import s.json --target clipboard | Set-Clipboard     # PowerShell
```

`<input>` accepts a file path, an `https://...` URL (e.g. a presigned
`share upload` link), or `-` for stdin. JSON only — Markdown is
intentionally rejected as ambiguous to round-trip.

Imported sessions get a leading provenance message:

> [i-self import] Continued from \<provider\> session \<id\>. \<N\> prior messages follow.

so the recipient agent (and you, scrolling back) can tell at a glance
where the transcript came from.

### Fidelity caveat

Each agent has its own tool catalog (Claude Code's `Bash`, Aider's
`/run`, Goose's plugins, etc.). When crossing agent boundaries, tool
calls flatten to text descriptions. The recipient gets a faithful,
readable transcript they can continue from — **not** a wire-compatible
session that re-executes the source agent's tool calls verbatim.

OpenCode import is intentionally absent: its session-write paths
reference internal Bun runtime IDs, and a synthetic file may not appear
in `opencode --list`. Use `--target clipboard` for OpenCode handoffs.

---

## Activity monitoring (`monitor`, `track`)

Polls keyboard / mouse / active-window state every 50ms (via
`device_query`) and snapshots the screen on a configurable cadence.
Counters drive automation triggers.

```bash
i-self monitor start                 # spawns the background poller
i-self monitor stop
i-self monitor suggestions           # surface what the analyzer flagged
i-self track summary --days 7        # weekly activity summary
```

**macOS:** the first run prompts for Accessibility permission so the
system can report keyboard/mouse state for non-foreground apps. Without
it, counters stay at zero — and so do automation triggers that depend
on them.

**Limitations.** Screenshots are saved unredacted to
`~/.i-self/screenshots/`. If your screen routinely shows secrets, set
`screenshot_interval = 0` to disable, or wipe the directory regularly.

---

## Automation rules (`automate`)

Trigger-based rules persisted in `~/.i-self/automation.toml`. Each rule
has a trigger (event + threshold) and a list of actions.

```bash
i-self automate init                 # write default rules
i-self automate ls
i-self automate add --name "Meeting alert" --trigger meeting-silence \
                    --duration 60 --action notify --message "Quiet for a min"
i-self automate test --event idle --value 600    # actually fires matched actions
```

### Triggers

| Type | Description |
|---|---|
| `idle` | User idle ≥ N seconds |
| `meeting-silence` | No meeting activity for N seconds |
| `no-activity` | No keyboard/mouse for N seconds |
| `activity-spike` | Keystrokes-per-window above threshold |
| `incoming-call` | Detect incoming call (system events; platform-dependent) |

### Actions

| Action | Status | What it does |
|---|---|---|
| `notify` || Desktop notification via `osascript` / `notify-send` / PowerShell |
| `telegram` || POST to Telegram Bot API |
| `whatsapp` || Cloud WhatsApp Business API |
| `log` || Tracing log line |
| `run-command` || Runs the command via `sh -c`; stdout/stderr captured to logs |
| `exit-meeting` | ⚠️ stub | Logs only |
| `start-recording` | ⚠️ stub | Logs only |
| `stop-recording` | ⚠️ stub | Logs only |
| `send-message` | ⚠️ stub | Logs only — distinct from `telegram`/`whatsapp` |

Required env for messaging actions:
- Telegram: `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`
- WhatsApp: `WHATSAPP_API_KEY`, `WHATSAPP_PHONE`, `WHATSAPP_TO_PHONE`

---

## Vulnerability scanner (`vuln`)

Backed by [OSV](https://osv.dev). Reads lockfiles, calls
`https://api.osv.dev/v1/query` per dependency, surfaces results.

```bash
i-self vuln scan --path ./my-project
i-self vuln check lodash 4.17.20 --ecosystem npm
```

**Supported lockfiles:** `Cargo.lock`, `package-lock.json` (lockfile
versions 1, 2, 3). Other names are detected but only those two are
parsed today. Pip / Go / Maven / NuGet are flagged for future work.

**Severity** is taken from `database_specific.severity` when present
(GHSA records always carry this), otherwise computed from a CVSS v3
vector via the implementation in
[src/vuln/mod.rs](src/vuln/mod.rs).
Bucketing follows the official ratings: Low (<4.0), Medium (4.0–6.9),
High (7.0–8.9), Critical (≥9.0).

**Exit code 2 on partial scans.** If any per-package OSV lookup fails
(timeout, 5xx), the scan is incomplete and "0 vulnerabilities" is not
safe to trust. Failures are listed on stderr; CI scripts can grep the
exit code to gate. The summary line shows ⚠️ INCOMPLETE rather than ✅
in this case.

---

## Cloud sync (`sync`)

S3-compatible backup of `~/.i-self/` — single backend covers every
provider speaking the S3 API.

```bash
export ISELF_SYNC_BUCKET=my-iself
export ISELF_SYNC_ENDPOINT=http://localhost:9000     # MinIO; AWS leaves this unset
export AWS_ACCESS_KEY_ID=minio
export AWS_SECRET_ACCESS_KEY=minio-secret
i-self sync push      # upload ~/.i-self/ to bucket
i-self sync pull      # download bucket back to ~/.i-self/
i-self sync status    # show effective config
```

| Provider | Endpoint |
|---|---|
| AWS S3 | (leave unset) |
| MinIO | `http://localhost:9000` (or your URL) |
| Cloudflare R2 | `https://<account-id>.r2.cloudflarestorage.com` |
| DigitalOcean Spaces | `https://<region>.digitaloceanspaces.com` |
| Backblaze B2 | `https://s3.<region>.backblazeb2.com` |

Credentials follow the standard AWS chain (env → `~/.aws/credentials` →
IAM). Other env-var overrides: `ISELF_SYNC_REGION`, `ISELF_SYNC_PREFIX`,
`ISELF_SYNC_VHOST_STYLE=1` (force virtual-hosted-style; only AWS).

`[cloud]` in `config.toml` is the persistent equivalent — fields
`bucket`, `region`, `endpoint`, `prefix`, `access_key`, `secret_key`.
**Env wins** over config so a single shell can override without rewriting
the file.

---

## Web dashboard / REST API (`dashboard`, `api`)

`i-self dashboard` and `i-self api` start the same axum server. The
"dashboard" subcommand binds 8080 and serves the HTML UI; `api` is an
alias bound to 3000. Routes:

- `GET /healthz` — always public
- `GET /` — HTML dashboard
- `GET /api/profile`, `GET /api/stats`
- `POST /api/search`, `GET /api/search/stats`
- `POST /api/ai/{ask,explain,generate}` — bearer-auth + per-IP rate-limited
- `GET /api/teams`, `GET /api/teams/:name`, `POST /api/teams/:name/aggregate`

**Default bind is `127.0.0.1`.** Auth is loopback-trust by default — any
local process can call the API.

**Network exposure requires a token.** Set `ISELF_BIND` to a non-loopback
address and the server demands `ISELF_API_TOKEN`. If neither
`ISELF_API_TOKEN` env nor `~/.i-self/api_token` file is present, a 256-bit
hex token is auto-generated and written to `~/.i-self/api_token` (mode
0600 on Unix). The token is also printed once at startup.

```bash
export ISELF_BIND=0.0.0.0
export ISELF_API_TOKEN=$(openssl rand -hex 32)        # or skip → auto-generated
i-self dashboard --port 8080
# Clients send: Authorization: Bearer $ISELF_API_TOKEN
```

**Browser bootstrap.** Open the dashboard with `?token=<token>` in the
URL once. The dashboard JS strips the token from the URL via
`history.replaceState`, stores it in localStorage, and adds it to every
API call as `Authorization: Bearer <token>`. On 401, the JS prompts the
user for a fresh token and reloads.

**Rate limiting.** `/api/ai/*` is per-IP rate-limited (default: 10 req/sec,
burst 12). Tunable via `ISELF_AI_RATE_PER_SECOND` / `ISELF_AI_RATE_BURST`.
This is in addition to the bearer token — a leaked token still can't
translate to unbounded LLM spend.

**Request logging.** Every request is logged via
`tower_http::trace::TraceLayer`. The `Authorization` header is *not* in
default span fields; the `?token=...` query string *is* (tradeoff for
browser bootstrap), and the dashboard JS strips it on first load.

---

## Snippets (`snippet`)

Local code snippet manager. Stores snippets in `~/.i-self/snippets.json`.

```bash
i-self snippet add "Tokio retry" "$(cat retry.rs)" rust --tags "async,tokio"
i-self snippet ls --language rust
i-self snippet ls --tag tokio --favorites
i-self snippet search "http"
i-self snippet show <id>
```

---

## Messaging (`message`)

Two distinct paths. **Outgoing** messages (i-self → your phone) go
through the `automation` action handlers. **Incoming** messages (your
phone → i-self) go through the `message listen` command.

### Outgoing — automation actions

The `telegram` / `whatsapp` automation actions read these env vars
each time they fire:

- Telegram: `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`
- WhatsApp: `WHATSAPP_API_KEY`, `WHATSAPP_PHONE` (your sender),
  `WHATSAPP_TO_PHONE` (recipient)

```bash
i-self automate add --name "Idle alert" --trigger idle --duration 300 \
                    --action telegram --message "you've been idle"
i-self automate test --event idle --value 600   # actually sends
```

### Incoming — `i-self message listen`

A real Telegram bot listener: long-polls the bot inbox, dispatches
slash-commands, replies in the same chat. Run it in the foreground
(Ctrl+C to stop) or under launchctl/systemd if you want it persistent.

```bash
export TELEGRAM_BOT_TOKEN=<from BotFather>
export TELEGRAM_ALLOWED_CHAT_IDS=<your chat id>     # comma-separated
i-self message listen
```

**Allowlist is mandatory.** The listener refuses to start without
`TELEGRAM_ALLOWED_CHAT_IDS` because `/screenshot` would otherwise leak
your desktop to anyone who finds the bot. To bootstrap: send any text
to your bot, then check `https://api.telegram.org/bot<TOKEN>/getUpdates`
to find your chat id.

#### Commands

| Command | What it does |
|---|---|
| `/help` (or `/start`) | Show available commands |
| `/status` | Profile loaded? Embedder backend? Visible session count |
| `/sessions [N]` | List N most recent agent sessions across all providers (default 10, capped at 50) |
| `/share <id>` | Render a session as Markdown and reply with it |
| `/activity` | Current active window + timestamp |
| `/screenshot` | Capture and reply with a photo |

#### Persistence

Last-seen `update_id` is stored at `~/.i-self/messaging_state.json` so
restarts don't re-process old messages. Long-poll timeout is 25s; on
Telegram-side errors the listener backs off 5s and retries.

### What about WhatsApp listen?

Not implemented. WhatsApp Cloud API delivers incoming messages via
**webhooks**, not polling — that requires a public HTTPS endpoint.
Practical path: run `i-self dashboard` on a real domain and add a
WhatsApp webhook handler in a future change.

### `message send` and `message config`

`i-self message send` and `i-self message config` are scaffold commands
that predate the listener. Both work but are limited:

- `send` reads env vars and tries to dispatch; it depends on
  `allowed_chat_ids` being set in the in-memory config, which the CLI
  doesn't currently populate. **Treat as a stub** — use the automation
  `telegram`/`whatsapp` actions for one-shot sends instead.
- `config` prints which env vars to set.

---

## Team aggregation (`team`)

Combine multiple developer profiles to surface team-wide skill coverage,
knowledge silos, and bus-factor risk.

```bash
i-self team add alice path/to/alices/profile.json
i-self team aggregate engineering
i-self team show engineering
```

**Limitations.** This is a JSON-aggregation feature — it doesn't fetch
profiles from a central server, so each developer has to share their
`profile.json` (or use `i-self sync` to mirror it through a shared
bucket).

---

## Built-in analyzers (`plugin`)

```bash
i-self plugin list
```

Three compiled-in analyzers:
- **security_patterns** — high-recall regex hits for `eval(`, `exec(`,
  hardcoded passwords / secrets / api_keys.
- **performance_patterns** — Python-specific anti-patterns
  (unnecessary `.keys()`, string concat in loops, `== None`).
- **documentation** — flags long functions with no comments / docstrings.

**There is no dynamic plugin loader.** The 1.0.0 README claimed one;
that code walked `.so` files and `println!`-ed their names without ever
`dlopen`-ing them. The 0.4.x release deleted the pretense and renamed
the surface area honestly. To add an analyzer, implement
`AnalyzerPlugin` in [src/plugins/mod.rs](src/plugins/mod.rs) and
recompile.

---

## Things that look like features but aren't

Honest list, current as of 0.4.1:

- **Automation `exit-meeting`, `start-recording`, `stop-recording`,
  `send-message`** — defined in the rule schema, advertised in the UI,
  but the action handlers only `info!` log. `notify`, `telegram`,
  `whatsapp`, `log`, and `run-command` are real.
- **Cursor / Copilot Chat / Cline session enumeration.** These tools
  store sessions in editor globalState / IndexedDB. Not file-addressable.
  Use `share import --target clipboard` to get a paste-friendly Markdown
  blob instead.
- **OpenCode session import.** Provider works (read), importer is
  intentionally absent (write). See the [share matrix]#provider-matrix.
- **Pip / Go / Maven / NuGet vuln scanning.** Lockfiles are detected but
  only Cargo.lock and package-lock.json are parsed. The OSV call path is
  ecosystem-agnostic; what's missing is the lockfile parser.
- **Incremental embedding reindex.** `i-self index` always re-embeds
  every file; for big monorepos this is slow.
- **Any Web 1.0 tool with no programmatic export** (ChatGPT.com session
  pages, Claude.ai conversations, Gemini chat). Use the manual data-export
  flow, then point `ISELF_GENERIC_DIR` at the unzipped JSON.

---

For the architecture overview and per-module breakdown, see the
"Architecture" section of the [README](README.md#architecture). For the
list of breaking changes between releases, [CHANGELOG.md](CHANGELOG.md).