Skip to content

ADR-0001: No-Daemon Invariant

  • Status: Accepted
  • Date: 2026-04-14
  • Supersedes: None

Context and Problem Statement

nubos-pilot must run inside existing agent CLIs (Claude Code, Codex, Gemini, OpenCode). Any long-lived background process, RPC server, or OS-level service registration would break the install-anywhere promise and directly violate PROJECT.md's Core Value ("ohne eigenes Daemon"). The question is binary: should nubos-pilot ever spawn or require a background process?

For the purposes of this ADR, "daemon" means any one of:

  1. An OS-level service (systemd unit, launchd agent, Windows service).
  2. A long-lived runtime process kept alive between slash-command invocations.
  3. An RPC server exposing a local port, socket, or pipe.
  4. A between-invocation file-watcher or async-job runner.

What does NOT count as a daemon: a short-lived, foreground node process launched by a slash-command's bash block that exits when its work completes. That is an ordinary synchronous invocation, not a background process.

Decision Drivers

  • Install-anywhere — no sudo, no systemd/launchd, no Windows service registration.
  • Multi-runtime compatibility — all four target runtimes treat this tool as a synchronous set of slash-commands. None of them host background services.
  • Simplicity — no process lifecycle to reason about; no "is it running?" diagnostics; no log rotation; no PID files.
  • Security / footprint — no always-on listener, no accidental RPC surface, no persistent state in a running process.

Considered Options

  • Stay daemon-free — in-session, foreground-only execution via short-lived node invocations. (CHOSEN)
  • SDK-embedded coding-agent runtime — adopt a persistent coding-agent SDK as a runtime layer.
  • Cross-session daemon via launchd/systemd — a user-installed service that auto-advances plans while no agent CLI is open.
  • RPC multi-agent system — spawn local worker processes communicating over sockets to achieve real parallelism beyond Claude's Task tool.

Decision Outcome

Chosen: "Stay daemon-free", because it is the only option that satisfies install-anywhere + multi-runtime compatibility + simplicity drivers simultaneously. Any feature that would require a persistent background process is out of scope by construction; the same user intent can be satisfied via the in-session auto-advance loop (np:autonomous) which runs inside the agent CLI's own session.

Consequences

  • Good — any feature that requires a daemon is out of scope by construction; the invariant resolves scope disputes before they start.
  • Good — the tool is fully removable by deleting files; there is no service to stop, no PID to kill, no socket to clean up.
  • Good — no security surface from an always-on listener; no accidental RPC port; no attack surface grown by simply installing nubos-pilot.
  • Good — install works on machines where the user cannot sudo (corporate/managed environments, air-gapped dev boxes).
  • Bad — background auto-advance while the user's agent CLI is closed is impossible. Mitigated by np:autonomous (in-session loop). The cross-session variant is explicitly deferred and would require a future ADR that supersedes this one.
  • Bad — we forgo a richer SDK-embedded interactive loop; mitigated by the fact that the four supported agent CLIs already provide their own interactive loops — we compose with them instead of competing.

Pros and Cons of the Options

Stay daemon-free — chosen

  • Good — .cjs files invoked inline from slash-command bash blocks require zero persistent processes; the implementation cost is bounded and well-understood.
  • Good — zero supply-chain exposure from a daemon framework.
  • Good — lines up with PROJECT.md Constraint "Keine eigenen Prozesse".
  • Bad — we must implement auto-advance as an in-session loop rather than a scheduled background worker; accepted cost, captured by np:autonomous.

SDK-embedded coding-agent runtime — rejected

  • Good — provides a richer interactive loop and a unified tool/capability abstraction.
  • Bad — reintroduces a runtime; directly contradicts PROJECT.md Constraint "Keine eigenen Prozesse".
  • Bad — couples the tool's lifecycle to a library's API stability.
  • Bad — maintaining a process means maintaining crash-recovery, log files, and version migrations — all scope we explicitly reject.

Cross-session daemon via launchd/systemd — rejected (deferred)

  • Good — would enable true "leave it running overnight" plan execution.
  • Bad — requires per-OS service registration (root on Linux, launchctl on macOS, Service Control Manager on Windows); install-anywhere dies.
  • Bad — requires PID/lock management that the synchronous in-session model avoids entirely.
  • Deferred — REQUIREMENTS.md FUT-06 captures this as future-scope; adoption would require a new ADR superseding ADR-0001.

RPC multi-agent system — rejected

  • Good — would unlock true multi-agent parallelism beyond Claude's in-session Task tool.
  • Bad — requires a long-lived server process — the exact thing this ADR forbids.
  • Bad — the parallelism Claude's Task tool already provides is sufficient for the scope outlined in PROJECT.md.
  • Bad — introduces local-socket attack surface for negligible benefit over in-session Task.

More Information

  • Related ADR: ADR-0004 — atomic-commit-per-unit works precisely because no daemon holds state across sessions; each commit is self-contained.
  • PROJECT.md: §"Constraints" — "Keine eigenen Prozesse: alles läuft inline im Agent-CLI".
  • CLAUDE.md: §"External runtime SDKs" — runtime coding-agent SDKs are explicitly prohibited.
  • REQUIREMENTS.md: §"Out of Scope" → "Eigene Runtime / Daemon / Background-Prozess", "Cross-Session Daemon", "Echtes RPC-basiertes Multi-Agent-System".