# Build and test

> bun install, typecheck, bun test unit/e2e, compiled binary via bun build --compile, and skill-regression.sh requirements (claude CLI, API key).

- 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

- `package.json`
- `tsconfig.json`
- `README.md`
- `test/cli.e2e.test.ts`
- `test/skill-regression.sh`
- `test/helpers/cli.ts`
- `CLAUDE.md`

---

---
title: "Build and test"
description: "bun install, typecheck, bun test unit/e2e, compiled binary via bun build --compile, and skill-regression.sh requirements (claude CLI, API key)."
---

loopany ships as a Bun-first TypeScript ESM project: `package.json` defines `install`, `typecheck`, `test`, `build`, and `dev` scripts; the default verification path is `bun install`, `bun run typecheck`, and `bun test` (235 tests across 15 files). A compiled CLI lands at `bin/loopany` via `bun build --compile`. Agent-skill behavior is validated separately by `test/skill-regression.sh`, which drives Claude Code with live API calls.

## Prerequisites

| Requirement | Used for |
|-------------|----------|
| [Bun](https://bun.sh) | Runtime, test runner, bundler, and `bun build --compile` |
| TypeScript 5.x (devDependency) | `bun run typecheck` (`tsc --noEmit`) |
| Temp filesystem access | E2E tests create scratch workspaces under the OS temp dir |
| `claude` CLI (≥ 2.0) + Anthropic API credentials | `test/skill-regression.sh` only |

`tsconfig.json` targets ES2022, `moduleResolution: "bundler"`, `strict: true`, and includes `src/**/*` and `test/**/*`. There is no `engines` field in `package.json`; development and tests assume Bun, not Node, for spawning the CLI and running the suite.

## Install dependencies

```bash
bun install
```

This pulls runtime deps (`yaml`, `zod`, `@huggingface/transformers`) and dev deps (`typescript`, `@types/bun`). For a global `loopany` command during local development, also run `bun link` after install (see [Installation](/installation)).

## npm scripts

| Script | Command | Purpose |
|--------|---------|---------|
| `dev` | `bun run src/cli.ts` | Run the CLI from source without compiling |
| `build` | `bun build --compile --outfile bin/loopany src/cli.ts` | Produce a single static binary |
| `test` | `bun test` | Full unit + E2E suite |
| `typecheck` | `tsc --noEmit` | Static type check (no emit) |

<Note>
`CLAUDE.md` mentions `bun run test:e2e`, but that script is **not** defined in `package.json`. Run E2E files explicitly (see below) or use `bun test` for the full suite.
</Note>

## Typecheck

```bash
bun run typecheck
```

Runs `tsc --noEmit` against `src/` and `test/` with Bun types. A clean run produces no output and exit code `0`.

## Test suite overview

`bun test` discovers all `*.test.ts` files under `test/`. The repo uses filename convention to separate layers:

```text
test/
├── *.test.ts              # unit / module tests (11 files)
├── *.e2e.test.ts          # CLI subprocess + real workspace (4 files)
├── helpers/cli.ts         # spawns `bun src/cli.ts` with LOOPANY_HOME
└── skill-regression.sh    # optional; Claude Code + API (not bun test)
```

```mermaid
flowchart TB
  subgraph bun_test["bun test"]
    U[Unit tests<br/>artifact-store, kind-registry, search-store, …]
    E[E2E tests<br/>cli.e2e, search.e2e, scenario.e2e, migration e2e]
  end
  subgraph harness["E2E harness"]
    H[test/helpers/cli.ts]
    CLI[src/cli.ts via Bun.spawn]
    WS["$LOOPANY_HOME temp dir"]
  end
  subgraph skill_reg["skill-regression.sh"]
    CC[claude -p]
    SK[skills: core, capture, reflect, review]
  end
  U --> bun_test
  E --> H --> CLI --> WS
  skill_reg --> CC --> CLI
  skill_reg --> SK
```

### Full run

```bash
bun test
```

Typical result: **235 pass**, **0 fail**, across **15 files** (~45–50s on a developer machine). The suite uses real directories and files; E2E tests do not mock the filesystem.

### Unit tests only

Unit files omit the `.e2e.` segment in the filename. Examples: `test/slug.test.ts`, `test/kind-registry.test.ts`, `test/search-store.test.ts`, `test/artifact-store.test.ts`, `test/migration-framework.test.ts`.

Run a subset:

```bash
bun test test/slug.test.ts test/kind-registry.test.ts
```

Roughly **136 tests** live in the 11 non-`.e2e.` files (total minus the four E2E files).

### E2E tests only

Four files, **99 tests** total:

| File | Focus |
|------|--------|
| `test/cli.e2e.test.ts` | `init`, `artifact/*`, `refs`, `trace`, `domain`, `followups`, `search`, `doctor`, JSON stdout |
| `test/search.e2e.test.ts` | `reindex` / `search` with `--no-embed` (no ONNX download in CI-style runs) |
| `test/scenario.e2e.test.ts` | Full lifecycle: signal → person → task → refs → followups → done + `## Outcome` |
| `test/migration-v0.1-to-v0.2.e2e.test.ts` | v0.1 synthetic workspace → five migration scripts → doctor-clean v0.2 |

Run E2E only:

```bash
bun test \
  test/cli.e2e.test.ts \
  test/search.e2e.test.ts \
  test/scenario.e2e.test.ts \
  test/migration-v0.1-to-v0.2.e2e.test.ts
```

### E2E harness behavior

`test/helpers/cli.ts` resolves `src/cli.ts`, spawns `bun` with `LOOPANY_HOME` set to a fresh temp directory from `newWorkspace()`, and returns `{ stdout, stderr, code }`. Every CLI E2E test exercises the same entrypoint agents use in development (`bun run src/cli.ts`), not the compiled binary.

<Info>
Search E2E intentionally passes `--no-embed` so runs avoid downloading the Hugging Face ONNX embedding model. Semantic embedding behavior is covered in `test/search-store.test.ts` with `NoopEmbedder` / vector math; production `reindex` without `--no-embed` uses `TransformersEmbedder` in `src/core/embedder.ts`.
</Info>

## Compiled binary

```bash
bun run build
```

Equivalent to:

```bash
bun build --compile --outfile bin/loopany src/cli.ts
```

Output: `bin/loopany` (single executable, on the order of tens of MB). `bin/` is listed in `.gitignore` — build locally; do not expect it in git.

Verify:

```bash
./bin/loopany --help
```

Distribution path for agents is still commonly `bun link` + `loopany` from `src/cli.ts` (`package.json` `bin` points at `./src/cli.ts`). The compiled binary is the planned single-artifact ship target described in `CLAUDE.md`.

## Skill regression (`test/skill-regression.sh`)

Separate from `bun test`. Exercises **four** bundled skills (`loopany-core`, `loopany-capture`, `loopany-reflect`, `loopany-review`) through **10** Claude Code scenarios with real `claude -p` calls.

### Prerequisites

- `claude` in `PATH` (Anthropic Claude Code CLI, documented as ≥ 2.0 in the script header)
- Active Anthropic API configuration for `claude`
- `bun` and repo checkout (script uses `bun $REPO_ROOT/src/cli.ts`, not requiring `loopany` on `PATH`)

`loopany-resolver` is not symlinked into the regression harness; scenarios target the four workflow skills above.

### Usage

```bash
./test/skill-regression.sh              # all 10 scenarios
./test/skill-regression.sh 4            # scenario 4 only
./test/skill-regression.sh --dry-run    # print plan; skip claude calls
```

### What the script does

<Steps>
<Step title="Prepare temp environment">
Creates `/tmp/loopany-skill-regression.*` with a fake `HOME` (skills under `~/.claude/skills/`), sets `LOOPANY_HOME` to a fresh workspace, symlinks the four skills.
</Step>
<Step title="Seed workspace">
Runs `loopany init`, creates a test `mission` artifact so bootstrap checks pass.
</Step>
<Step title="Run scenarios">
Each scenario calls `claude -p` with `--bare`, `--permission-mode bypassPermissions`, `--add-dir` for workspace and repo, `--max-turns 15`, and tool allowlist `Bash Read Write Edit Glob Grep`.
</Step>
<Step title="Assert workspace state">
Checks artifact counts, file patterns, quality-gate behavior (e.g. scenario 4 must not create artifacts), reflect threshold (scenario 8), signal→task upgrade (scenario 9).
</Step>
</Steps>

Expect **~5 minutes** for a full pass (10 API-backed agent turns). README notes isolated runs: each scenario shares one seeded workspace, not 10 separate inits.

On failure, the script **disables cleanup** (`trap - EXIT`) and prints log paths (`$TMPBASE/scenario*.log`) so you can inspect Claude output. Exit code `1` when any assertion fails.

### Scenario map

| # | Skill / theme | Validates |
|---|----------------|-----------|
| 1 | loopany-core | Signal created via natural language + CLI |
| 2 | loopany-core | Task created and moved to `running` |
| 3 | loopany-core | Note (fallback kind) |
| 4 | loopany-capture | Quality gate skips trivial typo fix |
| 5 | loopany-capture | Shipped PR → task artifact |
| 6 | loopany-review | Daily followups on empty workspace |
| 7 | loopany-review | Weekly doctor |
| 8 | loopany-reflect | Declines learning when &lt;3 task outcomes |
| 9 | Cross-skill | Signal upgraded to task, signal `addressed` |
| 10 | Kind routing | Competitor intel routed to `signal` |

<Warning>
Skill regression incurs **API cost** and requires network access. It is not part of `bun test`. Use `--dry-run` in CI planning or local scaffolding without calling Claude.
</Warning>

## Recommended verification order

<Steps>
<Step title="Fast gate">
`bun install && bun run typecheck && bun test`
</Step>
<Step title="Binary (optional)">
`bun run build && ./bin/loopany --help`
</Step>
<Step title="Before skill changes">
`./test/skill-regression.sh` (or targeted scenario number)
</Step>
</Steps>

## Troubleshooting

| Symptom | Likely cause | Action |
|---------|----------------|--------|
| `tsc` errors after pull | Types out of sync | `bun install`, re-run `bun run typecheck` |
| E2E timeout / slow run | 88 CLI tests spawn many processes | Run single file: `bun test test/cli.e2e.test.ts` |
| Search E2E vs prod divergence | E2E uses `--no-embed` | Manually test `loopany reindex` without `--no-embed` in a scratch workspace |
| `skill-regression.sh`: command not found `claude` | Claude Code CLI missing | Install Claude Code; ensure `claude` on `PATH` |
| Skill regression auth errors | No API key / expired creds | Configure Anthropic credentials for `claude` |
| Scenario 9 fails | Scenario 1 did not create a signal | Run full suite or fix scenario 1 logs |
| `bin/loopany` missing | Not built or cleaned | `bun run build` |

For workspace health after migrations or failed runs, use `loopany doctor` ([Doctor and troubleshooting](/doctor-and-troubleshooting)).

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Clone, `bun link`, `LOOPANY_HOME`, and agent harness wiring.
</Card>
<Card title="CLI reference" href="/cli-reference">
Full command surface exercised by `cli.e2e.test.ts`.
</Card>
<Card title="Artifact lifecycle example" href="/artifact-lifecycle-example">
Mirrors `test/scenario.e2e.test.ts` and skill-regression cross-skill flows.
</Card>
<Card title="Skills library" href="/skills-library">
Skills installed and tested by `skill-regression.sh`.
</Card>
<Card title="Schema migration" href="/schema-migration">
v0.1→v0.2 path covered by `migration-v0.1-to-v0.2.e2e.test.ts`.
</Card>
</CardGroup>
