Sub-skills
Deploy in depth
For your agentCopy this and give it to the AI you're building with.
Run `cubek skill`, then `cubek skill deploy`, read all of both and follow them exactly (no CLI: download https://cubek.dev/SKILL.md and https://cubek.dev/skills/deploy.md verbatim with curl; don't summarize them). Run `cubek check` after every edit until it is clean.
Previews, production, rollback, domains, secrets, logs, metrics and data
recovery. Every command takes --json and --help.
Sign in (once per machine)
cubek login # a human, in the browser (default https://api.cubek.dev)
cubek login --token T # headless: a personal token (cubek tokens create ci)
cubek whoami # on any 401/403: user, organization, roleCI can set CUBEK_URL and CUBEK_KEY instead.
Previews and production
cubek deploy # https://<name>--r<N>.cubek.app: a preview with a copy of production's data
cubek deploy --prod # the same revision becomes https://<name>.cubek.app
cubek deploy --prod -m "add invoices"
cubek revisions # every revision, * = production
cubek promote 12 # make r12 production
cubek rollback 11 # code back to r11, database kept
cubek rollback 11 --with-db # code and database back (the current db is snapshotted first)
cubek preview rm 12 # drop a preview's database copy- A revision is immutable; production is a pointer. A deploy compiles,
bundles
client/with bun and uploads only what changed (seconds). --prodsnapshots the database, applies additive migrations and switches atomically. Destructive schema changes stop with a message:--allow-destructiveafter reading it (database.md).- The project is created on the first deploy, named by cubek.json
name. - Staging clusters may serve plain http: use the URL the deploy prints.
Secrets
cubek secrets set STRIPE_KEY sk_live_... # production; read at the next request
cubek secrets list
cubek secrets --dev set STRIPE_KEY sk_test_... # cubek dev: .cubek/secrets.json (keep it out of git)// src/app.tsx
import { app, log, secrets } from "cubek"
app.get("/healthz", async (c) => c.text("ok"))
app.get("/api/status", async (c) => {
const key = secrets.get("STRIPE_KEY")
if (key === null) {
log.error("STRIPE_KEY is not set")
return c.json({ error: "payments are not configured" }, 503)
}
return c.json({ payments: key.startsWith("sk_live_") ? "live" : "test" })
})Never commit secrets or print them in logs; secrets.get returns null
when unset: handle it.
Custom domains
cubek domains add shop.example.com # prints the DNS records to create
cubek domains verify shop.example.com # check now (also automatic)
cubek domains list
cubek domains add example.com && cubek domains add www.example.com
cubek domains redirect www.example.com example.com # 308, path and query kept- DNS: a CNAME to
<name>.cubek.app, or (apex) the A/AAAA records the answer lists. HTTPS certificates are issued once the domain verifies. c.origin()gives the host the request came to: use it for absolute links.
Logs, metrics, data
cubek logs # last 100 lines: requests, log.*, tasks, errors
cubek logs --follow --level warn
cubek metrics --window 24h # requests, errors, p50/p95/p99, CPU, DB time, storage
cubek sql "SELECT status, COUNT(*) AS n FROM orders GROUP BY status"
cubek sql --write "UPDATE orders SET status = 'paid' WHERE id = '01J...'"
cubek db restore --to 2026-09-26T10:15:00Z # the database at that second, onto a preview
cubek db restore --promote # then make it production's
cubek project list- A 500 answers an empty body; its error is in
cubek logs. log.info("paid", { orderId }): structured data, searchable in the logs.- Point-in-time restore covers 7 days (30 on paid plans).
Workflow for agents
cubek checkclean,cubek testgreen, the routes tried oncubek dev.cubek deploy, try the preview URL, thencubek deploy --prod.- After production:
cubek logs --level warnand a request to/healthz. - Broken production:
cubek rollback <previous rev>first, fix after.