Concepts
Local CLI execute
Official Kody doc
When Node ≥22 and @kodycodes/cli are available, prefer
npx @kodycodes/cli execute --local for one-off modules, smoke tests, and
composition. Local execute is orthogonal to Open API: the CLI runs your
module in a local workerd and forwards each kody:runtime call through the
CapabilityProxy. Do not use hosted MCP execute for agent work when a local
or Open API path exists.
Auth: --token / KODY_API_TOKEN (kody_at_… with org:execute; add
package:execute when the module imports kody:@…), or when no API token is
set, the access token from kody login (MCP OAuth) as Bearer on CapabilityProxy
and package-graph routes.
Setup
Agents already on MCP (do this yourself; never ask a human for a token):
call cliCredentialBootstrap with a required lifetime (single-task agents use
short). Prefer MCP api with operationId: "cliCredentialBootstrap" (or the
capability via search when you need the schema). It returns a one-shot
kody_bc_… code and a cli_command that already includes lifetime flags
(not a kody_at_…). Bootstrap tokens are person-owned
(org_binding: user); pass ?org=<slug> on API calls to act in a team org
(default: personal). Run the returned cli_command (no second OAuth, no
tokenCreate):
{
"operationId": "cliCredentialBootstrap",
"params": { "lifetime": "short" }
}# Or run the cli_command returned by cliCredentialBootstrap:
npx @kodycodes/cli auth bootstrap --code 'kody_bc_…' --lifetime shortshort is 1 hour idle / 24 hours max. long is 14 days idle / 3 months max. Or
pass both --idle-ttl-seconds and --max-lifetime-seconds. Lifetime is
required; missing it fails with the exact flag syntax.
Default scopes: bootstrap tokens include local-execute use scopes
(org:execute, org:read, and package/integration/secret/email/job/app/memory
use scopes), plus package:write (plain-repo / package pushes),
package:create, and token:delete (self-revoke). They do not include
search:read. When a task needs a different set, pass scopes when minting.
The list replaces the defaults, so include every scope you need:
# Agents on MCP, with the api tool (execute is refused): cliCredentialBootstrap({ lifetime: "short", scopes: ["org:execute", "org:read", "package:execute", "package:read", "package:write"] })
npx @kodycodes/cli auth bootstrap --code 'kody_bc_…' --lifetime short
# After `kody login`, the CLI mints the code itself and stores the token:
npx @kodycodes/cli auth bootstrap --lifetime short \
--scopes org:execute,org:read,package:execute,package:read,package:write--scopes mints with --token when given, else the kody login session (any
scope your org role grants), else KODY_API_TOKEN or the stored token (only
scopes that token already holds). --code with --scopes is an error because a
code's scopes are fixed when it is minted.
Interactive humans: kody login once per machine (beside the agent
cliCredentialBootstrap path above), then run --local without
KODY_API_TOKEN.
npx @kodycodes/cli login # onceOn a remote VM, NAS, or SSH session, use npx @kodycodes/cli login --device and
approve the printed code from any browser. See
Remote or headless machines (raw).
CI / headless only: scoped KODY_API_TOKEN (kody_at_… with org:execute,
plus package:execute for saved-package imports), usually from MCP api
tokenCreate with a required lifetime. Put the value in the environment; never
paste it into chat (agents on MCP must use cliCredentialBootstrap instead).
Prefer the env var over --token. When set, KODY_API_TOKEN wins over
kody login / bootstrap store. Minting details: Open API
(guide:open_api).
{
"operationId": "tokenCreate",
"params": {
"name": "kody-cli-local",
"scopes": [
"org:execute",
"org:read",
"package:execute",
"package:read",
"integration:read",
"integration:use",
"secret:use"
],
"lifetime": "short"
}
}export KODY_API_TOKEN='kody_at_…'Usage
npx @kodycodes/cli execute --local --code 'import { kody } from "kody:runtime"; export default async function main() { return await kody.metaGetCurrentUser({}) }'Use --file path.ts the same way when the module lives on disk. Keep --local;
static kody:@owner/name imports still run locally (package-graph download +
CapabilityProxy hops). The CLI posts the kody:@ imports that still need
published modules to POST /v1/local-execute/package-graph (with a tiny
synthetic entry), never the whole module. Inline code on that route may be up
to just under the Open API JSON body limit (~5 MiB); larger callers pass
imports alone so origin synthesizes a tiny entry. If inline code still
exceeds that ceiling, the API (and CLI) name the actual UTF-8 byte length and
the maximum — not a bare Invalid parameters. Package-graph always returns the
gateway-fetch shim, so ad-hoc scripts with no kody:@ imports still expand
{{secret:…}} placeholders on origin (or fail closed naming the secret) instead
of sending them raw. import { credential } from 'kody:runtime' for ad hoc and
unpublished package source needs a CLI whose host kody:runtime exports
credential / credentials per the
CLI local credential runtime
contract (CapabilityProxy opens a handle; gateway placement only — same as
hosted). Older CLIs fail at import time; upgrade @kodycodes/cli.
A fetch that carries a placeholder runs on origin with the same 5-minute
overall deadline as cloud fetches. The deadline starts when origin sends the
request upstream, after it checks your quota and fills placeholders, and runs
until the response body ends. The response is also aborted after 60s with no
bytes. --local has no run cap, so a long streamed response, such as an AI
completion, can finish.
Small buffered placeholder-bearing bodies use the JSON CapabilityProxy hop
(kody.gatewayFetch): origin buffers the whole response before returning it, so
your code receives nothing until the body ends, and a body over 4 MiB fails.
Streamed bodies, multipart bodies, and bodies that would exceed 4 MiB use the
streaming hop (POST /v1/capability-proxy/gateway-fetch via
kody.gatewayFetchStream): there is no 4 MiB hop cap. That path still respects
the Cloudflare Worker upload limit (~100 MiB on Free/Pro). A Content-Length
over that limit returns JSON 413 payload_too_large. See the
CLI streaming gateway-fetch contract.
The CLI CapabilityProxy client waits up to 7 minutes for origin's reply, so the
gateway's 5-minute deadline ends a slow fetch, with its own error.
@kodycodes/cli below 1.13.1 hits Node's default 300-second wait
(UND_ERR_HEADERS_TIMEOUT) instead. With NODE_USE_ENV_PROXY=1 or
--use-env-proxy, these requests still go through HTTP_PROXY / HTTPS_PROXY.
A fetch without placeholders, and a multipart upload that does not need fill,
goes straight from local workerd and is not subject to this deadline.
Running from a package checkout
Run --file from inside a package directory and the CLI resolves that package's
own kody:@… exports (and .kody/deps.json mappings) from the working tree.
Their remaining kody:@ dependencies come from published package-graph. When a
successful package-graph response omits required modules, the module never
ran: that error (incomplete_package_graph in --json output) is a package
resolution problem, not an auth problem. HTTP 401 or 403 from package-graph is
still auth or permission — use the Failure section below. Two workarounds for
incomplete_package_graph:
- Inside the checkout, import your own package's files with relative imports
(
./src/helper.ts) instead ofkody:@scope/pkg/helper. - To test the published exports, run the entry from a directory outside the
checkout so every
kody:@import resolves from package-graph.
Failure
- Node is below 22, the CLI is missing, or the host cannot run workerd. Use
Open API / MCP
api, or fix the environment. Hosted MCPexecutestays banned for that failure case. - Not authenticated (missing or invalid credentials). Agents on MCP: call
cliCredentialBootstrapand run the returnedcli_command; never ask a human to paste a token. Humans:kody login. CI/headless:tokenCreate+KODY_API_TOKEN. - Bootstrap or redeem rejects a missing lifetime. Pass
--lifetime short|long(or both idle/max flags). CallcliCredentialBootstrapagain withlifetime: "short"if the code expired. insufficient_scopeon a token means it lacks a scope. The error names the scope and prints both mint commands with the full list (the token's scopes plus the missing one); run one and retry.--tokenandKODY_API_TOKENstill win over the stored token, so replace or unset them before retrying. Open API errors carry the same list asdetails.mint_scopes. When your org role lacks the permission (denial: missing_permission), a new token cannot help; an org Owner has to grant it.- Package-scoped
secretSet/secretSetMany/secretDeleteare not available under--local. Local CapabilityProxy does not attach package secret authority (a client-supplied package id is not trusted as a hosted run). Use hosted package execute, or set the secret from the account UI (/connect/secret-set) or Open APIsecretSetwith a user scope / outside local execute. See Secrets. - The module imports
kody:@…. Keep--local. - Auth priority for
--local:--token/KODY_API_TOKEN, then the stored bootstrap token, thenkody login.