Skip to content

feat(daemon): cc_daemon spike validating RFC 0001 contract end-to-end#77

Merged
chauncygu merged 1 commit intomainfrom
feature/daemon-spike
Apr 30, 2026
Merged

feat(daemon): cc_daemon spike validating RFC 0001 contract end-to-end#77
chauncygu merged 1 commit intomainfrom
feature/daemon-spike

Conversation

@chauncygu
Copy link
Copy Markdown
Contributor

Adds an isolated cc_daemon/ package (~1.1k LoC across 9 files, plus 360 lines of pytest) that implements the daemon contract surface defined in docs/RFC/0001-daemon-design-note.md (PR #74). This is a SPIKE — it exists to lock down the IPC + permission routing + local auth contract in runnable code so the upcoming foundation PR has a verified starting point. Nothing in cc_daemon/ is load-bearing for production.

Covers the ✓ rows of the RFC review-comment matrix: ThreadingHTTPServer with a non-default request_queue_size, 15s SSE heartbeat, client_id mint/persist/resume, sync RPC + async events (variant A of session.send), Cheetahclaws-Api-Version: 0 → 426 on mismatch, bounded event ring buffer with gap event on overflow, audit log default-on for both transports, 30 min interactive permission timeout with permission.refresh_timeout RPC, and originator-only permission.answer returning HTTP 403 / -32001 to non-originators.

Out of scope: agent.run integration, bridges migration, SQLite event store, cost guardrails, agent-runner subprocess isolation, /metrics, macOS peer-cred (TODO(macos) left in cc_daemon/auth.py).

Main code touches are minimal and isolated: a 6-line subcommand shim in cheetahclaws.py that intercepts cheetahclaws spike-daemon ... before the main argparse runs, plus one cc_daemon entry in pyproject.toml's package list. Existing CLI flags (--version, --help, prompt parsing) are unchanged.

Tests: 593 passing (580 existing + 13 new). Run the new suite with pytest tests/test_daemon_spike.py -v. Manual smoke and originator- routing demo in docs/RFC/0001-spike-notes.md "How to run it".

Refs #68, #74

Adds an isolated cc_daemon/ package (~1.1k LoC across 9 files, plus 360
lines of pytest) that implements the daemon contract surface defined in
docs/RFC/0001-daemon-design-note.md (PR #74). This is a SPIKE — it
exists to lock down the IPC + permission routing + local auth contract
in runnable code so the upcoming foundation PR has a verified starting
point. Nothing in cc_daemon/ is load-bearing for production.

Covers the ✓ rows of the RFC review-comment matrix: ThreadingHTTPServer
with a non-default request_queue_size, 15s SSE heartbeat, client_id
mint/persist/resume, sync RPC + async events (variant A of
session.send), Cheetahclaws-Api-Version: 0 → 426 on mismatch, bounded
event ring buffer with gap event on overflow, audit log default-on for
both transports, 30 min interactive permission timeout with
permission.refresh_timeout RPC, and originator-only permission.answer
returning HTTP 403 / -32001 to non-originators.

Out of scope: agent.run integration, bridges migration, SQLite event
store, cost guardrails, agent-runner subprocess isolation, /metrics,
macOS peer-cred (TODO(macos) left in cc_daemon/auth.py).

Main code touches are minimal and isolated: a 6-line subcommand shim in
cheetahclaws.py that intercepts `cheetahclaws spike-daemon ...` before
the main argparse runs, plus one cc_daemon entry in pyproject.toml's
package list. Existing CLI flags (--version, --help, prompt parsing)
are unchanged.

Tests: 593 passing (580 existing + 13 new). Run the new suite with
`pytest tests/test_daemon_spike.py -v`. Manual smoke and originator-
routing demo in docs/RFC/0001-spike-notes.md "How to run it".

Refs #68, #74

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chauncygu chauncygu merged commit c9d5ebd into main Apr 30, 2026
6 checks passed
chauncygu added a commit that referenced this pull request Apr 30, 2026
chauncygu added a commit that referenced this pull request May 2, 2026
Re-land cc_daemon spike for #80 (un-revert 3183fc6)  Revert "Revert "Merge pull request #77 from SafeRL-Lab/feature/daemon…
dsqueri-temeriteecorp pushed a commit to dsqueri-temeriteecorp/cheetahclaws that referenced this pull request May 4, 2026
dsqueri-temeriteecorp pushed a commit to dsqueri-temeriteecorp/cheetahclaws that referenced this pull request May 4, 2026
…ut flush, test floor

Four nits surfaced while smoke-testing F-1 (PR SafeRL-Lab#80) on real subprocesses.
None are blockers, but they each break a docs-promised path so they
deserve a dedicated polish PR rather than getting buried in F-2's diff.

1. `cheetahclaws daemon {status, stop, rotate-token}` now read the token
   path from the discovery file when `serve` was started with
   `--token-path`. `discovery.make_info()` accepts a new optional
   `token_path` keyword (schema stays at 1 — additive); `cli.cmd_serve()`
   records it only when the path overrides the default; new
   `commands.daemon_cmd._resolve_token_path()` prefers discovery and falls
   back to the default location for old discovery files / unset case.
   Previously these verbs always read `~/.cheetahclaws/daemon_token`,
   which silently created a *different* random token, then failed 401
   against the running daemon.

2. `python -m cc_daemon.cli --help` (and the `cheetahclaws spike-daemon
   --help` backward-compat alias) now print a usage banner and exit 0
   instead of `unknown subcommand: --help` / exit 2. The unknown-
   subcommand branch also includes the banner so users see how to
   recover. The PR description for SafeRL-Lab#80 said the spike-daemon alias was
   "preserved" — this closes the gap.

3. The three serve-mode startup prints (`token: …`, `cheetahclaws daemon
   listening on …`, `audit log: …`) now `flush=True` so they appear
   immediately when stdout is redirected to a file under `&`. Previously
   they sat in Python's 4 KB block buffer until the daemon exited,
   silently breaking the spike-notes' `--print-token > out.log &`
   workflow because the token line never reached disk.

4. `tests/e2e_daemon_skeleton.py::test_daemon_writes_discovery_and_token`
   token-length floor raised from `>= 32` to `>= 40`. `secrets.token_urlsafe(32)`
   yields ~43 chars, so the previous floor was loose enough that an
   accidental shrink to 16 raw bytes (~22 chars) would still ship green.

Tests: 10 new unit tests (4 covering `cli.main` dispatch, 4 covering
`_resolve_token_path`, 2 covering `discovery.make_info`'s new field).
Full suite 669/669 passing on `main`. End-to-end smoke verified all
three runtime fixes against `cheetahclaws serve --listen tcp://...`.

Docs:
* `README.md` docs index — adds row for RFC 0002 (foundation roadmap);
  refreshes the spike row to reflect the actual landing path
  (SafeRL-Lab#77 → reverted → re-landed via SafeRL-Lab#81); marks F-1 as merged via SafeRL-Lab#80.
* `docs/RFC/0002-daemon-foundation-roadmap.md` — F-1 status `OPEN`
  → `MERGED SafeRL-Lab#80`.
* `docs/architecture.md` — daemon section now mentions the optional
  `token_path` discovery field and notes that the daemon-control verbs
  use it.
* `docs/news.md` — May 2, 2026 entry covering the spike re-land and
  F-1 merge sequence, the polish nits, and the intentional "not in F-1"
  list (agent.run, bridges, SQLite, cost guardrails, agent-runner
  subprocess, macOS peer-cred).

Refs SafeRL-Lab#68, SafeRL-Lab#74, SafeRL-Lab#80, SafeRL-Lab#81

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant