Runtime Settings

Configure storage, inputs, grants, and host settings for each runtime

Set runtime options in the host that owns your session. Command-line manifests and environment variables and private browser storage are different integration surfaces.

HostWhere settings live
Command LineServer/client manifests, job files, daemon profiles, and process environment
WebAssemblyExplicit original Worker configuration and private saved setup

Command Line

The manifests, shell commands, profiles, and environment settings in this section configure kaya, kayad, and the native tool server. Browser settings are described in the WebAssembly section.

Native model configuration

The Rust tool server owns provider connections and model bindings. For local text and decision models, kayad derives attachments and default session grants from one server manifest. An explicit client manifest selects advanced routing; kayad persists the session's admitted ToolMap. Ordinary text aliases are resolved through that authority, rather than through provider-name prefixes or legacy profile quality mappings.

Text model bindings

This server manifest configures the complete local text route for gemini-fast. Choose an upstream model available to your account, replace the database path, and keep provider credentials in the tool-server environment.

{
  "manifest_version": 1,
  "bind": "127.0.0.1:8789",
  "database": "/absolute/path/to/tool-execution.sqlite",
  "models": [{
    "provider_id": "chat-models",
    "display_name": "Text model bindings",
    "connectors": {
      "gemini-direct": {
        "protocol": "gemini",
        "credential": { "env": "GEMINI_API_KEY" }
      }
    },
    "bindings": {
      "gemini-fast": {
        "connector": "gemini-direct",
        "upstream_model": "replace-with-a-gemini-model-id"
      }
    }
  }],
  "admissions": [{
    "token_env": "KAYA_TOOL_SERVER_TOKEN",
    "tenant_id": "local-tenant",
    "principal_id": "local-user",
    "session_id": "local-session",
    "workspace_id": "local-workspace",
    "grants": [{ "provider": "chat-models", "operation": "generate", "allow_open_world": true }]
  }]
}

Save this as tool-server.json and set its provider credential:

export GEMINI_API_KEY='your-provider-key'
export KAYA_TOOL_SERVER_MANIFEST='/absolute/path/to/tool-server.json'
kayad start

With no KAYA_TOOL_CLIENT_MANIFEST, kayad starts its local tool server and uses an in-memory client configuration. New sessions receive every configured text or decision alias admitted by the manifest's single admission, with only its corresponding generate or decide open-world permission. Automatic setup does not choose a decision default. An explicit session ToolMap keeps its exact empty or narrower grants. Existing sessions retain their captured grants when you change the manifest and restart.

The admission's token_env must name a dedicated authentication variable. A supplied token of at least 16 bytes is used as given. If it is absent, the supervisor generates a private token for its lifetime and passes it only to its tool child and in-memory client. Provider credentials remain server-side; the generated token is never written to client files or session records. Invalid supplied tokens and authentication names shared with other server values are refused. Initial startup completes only after the owned tool server passes authenticated readiness.

For a configured bedrock_sigv4 connector, automatic setup also reserves AWS_*, SECRET_ACCESS_KEY, HOME, USERPROFILE, HOMEDRIVE, HOMEPATH, and PATH for the AWS credential chain and its profile/process resolution. Use a separate admission reference such as KAYA_TOOL_SERVER_TOKEN. The explicit client configuration path retains its existing operator-owned behavior.

Automatic setup requires a fixed nonzero loopback bind, one admission, and unambiguous admitted aliases. Multiple admissions or the same admitted alias on different providers require an explicit client configuration. It creates no image, research, agent or unrelated tool grants and chooses no default model.

Save this program as summary.kaya:

let summary = generate(model: "gemini-fast", message: "Write one sentence about Kaya")
"{{summary}}"
kaya run summary.kaya

Restart an existing daemon with these settings before running the program. A provider key alone creates no binding or grant. Local Ollama bindings in models use this setup for offline work. Scripted providers and other tool families require explicit client/session grants.

Explicit client configuration

Use an explicit client manifest for an independently supervised server, multiple admissions, or a chosen subset of model aliases. Its attachment connection and default ToolMap take precedence over automatic setup, including configuration errors. This matching tool-client.json freezes its chosen grants into new sessions:

{
  "manifest_version": 1,
  "attachments": [{
    "id": "rust-local",
    "endpoint": { "env": "KAYA_TOOL_SERVER_ENDPOINT" },
    "token_env": "KAYA_TOOL_SERVER_TOKEN"
  }],
  "default_tool_map": {
    "manifest_version": 1,
    "bindings": [{
      "capability": "kaya.model.gemini-fast",
      "interface": "kaya:ai/generate@1",
      "operation": "generate",
      "attachment": "rust-local",
      "provider": "chat-models",
      "allow_open_world": true
    }]
  }
}

For an independently supervised server, start the included kaya-tool-server executable in one terminal with the server manifest shown above:

export KAYA_TOOL_SERVER_TOKEN='replace-with-a-long-random-token'
export GEMINI_API_KEY='your-provider-key'
kaya-tool-server serve --manifest /absolute/path/to/tool-server.json

Start the daemon in another terminal with the same tool-server token:

export KAYA_TOOL_SERVER_TOKEN='replace-with-a-long-random-token'
export KAYA_TOOL_SERVER_ENDPOINT='http://127.0.0.1:8789'
export KAYA_TOOL_CLIENT_MANIFEST='/absolute/path/to/tool-client.json'
export KAYA_DEFAULT_MODEL='gemini-fast'
kayad start

If a daemon is already running, restart it with these connection settings. Existing sessions retain their captured ToolMap authority.

The provider key belongs to the tool server; this explicit connection token belongs to both processes. For more connector families and complete deployment examples, see Supported Models, the checked server manifest and client manifest.

Repository-linked examples on this page require Kaya repository access. The inline manifests above configure the included native executables without a source checkout.

Decision bindings

Configure finite decisions separately from ordinary generation. Add a decisions group to the server manifest, for example:

{
  "provider_id": "fast-decisions",
  "display_name": "Finite decisions",
  "connectors": {
    "router": {
      "protocol": "open_router",
      "credential": { "env": "OPENROUTER_API_KEY" }
    }
  },
  "bindings": {
    "fast": {
      "connector": "router",
      "upstream_model": "typesafe/jev-1.13",
      "reviewed_decision_support": true
    }
  }
}

Grant {"provider":"fast-decisions","operation":"decide","allow_open_world":true} in the server admission. Automatic local setup supplies the matching kaya.decision.fast session grant for admitted aliases. It does not choose a decision default. An explicit client or session ToolMap retains its exact authority.

For a program-carried default, the job configuration supplies the same manifest used by other tools:

program: ./main.kaya
tools:
  manifest_version: 1
  default_decision_model: fast
  bindings:
    - capability: kaya.decision.fast
      interface: kaya:ai/decision@1
      operation: decide
      provider: fast-decisions
      allow_open_world: true

This job grants only decisions. Add the existing generation and other tool grants when its program needs them. With an explicit client connection, add the matching attachment ID. The complete checked example includes both decision and general generation bindings, a matching client manifest, and a runnable program.

For all newly admitted daemon sessions, put default_decision_model: "fast" inside the explicit client's default_tool_map. Alternatively set KAYA_DEFAULT_DECISION_MODEL=fast before starting kayad; the host captures it once. Embedded hosts can supply the same optional default through ready AgentConfiguration. No executor code reads environment variables.

Routing precedence is the explicit call model, the session decision default, the captured host decision default, then the original generation path. An explicit generation alias opts that call into generation even when a decision default exists. The default does not affect generate() or deterministic primitive casts.

Bindings must declare reviewed native decision support. Text/image evidence, question/choice counts and serialized request bytes are checked against protocol and binding limits before dispatch. Images require an admitted image-capable binding and inline file bytes. TypeSafe Jev is text-only; Ollama cloud is unsupported. Refusal, contradictory responses, unknown IDs and ties fail explicitly; there is no automatic generation fallback. Provider confidence retains its native meaning rather than becoming a portable probability of correctness.

The default TypeSafe byte budget is a conservative 16 KiB, independent of the vendor's token budgets. Reviewed limits.max_request_bytes can change this application budget; upstream token/context rejections remain structured errors. Ollama's documented request limits remain enforced in addition to reviewed binding limits. Kaya never silently truncates evidence.

Review gateway bindings for full evidence preservation as well as native capability. A catalog's context length alone does not prove an upstream route uses the entire state. Known truncating routes need a safe effective profile before admission; the generic router byte budget does not certify them. Prefer versioned upstream IDs for reproducible behavior. Moving aliases can change future answers; each result retains the upstream model identity that actually answered, and completed effects replay their recorded result.

Started decisions retain their original request, candidate mapping, alias and resolved binding revision. Changing a default cannot reroute an already started effect. Changing binding-local protocol, limits or policy changes its revision; retained work must not cross that change silently.

Kayad CLI-agent profile policy

~/.kaya/kayad.yaml can select a profile under ~/.kaya/profiles/:

currentProfile: default-profile

For native CLI-agent presets, the profile's constraints.llm supplies the existing whitelist, cloud and agentic policy checks. Its legacy quality and alias fields participate in that policy classification; they do not replace the dispatched text alias or install a provider. Native coding harnesses and their separate tool-server preset configuration are documented in Native Coding Profiles.

Image and media bindings

generateImage() no longer resolves provider SDKs from the kayad profile. Image aliases live in the Rust tool-server manifest, where connectors own endpoints and credential sources while bindings choose an upstream model and reviewed defaults:

{
  "provider_id": "media",
  "display_name": "Generated media",
  "artifact_store": "session-objects",
  "artifact_namespace": "generated/media",
  "connectors": {
    "openai-direct": {
      "protocol": "open_ai",
      "credential": { "env": "OPENAI_API_KEY" }
    }
  },
  "images": {
    "book-illustration": {
      "connector": "openai-direct",
      "upstream_model": "gpt-image-2",
      "default_size": "1024x1024",
      "default_quality": "medium",
      "default_output_format": "png"
    }
  }
}

A program requests model: "book-illustration"; the session must explicitly grant kaya.image.book-illustration. Omitting model requests only the separately granted kaya.image.default alias. Rebinding an alias to a different connector or upstream model changes its derived revision and therefore cannot reuse stale cache or replay identity. Credentials remain environment references and are never exposed to Kaya source or provider discovery.

Research bindings

generateResearch() uses the same manifest boundary for retained, long-running work. A server connector chooses its private wire protocol and credential source; the binding name is the logical model used by Kaya:

{
  "provider_id": "research",
  "display_name": "Research",
  "connectors": {
    "gemini-direct": {
      "protocol": "gemini_interactions",
      "credential": { "env": "GEMINI_API_KEY" }
    },
    "vertex-project": {
      "protocol": "google_vertex_interactions",
      "endpoint": { "env": "VERTEX_RESEARCH_ENDPOINT" },
      "credential": { "env": "GOOGLE_VERTEX_ACCESS_TOKEN" }
    }
  },
  "bindings": {
    "deep-research-pro-preview-12-2025": {
      "connector": "gemini-direct",
      "upstream_model": "deep-research-pro-preview-12-2025"
    }
  }
}

The session must separately grant kaya.research.deep-research-pro-preview-12-2025 (or an explicitly configured default). For Vertex, the endpoint includes the reviewed v1beta1/projects/.../locations/.../ path and the credential is a bearer access token; Gemini uses its API-key header. The retained provider owns remote status observation and external-ID custody, while Kaya continues to own cache policy, the session log, waits, retries, and cancellation on teardown.


Logical aliases and default grants

Quality names are deployment-defined aliases. For example, a program using model: "highQuality" requires a server binding named highQuality and an admitted kaya.model.highQuality route. Ordinary text calls do not consult the legacy profile's defaults.generate.highQuality field.

If the exact model capability is absent, the resolver can use an explicit kaya.model.default grant. The provider still requires the requested alias in its admitted bindings. Missing credentials, unreachable providers and unsupported names produce errors; Kaya does not retry them against a different quality tier or provider.


4. Zero-Trust Security Sandboxing

For native CLI-agent presets, the profile constraints.llm block is an additional admission policy. Session ToolMap grants and the tool server remain the authority for ordinary provider operations.

Enforcement status: llm.* constraints are enforced for native CLI-agent presets. The sandbox.* keys exist in the profile schema and are accepted in YAML, but they are planned / not enforced — do not rely on them as a security boundary yet.

Constraint KeyDefaultStatusDescription / Interception Vector
llm.onlyAllow[] (Allow all)EnforcedWhitelist for the selected CLI-agent preset after profile policy classification.
llm.allowCloudLlmstrueEnforcedWhen false, rejects cloud-classified CLI-agent presets unless explicitly whitelisted.
llm.allowAgenticLlmstrueEnforcedWhen false, refuses native CLI-agent preset execution.
sandbox.allowDiskAccesstruePlanned / not enforcedIntended to intercept file-related stdlib nodes (saveFile, copyFile) for non-whitelisted folders.
sandbox.allowProcessSpawntruePlanned / not enforcedIntended to block the execution of shell commands, command compilers, or script spawning.
sandbox.allowNetworkAccesstruePlanned / not enforcedIntended to intercept HTTP fetches, blocking outbound web requests and data leaks.

A denied native CLI-agent preset receives a named structured profile refusal before a new agent invocation starts. These profile fields do not grant ordinary model, filesystem, network or command capabilities.


5. Environment Variables (env.*)

Kaya programs can read individual host environment variables through the reserved, keyed-only env capability — in expressions and in templates. env is not a map or other first-class value:

let mode = env.API_MODE ?? "production"
let requestedName = "API_MODE"
let sameMode = env[requestedName] ?? "production"
"Running for {{env.USER_NAME}} in {{mode}} mode"
let region = "{{env.REGION | default: 'us-east-1'}}"

Key properties:

  • Read-only and reserved: the env root is write-protected. Declaring let env = ..., assigning to env.X, or clearing an env.* variable all fail with Cannot set variable with 'env' prefix. A program or caller-supplied template value cannot shadow env.
  • Keyed-only, never enumerable: env.FOO, env["FOO"], and env[keyName] each authorize one exact key after any computed key resolves. Bare env is an error. It cannot be copied, passed to a function, assigned to a Liquid alias, filtered or serialized as a root value, or used as a Liquid loop collection. Filters on a selected value, such as {{env.USER_NAME | downcase}}, remain ordinary template operations.
  • A live host read, never implicit program state: every keyed access resolves against the running engine process's environment at the moment it evaluates. Environment values are not written into session state, checkpoints, or the session ledger merely because env is available, so a resumed program may observe a different host value. Copying one selected value into an ordinary variable — let key = env.API_KEY — deliberately makes that value ordinary program state, and it can then be persisted, passed, filtered, or serialized like any other string.
  • Missing keys fail loudly unless the program supplies a fallback: directly reading a key the host never provided is an error naming that key; a typo must not become silent empty output. In a Kaya expression, use env.REGION ?? "us-east-1". In a plain Liquid path, use {{env.REGION | default: 'us-east-1'}}. These forms rescue a missing selected key; a bare | default without an argument is still an error. Liquid's default also replaces a present empty string, whereas ?? preserves it. Neither form swallows other errors or makes the env root a value.
  • No implicit file-partial boundary: context-backed Kaya templates reject Liquid's {% include %}, {% render %}, and {% layout %} tags because those file templates would inherit capability roots outside the validated template. Use Kaya imports for program structure, or an explicit render(template: nestedTemplate) call for an ordinary nested template string. Recursive render filters are outside the native vocabulary; explicit render() calls do not admit host-environment templates.

WebAssembly

createKayaRuntime accepts an explicit namespace and native-format configuration: toolServer, optional agentProfile, environment, private secrets, defaultModel, defaultDecisionModel and the default-false allowClientToolMap. Non-secret workflow variables belong in session input; provider credentials do not. The CLI shell environment, ~/.kaya, native paths do not configure browser resources.

One original Worker owns the namespace's OPFS/SQLite resources. Relative program and project paths resolve through that same authority. Use readFile/writeFile, not a native filesystem fallback. Opening another owner for an already held namespace returns an ownership refusal.

saveConfiguration validates and atomically stores the private authored document and named secrets for future initialization; it does not replace the active runtime's immutable binding snapshot. Await original close(), then explicitly initialize with { saved: true }. Missing/corrupt saved setup is a refusal, not an ambient fallback. savedConfiguration() returns only { configured: true } or null; use catalog() for actual admitted capability discovery.

resetConfiguration() clears only that owner's saved setup. Await its result and the original runtime close before declaring reset complete. It preserves durable sessions/files and does not revoke a running session's captured configuration. Origin-private storage does not protect secrets from scripts with the same-origin authority. The website clears successful private form drafts and never reads old authored setup into its public UI.

See WebAssembly Setup, WebAssembly Usage, and Models & Providers: WebAssembly.