move github sites
README.md

Self-hosted spindle #

Tangled runs no shared spindle; a repo can only run workflows on a spindle registered to an account. The mirror workflows run on one hosted on the same machine as the rest of this project, as two systemd user units: the spindle itself and a Cloudflare tunnel that gives it a public HTTPS name.

Machine-specific values (hostname, owner DID, tunnel id) are placeholders here; the live copies stay in ~/.config/spindle/spindle.conf and ~/.cloudflared/config.yml on the host.

Restoring on a fresh host #

  1. git ≥ 2.49. Ubuntu 24.04's stock 2.43 is refused; the git-core PPA supplies a new enough one.

  2. Build spindle from tangled.org/core with a current Go toolchain and put the binary at ~/.local/bin/spindle. The source clone doubles as the local reference for how the appview and spindle behave.

  3. Rootless Podman, with its user socket enabled (systemctl --user enable --now podman.socket).

  4. Cloudflare tunnel. Install cloudflared at ~/.local/bin/cloudflared, then cloudflared tunnel login, cloudflared tunnel create spindle, and cloudflared tunnel route dns spindle <spindle hostname>. Write ~/.cloudflared/config.yml from cloudflared-config.yml.example.

  5. Config. Copy spindle.conf.example to ~/.config/spindle/spindle.conf and fill in the hostname and owner DID.

  6. Units. Copy both .service files to ~/.config/systemd/user/, then:

    systemctl --user daemon-reload
    systemctl --user enable --now spindle.service cloudflared-spindle.service
    loginctl enable-linger
    

    Lingering keeps user units running with nobody logged in.

  7. Register the spindle on Tangled under the owner account, and point each repo that should use it at it in that repo's settings (web UI).

  8. Repo secrets (Tangled repo Settings → Secrets, web UI) live in the spindle's database, so a rebuild loses them; re-enter each one.

Checking it #

  • systemctl --user is-active spindle.service cloudflared-spindle.service
  • curl -s https://<spindle hostname>/xrpc/sh.tangled.owner returns the owner DID when the tunnel is up.
  • Recent runs: curl -s 'https://<spindle hostname>/xrpc/sh.tangled.ci.queryPipelines?repo=<repo did>&limit=5'. The repo DID appears in any pipeline triggered line of journalctl --user -u spindle.service.
  • Per-run detail is one JSON-lines file per workflow run under ~/.local/share/spindle/logs/; "kind":"control" lines mark step boundaries. The tail is post-run housekeeping, so reading only the last lines makes a passing run look truncated.

Behaviour worth knowing #

  • Secrets are withheld from runs whose source repo differs from the repo itself, so a fork's pull request cannot read them. A same-repo pull request does.
  • Tailscale Funnel was tried as the public ingress and abandoned: the ingress closed every external connection without presenting a certificate. Requests from the host itself resolve the tailnet name over MagicDNS and go through Serve instead, so they report success while nothing external can connect.