ADR-0022: Deployment model — two paths, one foundation, on-demand execution¶
- Status: Accepted
- Date: 2026-09-16
- Deciders: Jian (product owner)
Context¶
V9 (ADR-0021) makes a single-agent workflow real: it can be triggered by an event, call real apps (Slack/Gmail connectors), pause for a human, and act. That raises the obvious next question: once a user finishes authoring, how do they take it live? A planning discussion (2026-09-16) surfaced that "deployable" means two different things to the two personas (PLAN.md §Users), and that we should not conflate either with the V5 multi-tenant hosting stack.
Decision¶
1. Two deploy paths, one shared foundation¶
The trigger / execution / connector primitives are mode-agnostic. The same AgentSpec, engine,
and connectors run in both paths; only two things differ: who runs the process, and where the
credentials live.
- Self-host (the developer path).
kampong serve <spec>runs the workflow as a live webhook service on the developer's own machine, and the exported standalone project (plus a Dockerfile, follow-up) is a container image the developer runs anywhere — laptop, homelab k3s, a VPS, Fly, Cloud Run. Zero dependency on Kampong the platform (ADR-0002's no-lock-in guarantee). Credentials (connector tokens, model keys) come from the process environment (${ENV}), so "deploy" is "run the image with those env vars set." - Managed "go live" (the low-code path, SaaS). A Deploy action in the hosted UI provisions a webhook ingress URL and runs the workflow on the shared hosted server, using the workspace's stored credentials (the BYOK vault, KAN-1229) and durable runs (KAN-1231). The low-code user never touches Docker, ports, or DNS. This is a roadmap epic built on the V5 substrate + the V9 primitives — see "Consequences".
"Deployable = a container image" is the right answer for the developer; "Deploy button → it's live, we run it" is the right answer for the low-code user. Both are first-class; neither requires the other.
2. Execution is on-demand, not always-on¶
A trigger event drives one run on a shared process/server; there is no always-on, per-workflow
worker or container. On the laptop that shared process is kampong serve; in the managed path it is
the hosted server's run manager (KAN-1231), which already runs a durable run per request and would
simply be initiated by a webhook instead of an API call. Always-on per-workflow workers are heavier
and only needed for long-running/streaming/stateful agents, which single-agent event-driven
workflows are not (ADR-0001). Scheduled triggers, when added, need a scheduler; webhooks do not.
3. Trigger is a spec concept; ${ENV} locally, workspace vault when hosted¶
agent.trigger ({ type: "webhook" } today, room for schedule/others) is part of the spec, so
both paths and the canvas read the same declaration. Connector/model credentials are always
${ENV} placeholders in the spec (never literals); the resolver differs by path — process.env
for kampong serve / the exported app, and a per-workspace secret resolver (an extension of
resolveWorkspaceModelClient, KAN-1230, to connector tokens) for the managed path.
4. Sequencing: foundation first¶
The trigger/execution/connector primitives are buildable and testable now with no infrastructure, and are shared by both paths, so they come first:
- Now (KAN-1431):
agent.triggerschema +kampong serve(the laptop/self-host webhook service). - Next (follow-up card): the exporter emits a listening service + a Dockerfile, so the exported project is a runnable container image (the developer's "deployable artifact").
- Later (new epic): managed "go live" — webhook ingress, a deployment record + lifecycle (deploy/pause/redeploy), per-workspace connector secrets, and free/paid tier metering — on top of the V5 hosted backend, once that backend is actually deployed somewhere.
Alternatives considered¶
| Option | Why not |
|---|---|
| Only the self-host/container path | Leaves the low-code user (who won't touch Docker) with no way to go live; that "Deploy → it's live" experience is core product value. |
| Managed go-live first | Also requires actually standing up and operating the hosted server now; the shared primitives are needed either way, so building them first de-risks and reaches a demo faster. Chosen order is foundation-first (user decision). |
| Always-on container per workflow | Operationally heavy; unnecessary for event-driven single-agent workflows. Revisit only if long-running/streaming agents demand it. |
Hosted connector secrets in process.env |
Not multi-tenant-safe; the managed path must resolve per-workspace secrets from the encrypted vault, not a shared server env. |
Consequences¶
kampong serveand the exported container are the developer story and exist without any hosting.- The managed path is mostly assembly of things V5 already built (durable runs, BYOK vault, RLS) plus a webhook ingress and a deployment/lifecycle concept; it is a new epic, not part of V9's core.
- A per-workspace connector-secret resolver is required before the managed path can run connectors (extends KAN-1230). Tracked with the managed-go-live epic.
- Tiering (free vs paid allowances: live-workflow count, runs/month) sits on top of the deployment record as metering; deferred, but the deployment record should be shaped to allow counting.