# two agents. two shops.

In about five minutes, you will run a shop in two worktrees: one agent changes the catalog while another works on checkout. Each gets its own Vite storefront, Node API, and Postgres database. They share one Postgres engine and one Redis server. Tests place real orders.

Use **macOS, Git, Node.js 22.12 or newer, Bun, a running Docker Desktop or OrbStack, and [antil on your PATH](/docs/start-here/install/)**. Git needs your usual commit identity. The first image download can take longer.

## 1. unpack the shop

The [shop starter](/docs/examples/shop.tar.gz) contains all the code used throughout this manual. Use a new directory:

```sh
mkdir -p /tmp/antil-shop-lesson
cd /tmp/antil-shop-lesson
export DOCS_URL="${DOCS_URL:-https://antil.dev/docs}"
curl -fsSL "$DOCS_URL/examples/shop.tar.gz" -o shop.tar.gz
tar -xzf shop.tar.gz
cd shop
git init -b main
bun install
git add .
git commit -m "Add shop stack"
```

The shop has `index.html` and `vite.config.mjs` for the storefront, `api/server.mjs`, `seed.sql`, `compose.yaml` for Redis, `tests/shop.test.mjs`, and `antil.yaml`.

## 2. prepare the shared cache

```sh
bun run prepare:cache
```

After Docker's progress messages:

```text
shared Redis ready; connection saved in .antil/redis-url
```

Redis support through antil recipes is coming. For now this helper uses Compose, saves the connection in a gitignored file, and gives each worktree its own cache key prefix. Postgres is managed by antil.

Use separate state and ports for this lesson. Keep these exports in the same shell for every step:

```sh
export ANTIL_HOME=/tmp/antil-shop-lesson/state
export ANTIL_PROXY_PORT=1376
export ANTIL_PORT_RANGE=45100-45199
```

## 3. start the catalog worker

```sh
antil session start --json
antil status
```

Here are the app lines from a real run. IDs, ports, paths, and times vary:

```text
status: ok
session: ses_8cf7db2b7f27 (active, stack default)
  api          ready     http://api.ses-8cf7db2b7f27.prj-695192eb9055.localhost:1376  log: /private/tmp/antil-docs/shop-home/logs/run_8cf7db2b7f27_2.log
    last probe: ready (2026-10-31T16:32:54Z)
  web          ready     http://web.ses-8cf7db2b7f27.prj-695192eb9055.localhost:1376  log: /private/tmp/antil-docs/shop-home/logs/run_8cf7db2b7f27_5.log
    last probe: ready (2026-10-31T16:32:56Z)
```

Both apps are `ready`. The API's `/health` checks Postgres and Redis before it answers successfully. The storefront waits for the API.

Open the `web` URL from **your** output in your browser. You will see “field supplies”, a Field notebook for €12, and a Canvas tool roll for €35. Click **order a field notebook**. An order number appears, stored in this worker's database.

## 4. start the checkout worker

Keep the first shop running. In the same shell:

```sh
antil workspace create checkout --path /tmp/antil-shop-lesson/shop-checkout
cd /tmp/antil-shop-lesson/shop-checkout
bun install
bun run prepare:cache
antil session start --json
antil status
```

The second worker gets different addresses:

```text
status: ok
session: ses_2e26319326f0 (active, stack default)
  api          ready     http://api.ses-2e26319326f0.prj-695192eb9055.localhost:1376  log: /private/tmp/antil-docs/shop-home/logs/run_2e26319326f0_2.log
    last probe: ready (2026-10-31T16:32:58Z)
  web          ready     http://web.ses-2e26319326f0.prj-695192eb9055.localhost:1376  log: /private/tmp/antil-docs/shop-home/logs/run_2e26319326f0_5.log
    last probe: ready (2026-10-31T16:32:59Z)
```

Open its `web` URL beside the first. Ordering here writes to the checkout worker's database. Both workers share the database engine; their orders stay separate. Their Redis keys stay separate too.

## 5. run the checkout tests

```sh
antil run test --json
```

A successful result contains these lines, trimmed from a real run:

```text
"apiVersion": "antil/v1alpha1",
  "status": "ok",
  "operation": {
    "id": "op_dcd6b4b0cb0b",
    "kind": "run",
    "state": "succeeded"
  },
  "data": {
```

The tests check the seeded catalog and place an order. In `next_actions`, `argv` lists the words of the log command. Type `antil logs --run` followed by the run ID from your result. The report includes:

```text
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
```

These are ordinary test runs. **Seals are coming:** antil does not yet reuse a passing result in another worktree.

## 6. stop the lesson

End both workers, delete only the lesson's retained database data, and stop its shared Redis:

```sh
antil session end
cd /tmp/antil-shop-lesson/shop
antil session end
antil prune --json
```

`prune` prints a preview; it deletes nothing. Read the listed targets. The `apply` action gives an `argv` array: `antil`, `prune`, `--apply`, your preview revision, `--json`. Type those five entries in order, separated by spaces. Use the revision from your own preview. Both lesson databases and their unused engine should be in that preview. You used a separate `ANTIL_HOME`, so it contains only this lesson's work.

Finish cleanup:

```sh
bun run stop:cache
antil daemon shutdown --stop-sessions
```

The worktree files remain. You have two working shops with separate addresses and data, sharing the expensive servers. Continue with [tunnels: apps & urls](/docs/tunnels/), [chambers: shared resources](/docs/chambers/), or [seals: proof & cache](/docs/seals/).

If a start fails, read `blockers` and the log path in its result. Check that Docker is running and `bun run prepare:cache` succeeded in that worktree. After fixing the cause, end that session and start it again. [Recover a worker](/docs/tunnels/recover/) has the next steps.
