Discovered while running Task 12's Playwright editor test: Chromium's bootstrap_check_in Mach-port rendezvous is blocked by the sandbox, which surfaces as a FATAL crash with "Permission denied (1100)" rather than a path-related error. Document the workaround so future agents running e2e tests in the same sandbox don't waste time debugging it as a Playwright/network issue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
118 lines
4.6 KiB
Markdown
118 lines
4.6 KiB
Markdown
# AGENTS.md
|
|
|
|
Guidance for coding agents working in this repository.
|
|
|
|
## Mission
|
|
|
|
Build `left4me` according to the two implementation plans:
|
|
|
|
- `docs/superpowers/plans/2026-04-22-l4d2-host-lib-v1.md`
|
|
- `docs/superpowers/plans/2026-04-23-l4d2-web-app-v1.md`
|
|
|
|
Do not invent architecture outside these plans unless explicitly requested.
|
|
|
|
## Current Project State
|
|
|
|
- `l4d2host/` and `l4d2web/` implementation directories exist.
|
|
- Implementation plans remain the source of truth for contract changes and task sequencing.
|
|
|
|
## Non-Negotiable Constraints
|
|
|
|
### Workspace and tools
|
|
|
|
- Do not use git worktrees.
|
|
- Repo is a uv workspace; Python is pinned to 3.13 via `.python-version`. After fresh checkout: install `uv` (`brew install uv` / `curl -LsSf https://astral.sh/uv/install.sh | sh`), then `direnv allow` (or `uv sync` directly). See README **Local development** for details.
|
|
|
|
### Planning artifacts
|
|
|
|
- Design specs live in `docs/superpowers/specs/` as `YYYY-MM-DD-<topic>-design.md`.
|
|
- Implementation plans live in `docs/superpowers/plans/` as `YYYY-MM-DD-<topic>.md` (suffix the topic with `-v1`/`-v2`/etc. if a plan is versioned).
|
|
- Commit both to git as soon as the user approves them.
|
|
- Do not leave specs or plans outside this repo. The `~/.claude/plans/<slug>.md` plan-mode scratch file is acceptable while plan mode is open; the persisted artifact must end up under `docs/superpowers/` and be committed.
|
|
|
|
### Naming and boundaries
|
|
|
|
- Use `l4d2` naming consistently.
|
|
- Keep host library and web app as separate components.
|
|
- Do not collapse them into one package.
|
|
|
|
### Host library (`l4d2host` / `l4d2ctl`)
|
|
|
|
- Exposed CLI write command set is fixed:
|
|
- `install`
|
|
- `initialize <name> -f <spec.yaml>`
|
|
- `start <name>`
|
|
- `stop <name>`
|
|
- `delete <name>`
|
|
- CLI read commands are allowed for web/host boundary consistency:
|
|
- `status <name> --json`
|
|
- `logs <name> --lines <n> --follow/--no-follow`
|
|
- Runtime paths are rooted at `LEFT4ME_ROOT`, defaulting to `/var/lib/left4me`.
|
|
- Deployment/config management owns global units under `/usr/local/lib/systemd/system` and privileged helpers under `/usr/local/libexec/left4me`.
|
|
- Overlay directories are populated by the web app (workshop downloads, managed-global refresh). The host library only mounts them.
|
|
- Fail-fast subprocess behavior; pass raw stderr; propagate return code.
|
|
- No lock manager, no rollback, no preflight runtime checks.
|
|
- Delete missing instance/runtime dirs must succeed (no-op).
|
|
- Read APIs required for web app integration:
|
|
- `get_instance_status(name)`
|
|
- `stream_instance_logs(name, lines=200, follow=True)`
|
|
|
|
### Web app (`l4d2-web-app`)
|
|
|
|
- Flask + server-rendered templates + vendored HTMX.
|
|
- No external frontend framework/dependencies.
|
|
- Custom CSS with tokenized, consistent link and accent colors.
|
|
- Local username/password auth and `admin` flag.
|
|
- Persist command logs in `job_logs` table (retain indefinitely).
|
|
- Desired vs actual server state model.
|
|
- Live logs in UI for both jobs and servers.
|
|
- Web app host operations go through `l4d2ctl` via a host command client, not direct `l4d2host` imports.
|
|
- Blueprint semantics (locked):
|
|
- private per user in v1
|
|
- live-linked to servers
|
|
- no server-level overrides
|
|
- deleting in-use blueprint is blocked
|
|
- updates apply on next action
|
|
- servers can reassign blueprint anytime
|
|
|
|
## Delivery Workflow
|
|
|
|
1. Read both plan files fully before coding.
|
|
2. Execute plan tasks in order.
|
|
3. Keep changes scoped to one task at a time.
|
|
4. Run task-level tests before moving forward.
|
|
5. Do not claim completion without command evidence.
|
|
6. Keep docs updated when behavior/contracts change.
|
|
|
|
## Verification Expectations
|
|
|
|
Before claiming success on any step, run the relevant command and report actual output status.
|
|
|
|
Typical commands (once components exist):
|
|
|
|
- `pytest l4d2host/tests -q`
|
|
- `pytest l4d2web/tests -q`
|
|
|
|
## Change Control
|
|
|
|
- If a requested change conflicts with this file, follow explicit user instruction.
|
|
- If plans and code diverge, update plans or flag the mismatch clearly.
|
|
|
|
## End-to-end tests
|
|
|
|
The Playwright-based browser tests under `l4d2web/tests/e2e/` need a
|
|
chromium binary, fetched on first setup:
|
|
|
|
```bash
|
|
uv run playwright install chromium
|
|
```
|
|
|
|
Run with `uv run pytest -m e2e`. Excluded from the default fast suite
|
|
via the `e2e` marker.
|
|
|
|
**Sandbox note:** Chromium needs Mach-port IPC on macOS, which the
|
|
Claude Code sandbox blocks. When running e2e tests from a sandboxed
|
|
agent session, pass `dangerouslyDisableSandbox: true` on the
|
|
`uv run pytest -m e2e` invocation (the symptom of a sandboxed run is
|
|
a `FATAL` Chromium crash with `Permission denied (1100)` on Mach port
|
|
rendezvous, not a missing-binary or network error).
|