Running it on a server

Leave it running, and reach it safely

Goobers is self-hosted — no managed service, no hosted tier. A cloud VM runs the same single binary as your laptop, left unattended. The Kubernetes-and-Temporal tier is a deployment goal, not something you can run at v0.3.0 — quarantined, not a path.

01

goobers up

The daemon: an embedded scheduler (cron triggers and run conditions), the local runner, a loopback HTTP API, and a webhook listener if one's configured. On startup it resumes runs a prior crash interrupted before admitting new work, from their last durable checkpoints.

instance.yaml is read once, at startup — changing it needs a restart. --watch-config is narrower than that: it separately watches direct edits to the materialized config/ directory, a process-local development convenience, not how a server picks up definition changes (that's below).

02

Install it as a service

goobers service install
goobers service start
goobers service status

Wraps systemd on Linux, launchd on macOS, and the Windows Service Control Manager. install registers, enables, and starts it with restart and backoff preconfigured, and never overwrites an existing registration. It's per-user on Linux and macOS, since the credentials it runs with are the user's; Windows needs an elevated terminal. Updates go through self-update, never a reinstall. The daemon — and every stage it runs — inherits the service's environment, not your shell's dotfiles.

03

Shutting down cleanly

The first SIGINT or SIGTERM stops new work and drains. The drain is indefinite by default — there's no implicit timeout. --drain-timeout sets a deadline, and its default value of 0 means no deadline, not immediate shutdown. A second signal always forces a shutdown without prompting. A skipped drain is a dirty restart, and the daemon records that on its next start — the absence of a dirty-restart event is how you confirm every prior restart went graceful.

04

Staying current

goobers self-update --policy on-release

Three policies: manual (a specific release tag), on-release (the default), and on-main (the configured branch). Every policy stages the new binary and smoke-checks it before requesting supervised activation, rather than replacing the running binary in place. Config is never touched by a self-update.

05

Disk

goobers runs du
goobers runs list
goobers telemetry prune
goobers telemetry compact

runs du and runs list report journal disk usage; retention pruning past that point is opt-in and is still reporting until you configure it, not automatic cleanup.

06

Changing definitions while it runs

Definitions live in git; the running daemon never rewrites them. A Git workflowSource reconciles its tracked ref continuously: local ref changes wake the loop immediately, a periodic fetch-and-compare poll is always active underneath that, and an authenticated GitHub push delivery wakes it too, when webhook.secret is configured. An invalid revision is rejected outright and the last-known-good definitions keep running; a run already in flight stays pinned to the version it started on. goobers apply forces reconciliation immediately instead of waiting for the next poll, and goobers config diff catches drift against a canonical tree on demand.

07

Reaching it from another machine

Loopback is unauthenticated by design — fine for a solo laptop, not for anything else. A reverse proxy, tunnel, port forward, published container port, or any other non-loopback listener all count as exposure, and every one of them requires both TLS and OIDC on api.auth — there is no insecure override. Roles are ordered: admin includes operate and view, and operate includes view. An authenticated principal with no mapped role is denied, and a discovery or signing-key failure fails closed rather than falling back to anonymous access.

RequestResult
No token401
Valid token, mapped role200
Valid token, no mapped role403
Wrong issuer, audience, or expired401

Full IdP registration and the tier-3 Entra posture are in the product repo.

08

Not yet

There is no atomic cross-instance claim lock. Running two instances against one repository is a soft boundary today — a disjoint required label per instance plus a distinct branchNamespace, and neither alone is sufficient. Full pattern in the product repo .