skela is a deploy platform that runs on your server. every part of it is a plug: where apps run, how they build, where code comes from, who answers dns. keep the built-ins, swap any of them, or write your own. paste a repo and it's live.
click a plug to swap it · dashed ones are extensions you'd write
skela.acme.shopexample workspace
one prompt
paste a git url, pick a github repo or a docker image. it's built, it's live at a free url, and every push redeploys. no sidebar, no forty settings pages.
skela.acme.shop
› https://github.com/acme/web13:39youcreated acme/web from github.com/acme/web13:40railpackbuilding main@7be01f313:41skelaweb live → web-acme.203.0.113.7.sslip.io13:52githubpush main@b82d1c4 · redeploying
agents drive it too
a built-in mcp server with scoped tokens: read or full, every project or a few. your extensions' routes are tools as well, and everything lands in one log.
mcp · token agent
› deploy { id: svc_api }13:42agentapi · main@b82d1c4 · build started› rollback { deploymentId: dep_7be01f3 }13:44agentapi back on 7be01f3 · no rebuild› set_extension_projects { porkbun → acme }13:45agentporkbun runs for acme only
deploys that don't break
start-first: a release passes its health check before traffic moves, or the live one keeps serving. rollbacks reuse the image, no rebuild.
skela, its postgres, traefik and your apps run on your server, one box or a swarm. secrets are sealed with a key in /var/lib/skela: back up that folder and one volume, and you have all of it.
root@203.0.113.7
$ ls /var/lib/skelaextensions vault.key$ ls /var/lib/skela/extensionsnotify porkbun$ # yours, beside the ones skela ships
// under the prompt
almost everything is an extension_
skela's core keeps projects, services, deploys and the log. the rest plugs in, and the built-ins use the same sdk you get: replace any of them, limit one to a few projects, or switch it off. drop a folder in your extensions dir and it loads; save a file and it reloads. no restart. pick one below to read its code.
extensions/notifyzsh
$ cat server.tsimport { defineExtension } from"@skela/sdk"import { Effect } from"effect"// a line in the log whenever a deploy goes liveexportdefault defineExtension({ id: "notify", setup: (ctx) => ctx.hooks.deployment.register({ onStatus: ({ service, deployment, url }) => deployment.status === "live" ? ctx.log(`${service.name} is live → ${url}`) : Effect.void, }),})$ # save it18:02extensionreloaded notify@0.1.018:04extensionweb is live → https://acme.shop