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.
| Host | Where settings live |
|---|---|
| Command Line | Server/client manifests, job files, daemon profiles, and process environment |
| WebAssembly | Explicit 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 startWith 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.kayaRestart 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.jsonStart 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 startIf 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: trueThis 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-profileFor 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 Key | Default | Status | Description / Interception Vector |
|---|---|---|---|
llm.onlyAllow | [] (Allow all) | Enforced | Whitelist for the selected CLI-agent preset after profile policy classification. |
llm.allowCloudLlms | true | Enforced | When false, rejects cloud-classified CLI-agent presets unless explicitly whitelisted. |
llm.allowAgenticLlms | true | Enforced | When false, refuses native CLI-agent preset execution. |
sandbox.allowDiskAccess | true | Planned / not enforced | Intended to intercept file-related stdlib nodes (saveFile, copyFile) for non-whitelisted folders. |
sandbox.allowProcessSpawn | true | Planned / not enforced | Intended to block the execution of shell commands, command compilers, or script spawning. |
sandbox.allowNetworkAccess | true | Planned / not enforced | Intended 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
envroot is write-protected. Declaringlet env = ..., assigning toenv.X, or clearing anenv.*variable all fail withCannot set variable with 'env' prefix. A program or caller-supplied template value cannot shadowenv. - Keyed-only, never enumerable:
env.FOO,env["FOO"], andenv[keyName]each authorize one exact key after any computed key resolves. Bareenvis 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
envis 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| defaultwithout an argument is still an error. Liquid'sdefaultalso replaces a present empty string, whereas??preserves it. Neither form swallows other errors or makes theenvroot 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 explicitrender(template: nestedTemplate)call for an ordinary nested template string. Recursiverenderfilters are outside the native vocabulary; explicitrender()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.