---
sidebar_position: 1
title: Test memory
---

# Test memory

Zibby's `zibby test` runner has a local-first **memory database** at `.zibby/memory/.dolt/` that learns from every run — selectors that worked, page-element fingerprints, navigation transitions, timing quirks, recorded insights. Cross-spec via per-domain keying, optionally synced across the team.

The package powering this is [`@zibby/ui-memory`](../packages/ui-memory) — read that for the schema and SDK. This page is a **usage walkthrough**.

## What's in the box

- **Local DB** — `.zibby/memory/.dolt/` (Dolt SQL, version-controlled like git)
- **5 MCP tools** auto-exposed when `zibby test` runs and the DB exists
- **Auto-pull / auto-push** before and after each test run when a remote is configured
- **CLI** — `zibby memory <verb>` for stats, cost, compact, reset, pull, push, remote management

## Why per-domain keying matters

Memory is keyed on the **domain**, not the spec file. Selectors learned by `login.txt` for `myapp.com/login` are immediately available when `checkout.txt` lands on `myapp.com/checkout` and asks "what's a stable selector for the email field on this site?"

In practice this means a multi-spec suite gets sharper with every run — the agent's Nth run on a domain is meaningfully cheaper and more reliable than its first.

## The 5 MCP tools

When `zibby test` runs and `.zibby/memory/.dolt/` exists, the agent gets these auto-exposed:

| Tool | What it does |
|---|---|
| `memory_get_test_history` | Recent runs (filter by spec-path substring) — pass/fail and timing |
| `memory_get_selectors` | Known selectors per page with success/fail counts |
| `memory_get_page_model` | Page elements (URL, ARIA role, accessible name, best-known selector) |
| `memory_get_navigation` | Known transitions (from URL → to URL via what trigger) |
| `memory_save_insight` | Save an observation: `selector_tip | timing | navigation | workaround | flaky | general` |

> **The agent must call `memory_save_insight` at least once per run.** It's required by the memory skill's prompt fragment. Without insights, only the structural data (selectors / runs) compounds; insights are how the system learns "the site shows a banner on Tuesdays" or "this button needs a 200ms wait after focus".

## CLI commands

```bash
zibby memory init               # initialize (auto-runs on first `zibby test -m`)
zibby memory stats              # row counts, last commit, per-spec breakdown
zibby memory cost               # real LLM token spend per spec / per domain (input/output/cache)
zibby memory compact            # prune old runs + Dolt GC (--max-runs 50, --max-age 90d)
zibby memory reset -f           # wipe the DB (destructive — confirm)
```

`compact` is the maintenance lever once the DB grows. `cost` is the most-asked-after view — it answers "which spec is the expensive one?" with real numbers.

## Team sync

Memory is local-first by default. Opt into a shared remote so teammates' learnings flow back to you:

```bash
# Option A: bring your own bucket
zibby memory remote add aws://my-bucket/team/proj/main      # S3
zibby memory remote add gs://bucket/team/proj/main          # GCS
zibby memory remote add https://www.dolthub.com/repositories/<owner>/<repo>
zibby memory remote add file:///abs/path/to/local-shared    # filesystem

# Option B: Zibby-managed S3 (signed-in users only)
zibby memory remote use --hosted

# Inspect / disconnect
zibby memory remote info
zibby memory remote remove [name]   # default: origin
```

Once a remote is configured:

- `zibby test` auto-pulls before each run
- `zibby test` auto-pushes after each **passing** run (failing runs don't pollute team memory)
- `zibby memory pull` / `zibby memory push` for manual override

### Auto-wire teammates with `memorySync.remote`

Drop this into `.zibby.config.mjs` and commit it:

```js
export default {
  agent: { claude: { model: 'auto' } },
  memorySync: {
    remote: 'hosted',                       // or 'aws://my-bucket/team/proj/main' or null
  },
};
```

Now when a teammate clones the repo and runs `zibby init`, the CLI reads `memorySync.remote` and auto-configures the matching remote. For `'hosted'`, init prompts for `zibby login` if they're not signed in but never blocks the init itself.

### Hosted vs BYO at a glance

| | Hosted (`--hosted`) | BYO |
|---|---|---|
| Setup time | One command | Provision bucket + IAM (+ KMS if you want) |
| Where data lives | Zibby-managed AWS account | Your account |
| Access | Anyone with Zibby project access | Whoever your IAM grants |
| Compliance / data residency | Limited regions | Wherever you want |
| Cost | Included in plan | Your S3 bill |

If you have any data-residency requirement or a regulated workload, prefer BYO. Otherwise hosted is the path of least resistance.

## Run-level controls

`zibby test` exposes one memory-relevant flag:

```bash
zibby test test-specs/login.txt -m            # enable test memory (auto-init if needed)
zibby test test-specs/login.txt --no-sync     # don't push to cloud (does not affect memory remote)
```

Memory is independent of the cloud-results sync (`--sync` / `--no-sync` controls run upload to the Zibby dashboard; memory sync is its own remote).

## Inspecting the DB by hand

It's just Dolt:

```bash
cd .zibby/memory
dolt log
dolt sql -q "SELECT spec_path, passed, duration_ms FROM test_runs ORDER BY created_at DESC LIMIT 20"
dolt diff HEAD~1 HEAD
```

Branching works too — `dolt branch experiment` to try out a memory mutation in isolation.

## See also

- [`@zibby/ui-memory` package](../packages/ui-memory) — schema, SDK, middleware
- [`zibby test` recipe](../recipes/test) — the primary consumer
- [CLI reference: memory](../cli-reference#memory) — full command list
