## Description
The savings dashboard is served at `GET /dashboard`
(`headroom/proxy/server.py`) but was
effectively undiscoverable: there was no `headroom dashboard` command,
the `wrap` startup banner
only printed `Proxy ready on http://127.0.0.1:PORT` (never the dashboard
URL), and the docs
buried it — so users on current releases didn't know it existed (#1277).
This makes it
discoverable from the CLI, the wrap banner, and the docs.
Closes#1277
## Type of Change
- [x] New feature (non-breaking change that adds functionality)
## Changes Made
- `headroom/cli/proxy.py`: new `headroom dashboard` command — prints
`http://127.0.0.1:<port>/dashboard` and opens it in a browser (stdlib
`webbrowser`); `--no-open`
just prints, `--port`/`HEADROOM_PORT` honored. Headless failures are
swallowed (URL already
printed).
- `headroom/cli/wrap.py`: print the dashboard URL alongside "Proxy
ready" so every `wrap` surfaces
it.
- `docs/content/docs/installation.mdx` + `README.md`: document `headroom
dashboard`.
- `docs/content/docs/mcp.mdx`: document the Codex MCP `command:
"headroom"` PATH pitfall (#768) —
a project-venv (`uv add`) install isn't on the host's PATH; install
globally with
`uv tool install` / pipx, or use an absolute path.
- `tests/test_cli_dashboard.py`: new tests.
## Testing
- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check`)
- [x] New tests added for new functionality
### Test Output
```text
$ python -m pytest tests/test_cli_dashboard.py -q
3 passed
$ python -m ruff check headroom/cli/proxy.py headroom/cli/wrap.py tests/test_cli_dashboard.py
All checks passed!
```
## Real Behavior Proof
- Environment: Windows 11, Python 3.13, branch
fix/1277-dashboard-discoverability off
headroomlabs-ai/main
- Exact command / steps: built the CLI and invoked the new command via
the real entry-point import
(`from headroom.cli.main import main;
main(['dashboard','--no-open','--port','8787'],
standalone_mode=False)`) and checked it is registered (`'dashboard' in
main.commands`).
- Observed result: prints ` Dashboard: http://127.0.0.1:8787/dashboard`,
`'dashboard' in
main.commands` → `True`, exit 0. The three new tests pass (prints URL +
no browser on `--no-open`;
opens the URL by default; a raising `webbrowser.open` does not crash the
command).
- Not tested: did not load the rendered `/dashboard` HTML against a live
proxy in CI — the change
only adds a launcher/printer for the existing route; the route itself is
unchanged.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>