How the hosted service at loop.goodone.si is set up and deployed. This is for whoever runs the service; people using Loopable only need runners.md.
Since October 2026 the hosted service is paused while Loopable becomes a desktop app (desktop.md). LOOPABLE_SITE_ONLY=1 in wrangler.jsonc makes the Worker serve the front page and its legal pages and nothing else: the app's pages go to the front page, sign-in and the runner API answer 410 with where Loopable went, and nothing reads the database. The cron is gone, nothing wakes the dispatcher, and the container stops after ten idle minutes, so it costs nothing.
Everything else is kept as it was: the database and its data, the Worker's secrets, the container's definition and the deploy workflow. To run the hosted service again, remove LOOPABLE_SITE_ONLY, put the cron * * * * * back, and deploy. The dispatcher should then keep itself awake again, as onActivityExpired renewing its timer used to.
| Part | Where | What it does |
|---|---|---|
| App Worker | Cloudflare Worker loopable, at loop.goodone.si |
Front page, the app, sign-in, the API runners call |
| Dispatcher | Cloudflare Container beside the Worker | Watches services, queues jobs, writes answers back; applies migrations on start |
| Database | Turso, in aws-us-west-2; the Worker's placement in wrangler.jsonc sits next to it, and must move with it |
Every workspace's loops, tasks, connections, encrypted secrets |
| Runners | People's own machines | Run the agent; installed with npm install -g loopable-cli |
The Worker wakes the dispatcher on every request and once a minute from a cron trigger. There is one dispatcher for everyone.
-
Database. Create a libSQL database, such as
turso db create loopable, and an auth token for it. -
GitHub OAuth app. On GitHub, under Settings → Developer settings → OAuth Apps, create an app with:
- Homepage URL:
https://loop.goodone.si - Authorization callback URL:
https://loop.goodone.si/api/connectors/github/callback
That one callback covers both signing in and connecting GitHub. The callback tells them apart by the
stateit gets back. - Homepage URL:
-
Google OAuth client (for signing in with Google, and for Gmail). In Google Cloud, create a client of type Web application with the authorized redirect URI
https://loop.goodone.si/api/connectors/gmail/callback. It covers both signing in with Google and connecting Gmail.Enable the Gmail API. On the OAuth consent screen, add the scopes
openid,emailandprofilebeside the Gmail ones, and publish the app; while it is in Testing, only the test users listed there can sign in. -
Secrets on the Worker. From a checkout, signed in to wrangler:
./scripts/hosting-secrets.sh
It asks for each value and generates
LOOPABLE_MASTER_KEY. Keep a copy of the master key: every stored credential is encrypted with it. -
Deploy secrets for GitHub Actions. In the repository settings, add
CLOUDFLARE_API_TOKEN(with Workers, Containers and DNS edit) andCLOUDFLARE_ACCOUNT_ID, and in the production environment,LOOPABLE_DATABASE_URLandLOOPABLE_DATABASE_AUTH_TOKEN, so a deploy can migrate first.
Merging to main deploys: once CI passes there, the Deploy workflow migrates the database, builds the Worker and the dispatcher's container image (which needs Docker, so it is built there), and deploys both. Run it by hand to redeploy or roll back. The whole flow is in release.md.
Done in October 2026, and kept for reference. loop.goodone.si used to point at the old site Worker, loopable-web. To hand it to the app:
- In the Cloudflare dashboard, under Workers & Pages →
loopable-web→ Settings → Domains & Routes, removeloop.goodone.si. - Run the Deploy workflow. The app takes loop.goodone.si.
- Check
https://loop.goodone.sishows the front page, and that signing in works.
The old Worker was then left as a redirect from loopable-web.sobear-me.workers.dev to the app. Its source is gone from this repository; the deployed Worker stays up until it is deleted in the Cloudflare dashboard.
Each workspace can have up to 20 loops and 5 runners, and a loop is looked at no more than once a minute. Change them with the Worker variables LOOPABLE_LIMIT_LOOPS, LOOPABLE_LIMIT_RUNNERS and LOOPABLE_LIMIT_MIN_POLL_MS.
LOOPABLE_HOSTED=1 LOOPABLE_MASTER_KEY=local LOOPABLE_HOME=$PWD/.hosted PORT=4321 pnpm devThis runs the app, sign-in and workspaces on a local file database. Signing in uses the development apps in config/oauth-app.json, registered with callbacks on http://127.0.0.1:4321; copy config/oauth-app.example.json to start. Open the app at http://127.0.0.1:4321, not localhost, and stop pnpm dev first since it uses the same port. Connect a runner from the checkout with the token from the local Runners page: pnpm runner --token TOKEN. It joins http://127.0.0.1:4321 and keeps its state in ~/.loopable-dev, apart from a real runner.