agent-berth 2.0.0

Monitor and resume coding agents
Documentation
# Integration tests

Run the default suite with `cargo test` or just the integration tests:

```powershell
cargo test --test integration
```

`mise run test:integration` runs the same command. Tests use the compiled
agent-berth binary, real IPC, and real redb files. A small Rust fixture supplies client
discovery and records tmux commands; `rustc` must be on PATH. No installed agent,
tmux, authentication, or model request is needed for the default suite.

Coverage includes:

- Claude, Codex, and Grok hook lifecycle transitions, including session removal.
- OpenCode and Pi snapshots, blocking, and replacement of previous snapshots.
- Two concurrent agent-berth servers with separate endpoints and databases, duplicate
  server rejection, offline reads, and persistence after a server restart.
- Hook installation into disposable configuration directories for all providers.
- Resume command construction, including namespace and configuration propagation
  through tmux control mode. Dry runs must not invoke tmux.
- Resume pattern selection, `--here` filtering, and `rm` hiding sessions until
  they report again.

## Real tmux / psmux

```powershell
cargo test --test integration real_tmux -- --ignored
```

Or use `mise run test:tmux`. This starts a fixture agent through the real resume
path and checks its arguments, working directory, IPC endpoint, and state
directory. It makes no model calls. tmux or psmux must be on PATH.
The test also keeps a second namespace alive and verifies that cleaning up the
resumed session leaves that namespace running.

Every tmux command, including cleanup, uses a random `-L` namespace and an explicit
configuration file. On Windows, `PSMUX_DATA_DIR` also points into the test root.
Pane shells start without personal profiles. The test never issues a bare
`kill-server` command; in psmux that would terminate other namespaces too.

## Real agent client smoke test

This opt-in test makes a model request. Select an installed client and provide
credentials in its API-key environment variable before running:

```powershell
$env:AGENT_BERTH_TEST_CLIENT = 'codex'
cargo test --test integration live_client -- --ignored
```

Or use `mise run test:live`. Supported selections are `claude`, `codex`, `grok`,
`opencode`, and `pi`. `AGENT_BERTH_TEST_MODEL` optionally supplies the client's
`--model` argument, including any provider prefix required by that client.

Only `ANTHROPIC_API_KEY`, `CODEX_API_KEY`, `OPENAI_API_KEY`, `XAI_API_KEY`, and
`GROK_API_KEY` are forwarded from the parent environment to the selected client.
Use a key and model accepted by that client. Existing subscription logins,
personal configuration, plugins, and session histories are not copied. The test
does not perform a login or install a client.

The test installs the agent-berth hooks, then substitutes a recording executable that
forwards their original payloads to the compiled binary and records the resulting
session list. Success requires an actual client-generated session to appear in
the server, not merely a successful client or `notify` exit code. This also
exercises client hook/plugin compatibility, which synthetic payload tests cannot
establish. It uses each client's headless mode; interactive permission dialogs
and full real-client resume behavior are outside this smoke test.

Codex runs with `--dangerously-bypass-hook-trust` for the hooks generated by this
test. Its ordinary execution sandbox remains enabled. Session persistence stays
enabled. Model execution has a two-minute deadline; hook observations have an
additional ten-second deadline. Client stdout/stderr and hook payloads are saved
under the test root.

## Mock LLM client test

```powershell
$env:AGENT_BERTH_TEST_CLIENT = 'codex'
cargo test --test integration mock_llm -- --ignored
```

Or use `mise run test:mock`. This runs the same installed clients headless, but
points them at a local in-process mock of the Anthropic Messages and OpenAI
Chat Completions/Responses APIs instead of a paid service. No credentials are
needed. Supported selections are `claude`, `codex`, `grok`, `opencode`, and
`pi`. CI installs the clients and runs this test in a matrix on every push;
`AGENT_BERTH_TEST_MODEL` does not apply.

Each client is wired to the mock through its custom-endpoint configuration:
`ANTHROPIC_BASE_URL`/`ANTHROPIC_AUTH_TOKEN` for claude, a `[model_providers]`
entry with `wire_api = "responses"` for codex, `GROK_XAI_API_BASE_URL` for
grok, an `@ai-sdk/openai-compatible` provider in `opencode.json` for opencode,
and a `models.json` provider for pi.

The mock answers every completion with a final `stop` response, so the
conversation completes deterministically. The test asserts the client called
the mock, its session reached the server, and the session arrived at its
terminal state: a terminal hook (`Stop` for claude, which does not emit
`SessionEnd` in print mode; `SessionEnd` for codex and grok) plus removal from
the active list, or an idle-or-stale plugin snapshot for opencode and pi. The
mock delays its answers by two seconds (three for the plugin clients) so async
hooks and plugin heartbeats flush before the client exits.

opencode downloads the `@ai-sdk/openai-compatible` package into the sandbox's
fresh cache on every run, so it needs network access and can take over a
minute; the client deadline is four minutes.

Codex ignores `async` hooks in `exec` mode, so agent-berth installs its codex
hooks synchronously. On Windows, claude runs hooks through bash and codex
cannot parse quoted commands, so installed hook commands use an unquoted
forward-slash path to the agent-berth binary; paths containing spaces are not
supported there.

## Isolation and diagnostics

Each test builds a child-process environment from scratch. Home directories,
XDG directories, Windows app-data directories, provider homes, desktop discovery,
and temporary files point into its temporary root. The parent shell environment
is not modified. The IPC endpoint is a unique named pipe on Windows and a unique
Unix socket path elsewhere. Server readiness is checked with an IPC ping, because
the `list` CLI can fall back to reading the database.

The harness uses `setup --no-service`, owns its server process, and terminates
only that process during cleanup. It does not call service setup or `teardown`.
Successful tests remove their temporary directories. Failed tests print and
retain their artifact directory for diagnosis; server processes and real tmux
namespaces are still cleaned up.

Two environment overrides are available for any agent-berth invocation:

| Variable | Effect |
| --- | --- |
| `AGENT_BERTH_TMUX_SOCKET` | Adds `tmux -L <name>` to every tmux invocation. |
| `AGENT_BERTH_TMUX_CONFIG` | Adds `tmux -f <path>` to every tmux invocation. |

Leaving these unset preserves the normal tmux behavior. The tests set both and
remove inherited `TMUX` state before launching children.

## GitHub Actions

`.github/workflows/tests.yml` runs formatting, the default suite, and the real
tmux test on Windows and Linux for branch pushes and pull requests. It is also
callable from the publishing workflow. A second job runs the mock LLM client
test in a matrix over all five clients on Windows and Linux, installing the
clients with npm (grok from `x.ai/cli`) and never touching a paid API. Failed
runs upload their retained temporary directories as artifacts. Live client/model
tests are never selected in CI.