Skip to content
Back to skills

Qa Write

ASecurity

Write or update QA use-case test files for the thatch project. Use when adding a new use case after a feature ships, or when converting a live-session use case to automatable.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 23, 2026
ai-agentstypescriptgonodeapi

Works with

  • claude code
  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned September 23, 2026

npx -y skills add sysread/thatch --skill qa-write --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Qa Write?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Qa Write
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sysread-qa-write/badge)](https://www.skillsdirectory.com/skills/sysread-qa-write)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: qa-write
description: Write or update QA use-case test files for the thatch project. Use when adding a new use case after a feature ships, or when converting a live-session use case to automatable.
---

# Writing Thatch QA Use Cases

You are writing a QA use-case test file for the thatch project. Each use
case verifies end-to-end behavior through the CLI, module APIs, or a live
opencode session.

## Where to put it

- `tests/qa/auto/uc-NNN-name.ts` — if the scenario can be verified
  without a live LLM. No model tokens, runs in seconds.
- `tests/qa/live/uc-NNN-name.ts` — if the scenario needs a live agent
  to read a prompt, make tool calls, and respond. Costs tokens, up to 10
  min each.
- Set `manualOnly: true` if it cannot be automated at all (visual TUI,
  compaction, real Claude Code/Cursor sessions).
- **Add an `import "./uc-NNN-name";` line to the corresponding
  `index.test.ts` barrel file.** Bun's `--concurrent` parallelizes tests
  within a single file, not across files. The barrel file ensures all
  use cases run in parallel.

When in doubt, start with `auto/`. You can always move it to `live/` later.

## File template

```typescript
import { registerUseCase, type UseCase } from "../runner";

/**
 * UC-NNN: <one-line description>.
 *
 * <"Automatable: yes — ..." note if applicable, or
 *  "Requires a live opencode session.">
 */

const useCase: UseCase = {
  name: "UC-NNN-name",
  preconditions: [
    "- State of the system before the test",
  ].join("\n"),
  steps: [
    "1. Action",
    "2. Action",
  ].join("\n"),
  expected: [
    "- Observable outcome",
  ].join("\n"),
  // No custom run — uses default runViaOpencode.
};

registerUseCase(useCase);
```

## Automatable use cases

Add a `run(ctx: QaContext)` function. The context provides:

- `ctx.dir` — isolated repo copy path
- `ctx.env` — env vars (THATCH_DB_PATH, XDG_CONFIG_HOME, HOME,
  CLAUDE_CONFIG_DIR, etc.)
- `ctx.repoRoot` — real repo path (read-only)

### CLI-based pattern

```typescript
import { $ } from "bun";
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { registerUseCase, type UseCase, type QaContext } from "../runner";

const useCase: UseCase = {
  name: "UC-NNN-name",
  preconditions: "...",
  steps: "...",
  expected: "...",

  async run(ctx: QaContext) {
    const bin = `${ctx.repoRoot}/bin/thatch`;
    const env = ctx.env;

    const result = await $`${bin} stores`.env(env).quiet().nothrow();
    if (result.exitCode !== 0) {
      console.log("  FAIL: `thatch stores` exited non-zero");
      return "FAIL";
    }

    return "PASS";
  },
};

registerUseCase(useCase);
```

### Module-based pattern

For use cases that test internal modules directly:

```typescript
import { registerUseCase, type UseCase, type QaContext } from "../runner";
import { ThatchDB } from "../../src/db";
import { MockEmbeddingModel } from "../../src/embeddings";

const useCase: UseCase = {
  name: "UC-NNN-name",
  preconditions: "...",
  steps: "...",
  expected: "...",

  async run(ctx: QaContext) {
    const db = new ThatchDB(ctx.env.THATCH_DB_PATH);
    const model = new MockEmbeddingModel();

    // Exercise the module, check assertions.

    db.close();
    return "PASS";
  },
};

registerUseCase(useCase);
```

## Gotchas

- **Non-thatch hook names in setup tests:** the `replaceThatchHooks` function
  filters by `command.includes("thatch")`. If you inject a test hook, its
  command must NOT contain the substring "thatch" or it will be filtered out.
  Use a name like `"echo external-hook"`, not `"echo non-thatch-hook"`.
- **Import paths from `auto/` or `live/`:** use `../runner` for the runner
  library, `../../src/<module>` for source modules.
- **The name field must match the filename** without the `.ts`
  extension (e.g., `"UC-004-cli-inspection"`).
- **Join string arrays with `\n`** so preconditions, steps, and expected
  become multi-line strings.
- **Return a result:** `"PASS"`, `"FAIL"`, or `"PARTIAL"`. Print evidence
  with `console.log` on failure so it shows in the test output.

## After writing

Run `mise run check` to verify the regular suite still passes (the QA
suite is excluded from the regular check via a flat glob). Then run
`mise run qa-dry-run` to verify the new use case is discovered.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…