Skip to main content

Task automation security

Durable Tasks preserve Kaizen's interactive trust boundaries. Scheduling changes when work starts. It does not create new identity, credential, approval, model, tool, or sandbox authority.

Trace member consent, workload proof, run reservation, fenced execution, and one exact protected effect.

Two identities travel with every unattended action, and neither can stand in for the other. The member is the subject — the durable owner of the delegation and of anything it costs. The registered workload is the actor — proof of which code is running, and a ceiling it cannot exceed. Authority is what remains after intersecting the two, never their sum.

Ownership comes from the platform envelope​

Task ownership comes only from the validated Kamiwaza forwarded identity envelope. Task request bodies, query parameters, chat tool arguments, and queue messages cannot supply an owner, role, delegated principal, or credential.

Each task stores a non-transferable, server-owned actor binding plus safe owner display metadata. Definitions, tests, controls, and list and detail responses are owner-scoped. Shared Projects and conversations do not lend another member's task control or credentials.

Task data is private​

Inputs, selected references, destinations, schedules, limits, tests, and outputs are private to the task owner, unless an existing destination policy separately authorizes access.

Member responses expose bounded safe diagnostics — not raw provider errors, credentials, hidden reasoning, or sensitive worker logs.

A run's retained output is read back at exactly the sensitivity of the conversation it was written into. Every run writes into one deterministic private conversation it owns, and GET /api/task-runs/{run_id}/output resolves ownership from the forwarded envelope before it reads anything: the run id is a selector, never authority, and a caller who does not own the run gets the same non-disclosing not-found as for a run that does not exist. The projection reads only journal fields already declared member-safe — the answer text and artifact handles — so model reasoning, tool payloads, prompts, credentials and provider errors are never read, let alone returned. Retention is the conversation's own: when the source is gone the run reports that its output is unavailable and why, which never rewrites the run's durable terminal state or invents an output.

Queue jobs contain opaque Core run references only. Workers rehydrate the definition from Kaizen and acquire current authority from Core.

Exact targets, current access​

Creation preview resolves the selected Library target under current access and pins an immutable version by default. A saved prompt whose list response lacks a version is resolved once through the server, then previewed again as an exact pinned version before creation.

New member-authored scheduled definitions accept saved prompts and prompt chains only. Agent rows are retained for history, and ordinary Agent schedules remain blocked before worker execution. The narrow exception is a server-marked, disabled-schedule, one-time run promoted from an accepted Chat input. A member or model cannot manufacture that marker through Task authoring.

At draft run, at dispatch, and before side effects, Kaizen revalidates membership, target version, Library references, destination, tool grants, credentials, limits, and policy. Revocation or drift blocks fail-closed.

Member-plus-workload authority​

Task rows never store browser bearer tokens, connector secrets, workload secrets, MFA state, or copied role claims. The single exception is the encrypted, single-use draft test model grant described below, which lives in its own table and is cleared the moment it is used.

Core separates the consenting member (sub) from the registered Kaizen workload (act). Turning a task on is the member's consent: Kaizen creates the Core intent and approves that exact intent with the member's live session, which Core authenticates independently. It yields an opaque, revocable automation-grant reference bound to both identities, the exact task revision, targets, resources, actions, budgets, policy, and expiry.

The task-control API role may create intents and reserve or observe runs. The task-executor worker role may claim, heartbeat, observe cancellation, transition a fenced run, reserve and transition effects, and request bounded credential use. The manifest grants neither role arbitrary Core access.

Each process reads a short-lived projected Kubernetes service-account token from the fixed assertion path. Core validates it through the strongest healthy registered profile, with online TokenReview preferred over the registered offline baseline, then binds short-lived authority to a fresh P-256 DPoP key. Assertions, proof keys, proofs, run/effect capabilities, and broker handles are redacted and non-pickleable. Only opaque grant, run, claim, effect, resource, and credential-binding references plus safe revision/fence evidence may be durable.

The workload assertion authenticates Kaizen but cannot impersonate the member; the member grant cannot authorize an unregistered workload. Queue data, actor strings, local grant rows, and stored snapshots grant nothing. Current member authority, grant state, workload revision, activation epoch, claim fence, resource registration, policy, quota, and readiness are re-evaluated by Core.

The legacy local mode remains only for safe-test and fixture paths. There the stored grant is a revocable authorization fact, not a credential, and the local principal has no platform roles. It carries authorization headers from exactly two sources: the deployment's own platform service identity when one is configured, or, for a safe test on a deployment without one, the member's draft test model grant. A write still must pass the resolved member permission mode, the live task lease and current definition/target checks, and the tool's own resource authorization. Safe-test grants omit write. Sensitive actions remain excluded because a headless worker cannot satisfy the global MFA floor. Kamiwaza workspaces, the data catalog, and other platform resources stay unavailable unless separately authorized.

task_capability_grant contains no token, credential, header, cookie, password, signing key, or reusable delegation artifact.

Draft test model grant​

A safe test is the only task run a member starts with a live identity envelope in hand. On a deployment with no platform service identity, nothing else can authorize that run's model calls, so Kaizen lets the member's own bearer reach that one run and no other. This is a deliberate widening of what a background run may hold, and each property below is enforced in code rather than assumed:

  • Issued only where needed. The API edge seals a grant only when the deployment has no service identity and the member's request carries a platform bearer. A deployment with a service identity authorizes safe tests as itself and never stores a member credential.
  • Least material. Only the promoted authorization bearer is sealed. Cookies, workroom assertions and role claims stay at the edge.
  • Encrypted at rest with AES-GCM under KAIZEN_FIELD_KEY. The associated data names this grant kind, so a document upload grant or any other ciphertext sealed under the same key cannot be opened as one.
  • Bound to the purpose task_draft_test, the owner, the task, the exact test run and that run's test capability grant. The ciphertext authenticates all five, and the row is addressed by the same coordinates, so another member, another run, another task or a substituted capability grant opens nothing.
  • Test-only. Only a test-mode run's execution resolution looks a grant up. Scheduled runs and Run now never do, and later read or write resolutions in the same test carry no platform authorization.
  • Single-use. Consumption marks the row consumed and clears its ciphertext in one row-locked statement, so a retried job, a re-claimed lease or a concurrent worker finds nothing to open. A grant that fails to open is spent as well, so a refusal cannot be retried into acceptance.
  • Expiring with the run's test capability grant (TASKS_LOCAL_TEST_GRANT_TTL_SECONDS). An expired grant is refused, and issuing any new grant purges every expired, unconsumed one.
  • Audited as task.run.model_grant.issued, .consumed and .refused. No audit payload carries the bearer.

A safe test that reaches the worker without a usable grant still fails closed, before any model call, as draft_test_model_grant_unavailable. Unlike platform_authority_unavailable it offers the member Test again, because a new test from a live session seals a new grant.

Residual risks, stated plainly. The bearer keeps its own platform lifetime: a test that starts after the member's session token expires fails at its first model call, and a long test can outlive the token mid-run. A test that is re-executed after its first execution attempt, for example after a worker crash, has already spent its grant and ends draft_test_model_grant_unavailable. An issued grant whose test never starts keeps its ciphertext until it expires and the next issue purges it, or until the run is deleted.

Approval behavior​

A task stores either inherit or an explicit member permission mode. Inherit resolves the current workspace, owner, and per-agent defaults at each attempt; an explicit task mode wins. The safe default asks when a tool declares that it needs confirmation. Ask-before-writes pauses on every write, read-only denies writes, and never-ask permits otherwise authorized writes without a member prompt. Sensitive actions still deny without MFA.

Browser action tokens, interactive MFA state, and request-supplied bypass fields never authorize scheduled work.

Core parks the exact effect when policy requires approval. The approval record binds member, workload, task and run revision, claim fence, canonical request digest, resource/action, policy, quota, credential binding, approver, and expiry. Approval is not an auto-approval rule and does not execute the effect. Resume rechecks all current authority and issues a fresh one-use capability; denial, expiry, revocation, drift, or cancellation closes it.

When member approval is required, Kaizen persists an exact one-shot request, releases the sandbox, and atomically transitions the run to awaiting_approval. That transition clears the task lease and owner-concurrency slot. Approval queues the same run for a fresh fenced attempt; denial is terminal. A release failure blocks rather than creating an approvable request.

Authority is re-proved at the moment of effect​

Before dispatch, Kaizen reserves the idempotent Core run against the active grant and immutable occurrence. A worker atomically claims it, binds the returned claim, authority deadline, and monotonic fence to the exact Kaizen revision, then resolves current target access.

Before every model call, credential use, external write, or sensitive tool decision — and again inside the protected callback — the shared runtime reserves one exact effect and invokes a memory-only authorizer. It verifies the run claim/fence, grant, workload activation, task definition, member access, resource contract, request digest, policy, quota, approval, and cancellation. Server-side model calls are routed to the platform origin Kaizen is given, because an extension cannot observe which ingress controller a deployment runs and must not name one. Whatever transport carries the request, the proof and the resource decision stay bound to the receiver's registered public HTTPS authority; the transport address never becomes authority.

Failure returns one content-minimized authority denial. Credentials and raw provider errors are never persisted.

Calendar and occurrence integrity​

Browser time, browser timers, worker wall clocks, and Valkey are not schedule authority. PostgreSQL time owns due selection.

Preview and dispatch use one IANA evaluator with explicit gap and fold policy and an exact deployed timezone-data identity. Each immutable occurrence preserves its UTC instant, local wall time, offset, fold, schedule revision, and timezone-data version. Duplicate replicas and redelivery converge on deterministic occurrence and run identities.

Missed work, overlap, and replay safety​

Catch-up is never unbounded. Grace, backfill window and count, queue, concurrency, runtime, token, cost, and output limits are all server-capped.

Default recurring work skips missed windows; late one-time work expires. Queue-one permits only one pending occurrence. Cancel-replace requires conservative replace-safe classification, or it policy-blocks.

Ambiguous external effects never retry without explicit durable no-effect evidence.

Broker and restart boundary​

The database transaction commits occurrence and future cursor, and Core idempotently reserves the mapped run, before broker enqueue. Broker messages contain only opaque Core run references with deterministic job IDs.

Handoff repair may redeliver the same reference, but Core's atomic claim and monotonic fence let exactly one executor continue. Restart recovery never reconstructs authority from queue data or identity snapshots — each attempt repeats workload proof, claim, current-member, grant, policy, resource, and access checks. Failure closes before the shared runtime or any external effect.

Chat task management​

Every feature-enabled chat agent receives the same shared task inspection and management tools by default. Read-only capability ceilings may inspect tasks but cannot mutate them.

Writes pass through the shared capability ceiling and write guard before reaching the same owner-scoped task service, queue, and audit paths used by the member API. An agent cannot choose another owner or bypass task policy.

For a chat-promoted background job, Kaizen takes the conversation, accepted input, selected agent, version, and owner from server runtime context. The model may provide only bounded work text, a reason, requested limits, and an optional corpus selector. Library agents pin their immutable version. Built-in agents bind their current policy digest, and source-policy drift blocks execution.

An optional Goal adds outcome, constraints, and verification criteria but no authority. Kaizen normalizes and digests it, then binds a private envelope to the Task, exact accepted input, pinned Agent version, and definition revision. The member API redacts that envelope. The retired Tomo background marker is migrated in place and is not accepted by runtime policy after the upgrade.

Goal-backed loops are a closed server-created Agent target. They require both an end time and an occurrence cap, force skip-on-miss, zero backfill, and no overlap, and still require the normal safe test and Core consent before activation. There is no public request shape that admits a generic Agent schedule.

When a Goal needs input, Kaizen stores only a question digest and exact Task thread reference in the control ledger, releases execution leases, pauses the loop schedule, and notifies the owner. Resumption requires the exact pending request and run IDs, the current Goal revision and Agent version, and the exact accepted owner message loaded by the server. Goal steering has the same owner/exact-live-run binding and cannot carry model-authored instruction text.

The originating input is idempotent: repeating the tool call with the same work returns the existing run, while different work under that input is rejected. The one exception concerns a launch that never started because its consent failed. Different work under that input retries consent for the original request, the same member's own earlier request, and reports why it cannot start. That retry may now succeed and grant the original request, but nothing is launched. Once the original request can start, the different work is still rejected. An unattended background Task has the launch capability removed, so it cannot create a child background Task. Status and controls remain owner-scoped and use the existing Task run authorization and cancellation fences.

Cancellation​

Cancellation is durable first. Queued and retry-wait work becomes cancelled immediately. Running work receives the shared cancellation signal, loses side-effect authority at the task lease fence, and can no longer publish a stale success.

Corpus execution authority​

Corpus work remains a normal Task run. A selector supplies no connector, tool, egress, sandbox, model, write, sharing, or credential authority. Preview and activation resolve the selector for the authenticated owner; run start snapshots membership; every partition read re-checks current source lifecycle and ACL against the same bound principal.

Partition model calls enter the conversation-input runtime with stable idempotency. Only strict JSON Lines records cross into canonical corpus state. Source text, model output, record properties, and locators do not enter metrics or audit events. A later revocation redacts coverage and provenance detail while retaining content-free historical lineage.

Pause stops new partition scheduling and becomes durable at the next partition boundary. Resume retains the exact run and checkpoints. Budget exhaustion, malformed output, authority denial, cancellation, partial output, and success are distinct terminal facts; no partial corpus is labeled complete.