# `gaal index`

Purpose: index maintenance and corpus mutation commands.

## Usage

```bash
gaal index <SUBCOMMAND> [OPTIONS]
```

## `index backfill`

Usage:

```bash
gaal index backfill [OPTIONS]
```

Flags:

- `--engine <claude|codex|gemini|agy|hermes>`
- `--since <date|timestamp>`
- `--force`
- `--with-markdown`
- `--output-dir <path>`: implies `--with-markdown`
- `-H`, `--human`

Output:

- JSON summary: `indexed`, `skipped`, `errors`, optional `markdown_written`, optional `markdown_skipped`
- Progress lines go to stderr during the run

### Incremental behavior

`index backfill` is incremental. Each engine keeps its own mtime cursor in the `meta` SQLite table, for example `backfill:claude`, `backfill:codex`, `backfill:gemini`, `backfill:agy`, and `backfill:hermes`. On every run, discovery for an engine skips files whose on-disk mtime is older than `cursor - 10s` before any head-read, JSON parse, or SQLite lookup. The 10-second safety margin covers actively-appending session files whose mtime is close to wall-clock.

Cursor advancement rules:

- A cursor advances only when that engine's pass completes successfully.
- If one engine stalls, its cursor stays put and the next run retries the missed window. Other engines still advance independently.
- First run (no cursor) and DB wipes fall through to a full scan — the cursor is absent, so no mtime gate applies.
- `--engine`, `--since`, and `--force` are all additive on top of the mtime gate. `--engine claude` only advances the Claude cursor. `--since` narrows further. `--force` re-indexes already-known rows but still honors the mtime gate for discovery.

### Agy discovery behavior

Agy discovery scans Antigravity brain directories, prefers non-empty
`transcript_full.jsonl`, and falls back to `transcript.jsonl`. Native agy IDs
are the first 8 characters of the brain UUID. JSONL parsing also detects copied
agy transcripts by record shape. Outside the native brain path, copied agy files
preserve engine identity; session identity comes from explicit content IDs when
present, otherwise Gaal falls back to the copied filename.

Optional agent-mux sidecars can fill model or missing cwd for matching agy
sessions. Indexing does not require agent-mux.

### Troubleshooting: stuck cursor

If a backfill cursor ever gets stuck (e.g., an engine that keeps failing partway through and you want to force it to re-evaluate everything), delete the cursor rows and rerun:

```bash
sqlite3 ~/.gaal/index.db "DELETE FROM meta WHERE key LIKE 'backfill:%'"
gaal index backfill
```

This clears the per-engine cursors without touching indexed sessions or facts. The next run performs a full-scan baseline and rewrites the cursors on success.

## `index status`

Usage:

```bash
gaal index status
```

Flags:

- `-H`, `--human`

Real example:

```bash
$ gaal index status
{
  "db_path": "/home/alex/.gaal/index.db",
  "db_size_bytes": 387366912,
  "facts_total": 249747,
  "handoffs_total": 871,
  "last_indexed_at": "2026-03-29T10:46:56.904Z",
  "newest_session": "2026-03-29T10:46:13.988Z",
  "oldest_session": "2026-01-08",
  "sessions_by_engine": { "claude": 4277, "codex": 2925, "agy": 12 },
  "sessions_total": 7214
}
```

## `index reindex`

Usage:

```bash
gaal index reindex <ID>
```

Output:

- JSON summary with `session_id` and `facts`

## `index prune`

Usage:

```bash
gaal index prune --before <DATE>
```

Flags:

- `--before <date>`
- `-H`, `--human`

Output:

- JSON object with `before` and `deleted`

## `index recover-orphans`

One-off recovery for subagent JSONL files orphaned when Claude Code's 30-day cleanup deletes parent session files. Scans `~/.claude/projects/` for subagent files whose parent session is missing or unlinked, creates ghost parent records tagged `_recovered`, and indexes the orphaned subagents.

Usage:

```bash
gaal index recover-orphans [--dry-run]
```

Flags:

- `--dry-run`: preview orphan counts without writing to the database

Output:

- Dry-run: `{ "orphan_files": N, "parent_groups": N, "dry_run": true }`
- Live: `{ "ghosts_created": N, "subagents_indexed": N, "errors": N }`

Run with `--dry-run` first. This is an admin-only recovery tool, not part of normal workflow.

## Operational Note

Any command that mutates facts rebuilds the Tantivy index afterwards. Rebuild triggers include `gaal index backfill` (only when at least one engine indexed new sessions), `gaal index reindex`, `gaal index prune`, and `gaal index recover-orphans`.

# `gaal tag`

Purpose: add, remove, or list session tags.

## Usage

```bash
gaal tag [OPTIONS] [ID] [TAGS]...
```

## Flags

- `--remove`: remove tags instead of adding them
- `-H`, `--human`

## Modes

- `gaal tag ls`: list all distinct tags
- `gaal tag <id> <tag1> <tag2>`: add tags
- `gaal tag <id> <tag1> --remove`: remove tags

## Output

- `tag ls` returns a JSON array of strings
- tag mutations return `{ "session_id": "...", "action": "added|removed", "tags": [...] }`

## Real Example

```bash
$ gaal tag ls
[
  "bot",
  "build-gaal",
  "coordinator",
  "legacy",
  "test-tag",
  "worker"
]
```

## Related Commands

- [`gaal ls`](./fleet-view.md)
- [`gaal inspect`](./drill-down.md)
