# Local Development & Tooling

> Everything you run in the first 10 minutes: Bun workspaces with catalog dependency rules (never pin versions in package.json), worktree-based parallel development via scripts/wt.ts + scripts/run-dev.sh for port isolation, mandatory root-level lint/format/tsc, AGENT=1 for readable test output, and the scripts that prevent zombie ports and inconsistent state.

- Repository: pierrecomputer/pierre
- GitHub: https://github.com/pierrecomputer/pierre
- Human wiki: https://grok-wiki.com/public/wiki/pierrecomputer-pierre-fac2c554b845
- Complete Markdown: https://grok-wiki.com/public/wiki/pierrecomputer-pierre-fac2c554b845/llms-full.txt

## Source Files

- `AGENTS.md`
- `package.json`
- `scripts/wt.ts`
- `scripts/ws.ts`
- `scripts/run-dev.sh`
- `tsconfig.json`
- `tsconfig.options.json`
- `bunfig.toml`

---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [AGENTS.md](AGENTS.md)
- [package.json](package.json)
- [scripts/wt.ts](scripts/wt.ts)
- [scripts/ws.ts](scripts/ws.ts)
- [scripts/run-dev.sh](scripts/run-dev.sh)
- [tsconfig.json](tsconfig.json)
- [tsconfig.options.json](tsconfig.options.json)
- [bunfig.toml](bunfig.toml)
- [apps/docs/package.json](apps/docs/package.json)
- [packages/diffs/package.json](packages/diffs/package.json)
- [packages/trees/test/file-tree-profile-cli.test.ts](packages/trees/test/file-tree-profile-cli.test.ts)

</details>

# Local Development & Tooling

This page covers the commands and conventions you need in the first 10–30 minutes after cloning the pierre monorepo. It focuses on the Bun-based workspace setup, the catalog dependency rules that keep versions consistent, the worktree system for parallel development, port isolation to prevent conflicts, the scripts that clean up zombie processes, and the root-level quality gates that every change must pass.

The monorepo uses Bun exclusively for running commands, installing packages, and executing TypeScript without a separate build step. All local development flows through a small set of root scripts and two purpose-built helpers in `scripts/`.

## First Session Setup

Export the agent flag at the start of every terminal session. This tells Bun's test runner to produce plain, non-interactive output that is easy for humans and tools to read.

```bash
export AGENT=1
```

Run everything from the repository root. The root `package.json` defines the catalog and the convenience scripts; individual packages delegate to it via the workspace runner.

Sources: [AGENTS.md:5-10](), [package.json:100-119]()

## Dependency Management with Bun Catalog

The root `package.json` declares every shared dependency inside `workspaces.catalog`. Packages never contain hard-coded version numbers for catalog entries.

```json
// root package.json
"workspaces": {
  "packages": ["packages/*", "apps/*"],
  "catalog": {
    "react": "19.2.3",
    "typescript": "5.9.2",
    ...
  }
}
```

To add or update a dependency:

1. Add the exact version to the `catalog` object in the root `package.json`.
2. Reference it from any package with the string `"catalog:"`.

Never run `bun add <pkg>` inside a package directory; that writes a version pin directly into that package's `package.json` and breaks the single-source-of-truth rule. Published packages (`diffs`, etc.) may carry a few `^` ranges for end-user flexibility, but the catalog still supplies the development versions.

Bun's `bunfig.toml` adds a seven-day minimum release age for most packages (with explicit excludes for internal and `@types/*` packages) to reduce surprise upgrades.

Sources: [package.json:4-97](), [AGENTS.md:19-32](), [bunfig.toml:1-10](), [packages/diffs/package.json:64-70]()

## Workspace Script Runner (`bun ws`)

Typing `bun run` repeatedly inside each package is tedious. The `bun ws` command (implemented in `scripts/ws.ts`) lets you address any package by short name or path and forwards the requested script plus arguments.

```bash
bun ws diffs test
bun ws apps/docs build
bun ws '*' tsc          # every workspace that has a tsc script
bun ws 'packages/*' dev
```

`ws.ts` walks upward from the current directory, stops at the first `.git` marker (so it never leaks out of a worktree), loads any `.env.worktree` it finds, and injects those variables plus a correctly ordered `PATH` before spawning the target script. It also handles graceful shutdown, TTY restoration, and descendant process tracking so that Ctrl-C behaves reliably even when the child spawns further grandchildren.

Root-level commands such as `lint`, `format`, and `tsc` are thin wrappers around `ws`:

```json
"tsc": "bun run ws \"*\" tsc",
"lint": "oxlint --type-aware --tsconfig tsconfig.oxlint.json .",
```

Sources: [package.json:101-103](), [scripts/ws.ts:18-34](), [scripts/ws.ts:282-293](), [AGENTS.md:192-204]()

## Parallel Development with Git Worktrees

`bun run wt` (implemented in `scripts/wt.ts`) creates isolated git worktrees so you can have several independent checkouts running at once without branch-switching or stashing.

```bash
bun run wt new my-feature
bun run wt rm my-feature
bun run wt clean my-feature   # or --all
bun run wt ps                 # shows every worktree + live ports
bun run wt list
```

Each managed worktree is created under `~/pierre/pierre-worktrees/<slug>/` and receives a deterministic port offset (10, 20, 30, …) stored in `.env.worktree`:

```
PIERRE_WORKTREE_SLUG=my-feature
PIERRE_PORT_OFFSET=10
```

The main clone has offset 0 and keeps the historical default ports. `wt new` also runs `bun install` inside the new tree and prints the resulting port map.

`wt clean` (and `wt rm`) walk the process table with `lsof`, send SIGTERM, wait briefly, then SIGKILL any survivors on the ports that belong to that worktree (or all managed worktrees). This is the required cleanup step before an agent finishes its turn.

Sources: [scripts/wt.ts:30-40](), [scripts/wt.ts:143-166](), [scripts/wt.ts:257-282](), [scripts/wt.ts:442-469](), [AGENTS.md:38-68]()

## Port Isolation and Zombie Prevention

Dev servers and E2E fixtures bind fixed ports. Worktree offsets guarantee that no two live worktrees ever fight for the same port:

| Service     | Base port (offset 0) | Example with offset 10 |
|-------------|----------------------|------------------------|
| docs diffs  | 3690                 | 3700                   |
| docs trees  | 3691                 | 3701                   |
| docs E2E    | 4174                 | 4184                   |
| trees E2E   | 4173                 | 4183                   |
| chrome dev  | 9222                 | 9232                   |

Inside `apps/docs/package.json` the dev scripts compute the concrete port and then invoke the guard script:

```json
"diffs:dev": "export NEXT_PUBLIC_SITE=diffs PORT=$((${PIERRE_PORT_OFFSET:-0} + 3690)) && bash ../../scripts/run-dev.sh \"$PORT\" -- bun run _dev",
```

`scripts/run-dev.sh` does exactly one thing before `exec`ing the real command:

1. `lsof -ti :$PORT -sTCP:LISTEN` → SIGTERM any listeners.
2. Brief sleep.
3. SIGKILL any that remain.
4. `exec "$@"`

The same pattern appears in E2E server scripts and the Chrome remote-debug helper. Because the offset is injected by both `ws.ts` and the `.env.worktree` loader, even direct invocations outside the normal `bun ws` chain still receive the correct port.

Sources: [scripts/run-dev.sh:19-44](), [apps/docs/package.json:12-14](), [scripts/wt.ts:434-439](), [scripts/load-worktree-env.mjs:1-17]()

## Linting, Formatting, Type Checking

All three quality gates are run from the repository root after any code change:

```bash
bun run lint          # oxlint (type-aware via tsconfig.oxlint.json)
bun run lint:fix
bun run format        # oxfmt
bun run format:check
bun run tsc           # runs every package's tsc script via ws
```

`tsconfig.json` uses project references so that `tsc` (and the Go-based `tsgo` used by many packages) can type-check incrementally. Shared strict settings live in `tsconfig.options.json`.

The lint-staged configuration in the root `package.json` runs the same fixers on pre-commit.

Sources: [package.json:108-113](), [tsconfig.json:1-30](), [tsconfig.options.json:1-35](), [AGENTS.md:70-107]()

## Testing

Run tests from inside the package directory:

```bash
cd packages/diffs && bun test
cd packages/trees && bun test
```

With `AGENT=1` in the environment, Bun's test runner emits plain, line-oriented output instead of the interactive TTY UI. Several test suites also set the variable explicitly when spawning CLI child processes so that their `--help` and error output remain deterministic for assertions.

Sources: [AGENTS.md:5-10](), [packages/trees/test/file-tree-profile-cli.test.ts:11-15](), [AGENTS.md:226-241]()

## Command Cheat Sheet

| Task                        | Command                                      |
|-----------------------------|----------------------------------------------|
| Install / update deps       | `bun install` (from root)                    |
| Run a package script        | `bun ws <pkg> <script> [args...]`            |
| Create parallel checkout    | `bun run wt new <slug>`                      |
| Clean ports for one tree    | `bun run wt clean <slug>`                    |
| Clean all managed ports     | `bun run wt clean --all`                     |
| Lint / format / typecheck   | `bun run lint && bun run format && bun run tsc` |
| Run tests in a package      | `cd packages/<name> && bun test`             |
| Start a docs dev server     | `bun ws docs diffs:dev` (or trees:dev)       |

## Summary

The tooling exists to make the first ten minutes productive and the next ten hours free of port collisions, stale processes, and version drift. Always start with `export AGENT=1`, use the catalog for every new dependency, create worktrees with `wt new`, kill their ports with `wt clean` when you are finished, and run the three root quality commands after every edit. The implementation details live in the scripts and configuration files cited above; reading `AGENTS.md` and the top of `scripts/wt.ts` gives you the complete mental model.

Sources: [AGENTS.md:1-70](), [scripts/wt.ts:1-25]()
