Foundation Scheduler — Agentic Cron
- Area: Foundation
- Path:
services/foundation/scheduler - Kind: Agentic cron — runs prompts on a schedule, executes inside
engines/sandbox, dispatches results via Kode Relay - Status: v0.1.0 — foundation shipped (2026-05-24); follow-ups #013–#017 (real sandbox executor, real relay dispatch, active/standby leader election, Koder ID JWKS, OpenAPI emission)
Role in the stack
scheduler is the Koder Stack's agentic cron. It owns the question "run prompt P on schedule S as agent A, deliver to channel C" — the missing layer that turns one-shot agent invocations into a durable, audited, time-aware workflow. Without it, every product re-implements its own cron + retry + result delivery (and most don't, so periodic AI tasks live as ad-hoc shell scripts on developer laptops). It pairs the engines/sandbox runtime (per-job isolation) with engines/kode-relay (multi-channel delivery) into one operator surface: HTTP API + kjob CLI.
The seven done/ tickets that predate v0.1.0 are research bench: feature-parity specs against Google Cloud Tasks, Cloud Scheduler, Cloud Functions, Cloud Batch, Composer, Workflows, and WorkflowExecutions. v0.1.0 is the first executable layer; #013–#017 unlock the production path.
Boundary vs neighbors
engines/sandboxis the per-job execution sandbox (v0 uses deterministic Stub; #013 wires the real backend).engines/kode-relayis the result dispatch channel (chatemailwebhook; v0 stub; #014 wires).services/foundation/idis the auth boundary (v0 static Bearer; #016 swaps to Koder ID JWKS).services/foundation/billing/enginewill receiveUsageEventfor each run when wired (planned follow-up beyond #017).services/ai/agentsis the natural agent driver — many scheduled prompts will be agent-loop invocations rather than raw LLM calls.
Features (v0.1.0)
- HTTP daemon
koder-scheduleron:9445 - Operator CLI
kjob(list / create / get / delete / run-now / runs) - 5-field cron +
@every <duration>shorthand - In-memory Job + Run store with per-tenant slug uniqueness
- Tick loop (1s) that advances
NextFireand dispatches viaExecutor - Pluggable
Executorinterface: deterministic Stub (v0), typed sandbox + relay stubs returningSCHED-BACKEND-UNAVAILABLE-001referencing #013/#014 - Bearer middleware with
Identity{TenantID, UserID, Admin}+ dev-mode short-circuit - Per-
(tenant, op)quota counter with daily window (default 100 jobsday, 200 runsday) - Cross-tenant isolation: reads from a different tenant return 404 (not 403), per
policies/multi-tenant-by-default.kmd - Go SDK
engines/sdk/go/scheduler/
Primary couplings
| Producer | Relationship |
|---|---|
engines/sandbox |
Per-job execution sandbox (#013) |
engines/kode-relay |
Multi-channel result dispatch (#014) |
services/foundation/id |
Bearer / JWKS auth (#016) |
infra/data/kdb-next |
Persistence + leader-election keyspace (#015) |
| Consumer | Relationship |
|---|---|
services/ai/agents |
Schedules periodic agent runs |
services/ai/eval |
Periodic regression suites |
services/foundation/reporter |
Scheduled report generation |
| Product backends | Tenant-scoped cron (daily summaries, weekly digests, periodic data sync) |
RFC and bootstrap
- RFC:
services/foundation/scheduler/docs/rfcs/RFC-001-scheduler-cron-agentic.md(scaffold, ratified) - Foundation tickets shipped:
#008(cron + JobRun store + tick loop),#009(Executor interface + Stub + typed sandboxrelay stubs),#010(HTTP API + kjob CLI + Go SDK),#011(multi-tenant Bearer + per-tenant quota),#012(SCHED-* error map + TOML config) - Follow-up tickets:
services/foundation/scheduler/backlog/pending/{013..017}
Self-hosted-first analysis (5 gates)
| Gate | Status | Notes |
|---|---|---|
| G1 — Feature parity | Partial | v0.1.0 covers cron + run history + manual run-now. Per-tenant CRUD covered. Distributed scheduling (active/standby) + real sandbox execution + result dispatch are the gap vs Cloud Scheduler / Cloud Tasks / Apache Airflow. |
| G2 — Performance | Not measured | v0 is in-memory single-process — bench-worthy after #015 lands. |
| G3 — Operational maturity | Pre-prod | Single-node; no leader election; no persistence beyond process lifetime. #015 closes leader gap. |
| G4 — Self-host security | OK | Bearer + per-tenant isolation (404, not 403). JWKS via Koder ID in #016. |
| G5 — Ecosystem depth | Bootstrapping | Go SDK shipped; DartPythonCLI clients deferred until consumer demand. |
Promotion to "shadow-active" (vs Google Cloud Scheduler / Airflow) requires #013 + #014 + #015 closed.
Variants (per specs/variants/taxonomy.kmd)
scheduler-backend-linux— koder-scheduler daemon (Go, Linux amd64 + arm64)scheduler-cli-linux— kjob (Go, Linux amd64 + arm64)