start
Bring the-loop up: one command that reads the CLI config and starts, detached, every service it enables (issue-228, decision-084).
the-loop start| Service | Enabled by | Default |
|---|---|---|
| Control-plane service (REST + dashboard) | service.enabled | on |
MCP endpoint (/mcp, mounted on the service) | service.mcp.enabled | on |
| GitHub webhook receiver | webhooks.ghWebhook.enabled | off |
| Poller | polling.enabled | off |
| Slack Socket Mode listener | channels.slack.enabled with read.mode: socket | off |
| Standing sessions | standingSessions.enabled | off |
The ingresses are explicit opt-ins: a config that merely describes a receiver or a polling source must not open a port or start a loop. start prints one line per service — started, hosted (see below), already-running (start is idempotent), disabled (naming the key that enables it), misconfigured (an enabled poller with no polling.sources, or none of the top-level repositories it would poll), or failed (pointing at the service's logfile) — and exits 0 only when every enabled service came up. One service failing never hides the others' outcomes.
One process by default
With the service enabled and service.hostIngresses at its default (true, issue-231), start boots one process: the service, which runs the enabled ingresses as background threads inside its own lifespan — and, since issue-334, the Slack Socket Mode listener when the channel reads that way, so the long-lived connection to Slack comes up with start and needs no shell of its own. Each hosted ingress still holds its own pidfile lock — under the service's pid — so status, stop and the daemons API answer unchanged, and an ingress already running standalone is skipped with a warning, never fought over.
$ the-loop start
service started [enabled] started at http://127.0.0.1:4114; /mcp exposed
gh-webhook hosted [enabled] in the service process (pid 24846)
poller hosted [enabled] in the service process (pid 24846)
slack-listener hosted [enabled] in the service process (pid 24846)The listener has no standalone daemon form: with hostIngresses: false its row reads manual and names the-loop channels listen, the foreground form, which takes the same lock. A listener whose tokens are not in the service's environment is reported failed with the missing variable named.
Set hostIngresses: false to keep every enabled service in its own process (fault isolation). Then each daemon is spawned detached (its own session, output to its logfile under state.root):
$ the-loop start
service started [enabled] started at http://127.0.0.1:4114; /mcp exposed
gh-webhook disabled [disabled] webhooks.ghWebhook.enabled is false
poller started [enabled] spawned pid 24913; logging to .the-loop/logs/poller.outIn either mode start waits for the proof that a service is genuinely up — the service's /health, an ingress's pidfile lock — before reporting success.
Standing sessions
With standingSessions.enabled, start also brings up every declared session whose autoStart is true — after the service, so anything they run can reach it — and prints them in their own section:
$ the-loop start
service started [enabled] started at http://127.0.0.1:4114; /mcp exposed
gh-webhook hosted [enabled] in the service process (pid 24846)
poller hosted [enabled] in the service process (pid 24846)
standing sessions:
supervisor resumed resumed loop-standing-supervisor (claude 0f3a…)A session whose pane is already alive is already-running and is not touched; one with a recorded conversation is resumed, not restarted from nothing. See standing.
Foreground and cron forms
start composes daemons; it does not host one in your shell. For a supervisor (systemd Type=simple) or a cron job, run the daemon entry point directly:
python -m the_loop.daemon_entry poller # foreground run loop
python -m the_loop.daemon_entry poller --once # one poll cycle and exit (cron)
python -m the_loop.daemon_entry gh-webhook # foreground receiverThese replace the removed the-loop poll start [--once]; the run loop itself is unchanged (lock, dependency checks, heartbeat, config hot-reload).
See also
stop·status·restart- The control-plane service and the webhook receiver — what each service is and how to talk to it (
/mcp, verification, guards). The granularservice/gh-webhook/pollcommands are gone (owner review on PR #229): this one surface is the lifecycle.