# Doctor and troubleshooting

> doctor checks (workspace, schema version, kinds, artifacts, references, onboarding), common failures (WorkspaceNotFound, Zod validation, missing search index), and factory/reindex recovery steps.

- Repository: superdesigndev/loopany
- GitHub: https://github.com/superdesigndev/loopany
- Human docs: https://grok-wiki.com/public/docs/superdesigndev-loopany-97bd9ab97ae8
- Complete Markdown: https://grok-wiki.com/public/docs/superdesigndev-loopany-97bd9ab97ae8/llms-full.txt

## Source Files

- `src/commands/doctor.ts`
- `src/core/engine.ts`
- `src/commands/search.ts`
- `src/commands/reindex.ts`
- `test/cli.e2e.test.ts`
- `INSTALL_FOR_AGENTS.md`
- `src/commands/migrate.ts`

---

---
title: "Doctor and troubleshooting"
description: "doctor checks (workspace, schema version, kinds, artifacts, references, onboarding), common failures (WorkspaceNotFound, Zod validation, missing search index), and factory/reindex recovery steps."
---

`loopany doctor` runs deterministic integrity checks over `$LOOPANY_HOME` and exits **0** when every check with status `fail` is clear; **warnings** (`warn`) do not fail the command. The command bootstraps with `skipVersionCheck: true`, so it can report schema mismatches instead of throwing `SchemaVersionMismatchError`. Search health is separate: `loopany search` warns when `search.db` is missing; rebuild with `loopany reindex`.

## Command surface

```bash
loopany doctor [--format human|json]
```

| Output | Behavior |
|--------|----------|
| Human (default) | Columnar check lines with `✓` / `⚠` / `✗` and indented `problems` |
| JSON | `{ workspace, checks[], ok }` — each check has `name`, `status`, `detail`, optional `problems[]` |
| Exit code | `0` if `ok: true`; `1` if any check has `status: "fail"` |

<ParamField body="--format" type="human | json">
Human is the default. JSON is intended for agents and weekly review scripts (`loopany doctor --format json`).
</ParamField>

<ResponseField name="ok" type="boolean">
`true` only when no check has `status: "fail"`. Warnings still yield `ok: true`.
</ResponseField>

## What doctor checks

Doctor is **integrity-only**: no LLM passes, no body-content heuristics (TODO scans belong in reflect), and **no `search.db` probe**.

```mermaid
flowchart TB
  subgraph bootstrap["Bootstrap (doctor only)"]
    B["bootstrap({ skipVersionCheck: true })"]
  end
  subgraph checks["Deterministic checks"]
    W[workspace]
    SV[schema version]
    K[kinds]
    A[artifacts + Zod]
    R[references / dangling edges]
    O[onboarding: self + active mission]
    MC[mission coverage — warn]
    DC[domain coverage — warn]
  end
  B --> W --> SV --> K --> A --> R --> O --> MC --> DC
```

| Check | Status on problem | What it validates |
|-------|-------------------|-------------------|
| `workspace` | always `ok` if doctor runs | Bootstrap succeeded; reports `engine.root` |
| `schema version` | `fail` | `config.yaml` `schemaVersion` vs binary `SCHEMA_VERSION` (`0.2.0`) |
| `kinds` | `fail` | Every kind under `kinds/` (and enabled domain packs) parses; lists `registry.issues` |
| `artifacts` | `fail` | Every indexed artifact’s frontmatter passes its kind’s dynamic Zod schema |
| `references` | `fail` | No dangling edges in `references.jsonl` or implicit graph (missing `from`/`to`) |
| `onboarding` | `fail` | Artifact id `self` exists; ≥1 `mission` with `status: active` |
| `mission coverage` | `warn` | Each `task` has a `mentions[]` entry pointing at a mission id (skipped if no missions) |
| `domain coverage` | `warn` | Artifacts with `domain` set use a value in `enabled_domains` |

<Warning>
A fresh `loopany init` workspace fails **onboarding** until you create `--slug self` person and an active mission — matching `ONBOARDING.md` Phase 3 and e2e expectations.
</Warning>

### Onboarding expectations

Doctor requires:

- `loopany artifact create --kind person --slug self ...`
- At least one `loopany artifact create --kind mission --status active ...`

Legacy v0.1 ids like `prs-self` are migrated to `self` by `skills/migrations/v0.1.0-to-v0.2.0/`; doctor keys off the v0.2 slug id `self`.

## What doctor does not check

| Gap | Where to handle it |
|-----|-------------------|
| Missing or stale `search.db` | `loopany reindex`; `loopany search` stderr hint |
| Resolver / skill injection registered | Roadmap only (`INSTALL_FOR_AGENTS.md`); not in doctor today |
| Semantic body quality | `loopany-reflect` skill |
| Auto-reindex after each write | By design — reindex is explicit in v1 |

## Bootstrap gates vs doctor

Most commands call `bootstrap()` **with** the schema guard. Doctor and migrate are exceptions.

```text
$LOOPANY_HOME/
  kinds/          ← must exist or WorkspaceNotFoundError
  config.yaml     ← schemaVersion matched unless skipped
  artifacts/
  references.jsonl
  search.db       ← optional; not part of doctor
```

| Error | When | Message / recovery |
|-------|------|-------------------|
| `WorkspaceNotFoundError` | No `kinds/` under workspace root | `No loopany workspace at {root}. Run loopany init first.` |
| `SchemaVersionMismatchError` | `config.schemaVersion() !== SCHEMA_VERSION` on normal bootstrap | Points at `skills/migrations/v{from}-to-v{to}/SKILL.md` and `loopany migrate v{from}-to-v{to}` |
| Doctor still runs on mismatch | `skipVersionCheck: true` | `schema version` check `fail` with `run loopany migrate v…-to-v…` in `problems` |

<Info>
`LOOPANY_SKIP_VERSION_CHECK=1` also bypasses the guard (for migration scripts). `loopany migrate` always skips the check so it can describe the next migration on stale workspaces.
</Info>

Absent `schemaVersion` in `config.yaml`, the runtime assumes **`0.1.0`** (`ASSUMED_LEGACY_VERSION`) until `init` or migration writes the current version.

## Common failures and fixes

### WorkspaceNotFound

```bash
loopany init
# or
LOOPANY_HOME=/path/to/brain loopany init
```

Default root: `~/loopany` unless `LOOPANY_HOME` is set.

### Schema version mismatch

Symptom on most commands:

```text
Error: Workspace schema is v0.1.0 but this binary expects v0.2.0. Read skills/migrations/v0.1.0-to-v0.2.0/SKILL.md and run loopany migrate v0.1.0-to-v0.2.0.
```

<Steps>
<Step title="Inspect without crashing">
Run `loopany doctor` or `loopany migrate` — both bypass the version guard and report the gap.
</Step>
<Step title="Discover migration">
```bash
loopany migrate
loopany migrate v0.1.0-to-v0.2.0
```
`migrate` prints `SKILL.md` and ordered `bun run …/scripts/*.ts [--apply]` paths; the CLI does not auto-run migrations.
</Step>
<Step title="Run scripts, verify">
Execute migration scripts per the skill (typically dry-run first, then `--apply`). Finish with `loopany doctor` — `schema version` should be `ok`.
</Step>
</Steps>

Pre-migration doctor failures should be fixed **before** migrating (`skills/migrations/v0.1.0-to-v0.2.0/SKILL.md`).

### Zod validation (CLI writes)

`artifact create`, `set`, and `status` validate input at write time. Failures surface as:

```text
Invalid input:
  - status: Invalid enum value...
```

Doctor re-validates **all** on-disk artifacts: problems look like `{id}: {first zod message}`. Fix by correcting frontmatter (`artifact set`) or editing the markdown file to match `kinds/<kind>.md`, then re-run doctor.

### Broken kind definitions

Kind load errors are **tolerated at boot** but fail the **kinds** check:

```text
kinds/some-kind.md: <parse or schema error>
```

Repair the kind markdown under `~/loopany/kinds/` (or domain `domains/<name>/kinds/`), then doctor again.

### Dangling references

Sources include:

- `loopany refs add` to a missing id
- Hand-edited `references.jsonl`
- Body `[[wiki-links]]` to non-existent slugs (indexed as implicit edges)

Doctor lists lines like:

```text
dangling: task-foo → bar-baz (led-to)
```

Create the target artifact, remove the edge, or fix the link text.

### Onboarding incomplete

```text
self person artifact missing — run onboarding (Phase 3 step 2)
no active mission — run onboarding (Phase 3 step 3)
```

Complete onboarding artifacts or follow `ONBOARDING.md` with your agent host.

### Mission / domain warnings

These set `status: "warn"`; exit code stays **0**.

- **Mission coverage:** add `--mentions <mission-id>` on tasks, or accept orphan tasks.
- **Domain coverage:** `loopany domain enable <name>` or clear/remove invalid `domain` on artifacts.

## Search index: missing or stale

`loopany search` does **not** error when `search.db` is absent:

```text
loopany: no search index found — run `loopany reindex` first.
```

Stdout is `[]`; exit code **0** (scripts can probe safely).

### Reindex

```bash
loopany reindex [--force] [--no-embed]
```

| Flag | Effect |
|------|--------|
| (none) | Incremental: skip artifacts whose mtime matches `search.db` |
| `--force` | Delete `search.db` and rebuild FTS5 + embeddings from scratch |
| `--no-embed` | Use `NoopEmbedder` (fast CI; keyword/FTS still work) |

<ResponseField name="stdout JSON" type="object">
`{ indexed, skipped, removed, embedder: "transformers" | "noop" }`. Creates `$LOOPANY_HOME/search.db` on first run. Artifact CRUD does not auto-update the index in v1.
</ResponseField>

<Steps>
<Step title="Populate after init or bulk edit">
```bash
loopany reindex --no-embed   # quick smoke / CI
loopany reindex              # full hybrid (downloads embed model on first run)
```
</Step>
<Step title="Verify search">
```bash
loopany search "your query" --kind note --limit 10
```
</Step>
<Step title="Recover deleted artifacts in index">
Re-run `reindex` without `--force`; removed on-disk files are dropped from the DB (`removed` count in JSON).
</Step>
</Steps>

## Factory UI (exploration, not repair)

```bash
loopany factory [--port N] [--host H] [--no-open]
```

- Default: `http://127.0.0.1:4242`, opens browser unless `--no-open`
- Requires **normal** bootstrap (schema version must match)
- Read-only walkable view of nodes/edges from the same index doctor uses for references (not search)

Use factory to **see** graph shape after doctor is green; use **reindex** when search is empty. Factory does not fix validation or migration issues.

## Operational playbooks

### After `loopany init` or agent install

```bash
loopany doctor --format json
# fix onboarding → kinds → artifacts → references
loopany reindex --no-embed
loopany search "smoke" --limit 3
```

### Weekly review (agent)

Per `skills/loopany-review/references/weekly.md`: run `loopany doctor --format json`, summarize failures, propose fixes — **do not auto-fix** without user confirmation.

### Stale workspace on new binary

1. `loopany doctor` → read `schema version` problems  
2. `loopany migrate` → run scripted migration with git snapshot per skill README  
3. `loopany doctor` → all `fail` checks clear  
4. `loopany reindex [--force]` if you rely on search  

### Machine-readable health

```bash
loopany doctor --format json | jq '.ok, .checks[] | select(.status=="fail")'
```

Exit **1** when `ok` is false — suitable for cron or CI **after** onboarding is complete.

## JSON report shape (reference)

```json
{
  "workspace": "/Users/you/loopany",
  "ok": false,
  "checks": [
    {
      "name": "schema version",
      "status": "fail",
      "detail": "workspace v0.1.0, binary expects v0.2.0",
      "problems": ["run `loopany migrate v0.1.0-to-v0.2.0`"]
    }
  ]
}
```

Human output capitalizes check names and pads columns; semantics match JSON.

<Tip>
`VERSION` (package semver) and `SCHEMA_VERSION` (workspace format) drift independently — bumping the CLI does not always require migration; bumping `SCHEMA_VERSION` always ships a `skills/migrations/v*-to-v*/` directory.
</Tip>

## Related pages

<CardGroup>
<Card title="Workspace setup" href="/workspace-setup">
Init, bundled kinds, onboarding, and first doctor pass.
</Card>
<Card title="Schema migration" href="/schema-migration">
`SchemaVersionMismatchError`, migrate discovery, and v0.1.0→v0.2.0 scripts.
</Card>
<Card title="Graph, search, and scheduling" href="/graph-search-commands">
`reindex`, `search`, `factory`, refs/trace, and followups.
</Card>
<Card title="Kinds and validation" href="/kinds-and-validation">
Kind markdown, dynamic Zod schemas, and immutable write rules.
</Card>
<Card title="Configuration reference" href="/configuration-reference">
`LOOPANY_HOME`, `LOOPANY_SKIP_VERSION_CHECK`, and `config.yaml` keys.
</Card>
<Card title="CLI reference" href="/cli-reference">
Full command surface and JSON stdout conventions.
</Card>
</CardGroup>
