Operations
Two features for background work and operator-controlled feature gates.

Status: ✅ Stable
What: Persistence and operator tooling for jobs registered with
r.job(...). Built on BullMQ + Redis with lane routing (runIn: "api" | "worker"). Every run is written to store_job_runs /
store_job_run_logs.
How it works: r.job(name, { trigger, runIn?, … }, handler)
registers a worker. Handler signature is (payload, context), not
(ctx) alone.
| Trigger | How it fires |
|---|---|
{ manual: true } | jobs:write:trigger (operator / SystemAdmin) or JobRunner.dispatch(name, payload) |
{ cron: "0 9 * * *" } | Leader-elected schedule, read in the server’s zone |
{ cron: "0 9 * * *", tz: "Europe/Berlin" } | Same schedule, read in the given IANA zone |
{ on: writeHandlerOrEvent } | After the named write/event |
There is no ctx.jobs.enqueue. Manual runs go through the trigger
write handler or the job runner.
Cron time zone: Without tz, the cron fields are read in the zone of the
server process, which is UTC in the standard containers. Set tz to an IANA
name to schedule in local time, daylight saving included. An invalid zone aborts
the boot. A wall-clock time that a clock change skips runs once, shifted by the
size of the gap. A time that occurs twice runs once, at its first occurrence.
r.job( "morning-digest", { trigger: { cron: "0 9 * * *", tz: "Europe/Berlin" }, runIn: "worker" }, async (_payload, ctx) => { // runs at 09:00 Berlin time all year, 07:00 or 08:00 UTC },);Example:
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
defineFeature("ops", (r) => { r.job( "cleanup-old-attempts", { trigger: { cron: "0 3 * * *" }, runIn: "worker" }, async (_payload, ctx) => { // use ctx.db / ctx.notify / …, payload first, context second }, );
r.job( "send-incident-email", { trigger: { manual: true } }, async (payload, ctx) => { await ctx.notify!("incident-email", { to: payload["recipientId"] as string, data: { incidentId: payload["incidentId"] }, }); }, );});
// Trigger a manual job (SystemAdmin), not ctx.jobs.enqueueawait ctx.dispatch.write("jobs:write:trigger", { jobName: "ops:job:send-incident-email", // qualified name as registered payload: { incidentId: id, recipientId },});feature-toggles
Section titled “feature-toggles”Status: ✅ Stable
What: Global (not per-tenant) enable/disable for features that
opt in with r.toggleable({ default }). Operators flip state via
feature-toggles:write:set; the dispatcher gates disabled features
(feature_disabled). State lives in store_global_feature_state.
How it works: Declare r.toggleable({ default: false }) once on
the feature. There is no ctx.toggles, when a feature is off, its
handlers are unreachable and cross-feature hooks owned by that feature
are skipped. Load createFeatureTogglesFeature({ getRuntime }) and wire
GlobalFeatureToggleRuntime into the server’s effectiveFeatures
callback (see the recipe).
Best practice: when a toggle is fully rolled out, delete it from code. In tests set toggle state explicitly.
Recipe: samples/recipes/feature-toggles
Example:
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";import { z } from "zod";
export const billingFeature = defineFeature("billing", (r) => { r.toggleable({ default: false });
// When "billing" is globally off, this handler never runs : // the dispatcher returns feature_disabled. No ctx.toggles check. r.queryHandler( "invoice-list", z.object({}), async (_query, ctx) => { /* list invoices */ }, { access: { roles: ["Admin"] } }, );});metrics and metrics-system
Section titled “metrics and metrics-system”What: Dashboard data. Each metric declaration becomes a query that
aggregates a table and returns a value, a trend and rows for dashboard panels.
metrics serves the caller’s own tenant, metrics-system serves system admins
across tenants. admin-shell builds its overview pages from them.
These are not the Prometheus metrics from r.metric.
Setup, custom metrics and dashboard panels are in
Metrics and dashboard data.
cap-overview
Section titled “cap-overview”What: Read-only screens for plan limits. Tenant admins see a card per cap
with usage and limit, system admins get a list of caps across tenants.
admin-shell adds both to its navigation when the feature is mounted. Plans,
caps and showLimit are in Billing plans and checkout,
the options in the feature reference.
The framework’s cap overview reference
(German) covers the design decisions.
See also
Section titled “See also”- Bundled-features overview
- Audit & security
- Recipe
feature-toggles - Recipe
lane-routing, pin jobs to api/worker