Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
cf4c19f
Add portable dashboard lifecycle commands
justin808 Jul 17, 2026
c131aa1
Stabilize concurrent lifecycle starts
justin808 Jul 17, 2026
1c62e0d
Handle disappearing lifecycle locks
justin808 Jul 17, 2026
1ed4c8e
Make lifecycle fallback assertion platform-aware
justin808 Jul 17, 2026
ffde9ec
Address lifecycle review findings
justin808 Jul 17, 2026
b46ed8e
Handle IPv6 lifecycle hosts safely
justin808 Jul 17, 2026
6234131
Harden lifecycle restart preflight
justin808 Jul 17, 2026
4d6d417
Normalize IPv6 lifecycle hosts
justin808 Jul 17, 2026
8e441f6
Decode protected env escapes once
justin808 Jul 17, 2026
c107f2c
Preflight lifecycle restart settings
justin808 Jul 17, 2026
6deb207
Preflight protected lifecycle settings
justin808 Jul 17, 2026
b04db4b
Harden lifecycle child settings
justin808 Jul 17, 2026
5b35de0
Test host guard without built assets
justin808 Jul 17, 2026
70af226
Fail fast on unsafe lifecycle inputs
justin808 Jul 17, 2026
edd95f2
Harden lifecycle diagnostics and logs
justin808 Jul 17, 2026
436f28b
Close lifecycle portability review gaps
justin808 Jul 17, 2026
ade3ae3
Reject unscoped IPv6 link-local lifecycle hosts
justin808 Jul 17, 2026
3e030b3
Harden lifecycle review edge cases
justin808 Jul 17, 2026
2912218
Preserve lifecycle ownership across relocations
justin808 Jul 17, 2026
cf50bbb
Reject symlinked lifecycle state reads
justin808 Jul 17, 2026
1d5cd16
Handle zombie wrappers and localhost rebinding
justin808 Jul 17, 2026
f79014a
Preflight wildcard lifecycle listeners
justin808 Jul 17, 2026
9b9bfb5
Respect IPv6-only wildcard probes
justin808 Jul 17, 2026
3fb95ad
Continuously bound lifecycle logs
justin808 Jul 17, 2026
36e2d74
Conservatively preflight wildcard lifecycle binds
justin808 Jul 17, 2026
a76f589
Retry lifecycle log reads after rollover
justin808 Jul 17, 2026
dc85ab2
Speed up lifecycle log tail assertion
justin808 Jul 17, 2026
20701e2
Handle missing lifecycle URL opener
justin808 Jul 17, 2026
02b9a3f
Fix lifecycle shutdown and local write guards
justin808 Jul 17, 2026
d784f16
Harden lifecycle host and env validation
justin808 Jul 17, 2026
3c12dd9
Close remaining lifecycle trust gaps
justin808 Jul 17, 2026
f7bab2e
Reject IPv4 link-local write peers
justin808 Jul 17, 2026
6fcb383
Harden portable lifecycle edge cases
justin808 Jul 17, 2026
39793c6
Close remaining lifecycle review gaps
justin808 Jul 17, 2026
10b217a
Fix localhost lifecycle health probes
justin808 Jul 18, 2026
5fb2f80
Fix localhost open allowlist
justin808 Jul 18, 2026
5e4a75f
Reject IPv4 link-local lifecycle hosts
justin808 Jul 18, 2026
998750c
Fix localhost lifecycle doctor probes
justin808 Jul 18, 2026
68c8870
Preserve lifecycle log tail during rollover
justin808 Jul 19, 2026
f873098
Leave lifecycle log rollover headroom
justin808 Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 83 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,75 @@ npx agent-coordination-dashboard
This repository is package-ready only: these steps do not publish to npm,
create a Git tag, or change registry state.

## Detached lifecycle commands

The packaged CLI can manage a detached local dashboard on supported macOS and
Linux hosts without tmux, private dotfiles, or an interactive shell:

```bash
npx agent-coordination-dashboard start
npx agent-coordination-dashboard status
npx agent-coordination-dashboard logs
npx agent-coordination-dashboard open
npx agent-coordination-dashboard restart
npx agent-coordination-dashboard stop
```

Each `start` or `restart` reloads the optional protected environment file at
`~/.config/agent-coordination-dashboard/env`. When the file exists, it must be
a regular file owned by the current user with mode `0600`:

```bash
mkdir -p ~/.config/agent-coordination-dashboard
touch ~/.config/agent-coordination-dashboard/env
chmod 600 ~/.config/agent-coordination-dashboard/env
```

Use `--config-env-file <path>` on `start` or `restart` to load another protected
file. The lifecycle CLI deliberately does not call this flag `--env-file`:
current Node.js runtimes reserve that option and may consume it before the
dashboard CLI can validate it.

The child process receives explicit empty values for the coordination API URL
and token variables before values from the protected file are applied. Removing
API settings from the file and restarting therefore returns the dashboard to
filesystem mode instead of inheriting stale credentials. Lifecycle children
always run with `NODE_ENV=production`. Tokens are passed only in the child
environment; they are not stored in lifecycle metadata or command arguments.
Lifecycle metadata and logs live under
`~/.local/state/agent-coordination-dashboard/` with user-only permissions.

Lifecycle `HOST` must be `localhost` or an IPv4 or IPv6 address, including the
`0.0.0.0` and `::` wildcard addresses. A `restart` validates the protected file,
`PORT`, and `HOST` before stopping the running dashboard, so invalid replacement
configuration leaves the existing service intact.
Wildcard `HOST` values require an `ALLOWED_HOSTS` list containing only specific
hostnames or IP addresses; blank and catch-all entries are rejected.

`start`, `stop`, and `restart` are idempotent. The CLI records an instance marker
and verifies the owned process group before signaling it, so a listener it does
not own is reported but never terminated. If the lifecycle wrapper exits while
its marked server remains healthy, status and stop retain safe control of that
group. Mutating lifecycle commands share a
user-only lock, so simultaneous starts cannot race into an unowned listener; a
lock left by a dead command is recovered without signaling that command's
process. Startup probes the configured bind host, including IPv6 loopback, and
waits for `/api/health`; lifecycle status then reuses
`doctor --stack-json --deep` to report coordination health. A healthy server
with degraded coordination remains running and is reported as degraded rather
than being mistaken for a failed start. For a specific IP address assigned to
the local machine, lifecycle diagnostics connect from a loopback source address;
the dashboard's machine-local `/api/doctor` boundary remains unchanged.

Write routes recognize a same-machine peer from the kernel-reported TCP source
address, not from forwarded headers. Exact non-link-local interface matching is
not application authentication: it cannot compensate for a host or network that
permits source-address spoofing, or for a proxy that makes remote clients appear
local. Keep `HOST` on loopback on shared or untrusted networks. If a non-loopback
bind is required, use host firewall or equivalent access controls so untrusted
traffic cannot reach the dashboard. `/api/doctor` and foreground cache bypass
remain loopback-only.

## Component diagnostics

The installed command owns a read-only machine contract for stack-wide health
Expand Down Expand Up @@ -91,7 +160,8 @@ The server binds to `127.0.0.1` by default because it exposes private local
coordination metadata. Set `HOST=0.0.0.0` only when you intentionally want to
make it reachable from another machine on the network, and set `ALLOWED_HOSTS`
to the exact hostnames or IP addresses you will use in the browser.
Changing target repositories through the UI remains loopback-only.
Changing target repositories through the UI uses the same exact same-machine
socket-peer boundary described above; other network peers remain read-only.

To read from the HTTP coordination backend instead of the local filesystem
state root, set the same API variables used by `agent-coord`:
Expand Down Expand Up @@ -177,7 +247,9 @@ Work items show three scheduling states:

The dashboard does not launch Codex agents, edit code, merge PRs, resolve
reviews, or mutate claims or heartbeats. Coordination-state writes are limited
to explicit loopback-only actions:
to explicit actions whose socket peer is loopback or exactly matches a
non-link-local address currently assigned to the dashboard machine. Other LAN
and remote peers remain read-only:

- Save an imported batch plan to `batches/<batch-id>.json`.
- Append a `batch.stop_requested` event to `events/batches/<batch-id>.jsonl`.
Expand All @@ -186,9 +258,10 @@ A stop request is a coordination/audit signal so a batch can be restarted
cleanly; it does not kill processes or release claims by itself.

Dismiss and snooze actions never write coordination state. They are
presentation-only annotations, accepted from loopback clients and persisted in
`annotations.json` beside the dashboard settings file. Active snoozes expire
automatically; dismissals remain until an operator clears them.
presentation-only annotations, accepted from loopback or exact non-link-local
same-machine interface peers and persisted in `annotations.json` beside the
dashboard settings file. Active snoozes expire automatically; dismissals remain
until an operator clears them.

## Configuration

Expand All @@ -204,6 +277,11 @@ automatically; dismissals remain until an operator clears them.
| `TARGET_REPOS` | empty first-run fallback |
| `DASHBOARD_SETTINGS_PATH` | `~/.local/state/agents-coordination-dashboard/settings.json` |

The protected lifecycle environment file rejects `NODE_OPTIONS`, and detached
lifecycle children do not inherit it from the launching shell. Lifecycle-managed
dashboards do not support Node runtime options through `NODE_OPTIONS`, keeping
restart behavior independent of the caller's working directory.

Target repositories are edited in the dashboard and persisted across restarts.
`TARGET_REPOS` accepts a comma-separated list only as the first-run fallback
when no settings file exists yet.
Expand Down
Loading
Loading