Skip to content

kici: authoring & local dev

Compile workflows from .kici/workflows/ to kici.lock.json.

Terminal window
kici compile [options]

Examples:

Terminal window
# Compile all workflows
kici compile
# Validate and type-check (CI-friendly, no file writes)
kici compile --check
# Watch mode for development
kici compile --watch
# Custom .kici directory location
kici compile --kici-dir packages/app/.kici
# Verbose output for debugging
kici compile --verbose

Exit codes:

CodeMeaning
0Compilation successful
1Compilation failed (errors)

The --check flag is useful in CI pipelines and pre-commit hooks. It validates that workflows are syntactically and semantically correct and runs a tsc --noEmit type-check over .kici/workflows/**, so type-broken workflows are caught at compile time instead of shipping silently. No lock file or other files are written.

The type-check requires .kici/tsconfig.json and a typescript dependency — both are scaffolded by kici init. In a JavaScript-only workspace (kici init --mjs, which has no tsconfig.json), the type-check is skipped with a notice and validation still runs. When the type-check finds errors, kici compile --check prints each one in file:line:column error [E120]: message form and exits non-zero.

If .kici/ has workflows but no .kici/package.json, kici compile warns: agents install the .kici/ dependencies from that file only, so the workflows cannot run on an agent. kici run remote and kici run --local print the same warning. kici run --local --in-place does not, because it uses the node_modules already in your working tree. To fix it, run kici init --workspace in a workspace, or add a .kici/package.json that declares @kici-dev/sdk.

Compile and validation errors carry the real file:line:column of the offending job or step (anchored to the job’s first step location), so you can jump straight to the source instead of a generic line 1.

Auto-type regeneration: When kici types has a source (a direct orchestrator target, a Platform login with an active organization, or local secret files), kici compile refreshes .kici/types/secrets.d.ts after each successful compilation. The refresh keeps type declarations in sync with your secret contexts. The type regeneration is non-blocking — if the source is unreachable, compilation still succeeds with a warning. The --check flag skips type regeneration since a check writes no files.

Preview which workflows match a trigger event (dry-run, no execution). Useful for verifying trigger configurations during development.

Terminal window
kici preview [event] [options]

Examples:

Terminal window
# Preview which workflows match a push event
kici preview push
# Preview PR trigger matching
kici preview pr:open
# Preview with branch override
kici preview push --branch develop
# Filter to specific workflow
kici preview push --workflow ci
# Simulate changed files for path-filtered triggers
kici preview push --files src/index.ts --files README.md

For each matched job, preview lists the steps with the names that a run records. A named step shows its name. A run: shorthand step, a bare function step and a step() with no name show their step-N name. A parallel() group shows its steps under the group name. A step layout that kici compile rejects, such as an empty parallel() group, also makes preview fail with the same error.

Exit codes:

CodeMeaning
0Preview completed (including zero matches)
1Error

Manage the local dev plane — the warm, per-user orchestrator (plus its own local PostgreSQL) that kici run <event> --local dispatches through. You rarely need these commands directly: a local run boots the plane on demand and reuses it afterwards. Reach for them to inspect the plane, stop it, read its log, or switch it between offline and Platform-connected mode.

Terminal window
kici local up [--offline | --connected] # Start, or reuse an already-running plane
kici local status [--json] # Port, pid, PostgreSQL backend, attachment mode, readiness
kici local down # Stop the orchestrator and its PostgreSQL, verifying the port is freed
kici local logs # Print the plane log paths and rotation policy
kici local attach # Attach to the Platform (hybrid mode)
kici local detach # Return the plane to offline (independent) mode
kici local trust-root <file> # Export the dev-signed trust root for offline verification

The plane runs in one of two modes:

  • Independent (offline) — the default for a plane that has never been attached. Identity tokens and attestations are signed by a local dev key under the clearly non-production issuer kici-local.
  • Hybrid (attached) — kici local attach mints an org-scoped key with your logged-in credentials and reboots the plane connected to the Platform, so local runs get identity and attestation signed by the plane’s own key under its own issuer, as a deployed orchestrator would. kici local up honors a durable attachment record: an attached plane comes back up hybrid, and falls back to offline with a warning when the Platform is unreachable.

--offline forces an independent boot without clearing the attachment record (only detach clears it); --connected requires an attached, reachable Platform and fails otherwise.

kici local down reports success only once the plane port is verified free. If a process still holds it — including a plane left behind by an interrupted boot — the command exits non-zero and names the holder, so a failed teardown is never mistaken for a clean one. A holder that does not identify as a KiCI plane orchestrator is reported and left alone, never stopped.

kici local status reports a plane whose process is alive but whose readiness probe fails — for example when its PostgreSQL has stopped — as running but not ready, together with its readiness checks, rather than as not running. When the holder is a KiCI plane orchestrator that this config directory did not start, status names it as such rather than as not ready, since its readiness is never probed. Such a holder is a plane belonging to another KICI_CONFIG_DIR, or one whose record here was lost. For such a holder, status points at kici local down, which does reclaim it. When the port is held by a process that is not a KiCI plane orchestrator, kici local status names that holder instead and points at KICI_LOCAL_ORCH_PORT, because kici local down will not stop it.

The plane writes its orchestrator log to orchestrator.log in its state directory and, when it runs embedded PostgreSQL, the PostgreSQL log to orchestrator.log.pg beside it. kici local logs prints their location. Each is rotated to a .1 sibling when it reaches 50 MB, at the next plane start — the plane keeps the current log and one previous generation, so neither can grow without bound.

Pass --json for machine-readable output. It prints one object and exits 0 for every state, including when the plane is stopped — the state is in the payload, not the exit code:

Terminal window
$ kici local status --json
{"state":"ready","running":true,"pid":3768093,"port":4319,
"url":"http://127.0.0.1:4319","pgKind":"embedded","stampVersion":5,
"mode":"independent"}

state is one of stopped, ready, unready, foreign-kici, foreign-unknown. The key set is fixed: the plane’s admin token is never part of it, so the output is safe to log. Every key is always present, but only state, running and mode always carry a value — the rest are null whenever the plane cannot supply them (for stopped that is all of them, and stampVersion is populated only for ready), so read them defensively (jq -r '.pid // empty').

A local run also fails fast when no agent claims it. If no scaler label set matches the job’s runsOn, or the agent cannot start, the run gives up within a short acceptance window. The window is 2 minutes by default, and KICI_LOCAL_ACCEPTANCE_TIMEOUT_MS overrides it. The CLI then names the plane log instead of waiting out the full no-progress timeout. Whenever the CLI stops following a run before it finishes (a timeout, an error, or Ctrl-C), it cancels the run in the plane, so a later plane start never dispatches it again.

Verifying an offline-signed bundle: export the plane’s trust root, then pass it to the verifier:

Terminal window
kici local trust-root ./local-trust-root.json
kici verify-attestation ./dist/app.tgz \
--bundle ./app.tgz.kici.json \
--trust-root ./local-trust-root.json

For the plane’s on-disk layout, port selection, PostgreSQL backends, and reset behavior, see Local dev plane.

Generate a fixture template for an event type. Useful for creating custom test payloads.

Terminal window
kici fixture <event> [options]

Valid events: pr:open, pr:sync, pr:close, pr:reopen, push, tag, comment, review, review_comment, release, dispatch, create, delete, status, workflow_run, fork, star, watch, kici_event, workflow_complete, workflows_failed_batch, job_complete, generic_webhook, schedule, lifecycle (many support :action suffixes, e.g. comment:edited, release:published, lifecycle:workflow_complete). webhook:<source> is a shorthand alias for generic_webhook:<source>.

Examples:

Terminal window
# Print fixture to stdout
kici fixture pr:open
# Write fixture to file
kici fixture pr:open --output fixtures/pr-open.json
# Generate push fixture
kici fixture push --output fixtures/push.json

Use generated fixtures as reference when writing test fixture files in .kici/tests/:

Terminal window
kici fixture pr:open --output fixtures/pr-open-reference.json
# Use the generated JSON as reference when writing .kici/tests/pr-open.ts

Generate TypeScript declaration files from your contexts’ secret key names. The generated .d.ts file augments the SDK’s KnownSecretKeys and ContextSecrets interfaces, providing compile-time autocomplete and type checking for secret key names.

Terminal window
kici types [options]

Prerequisites: any one of these sources. kici types reads the first that is available:

  1. A direct orchestrator target: --orchestrator-url, KICI_ORCHESTRATOR_TOKEN, or the orchestrator saved by kici connect. The token needs the owner or admin role.
  2. Your Platform login (kici login and an active organization).
  3. The local secret files kici run --local reads: .kici/.secrets and .kici/secrets.yaml. Only key names are read, never values.

With none of them, kici types writes an empty stub (see “Offline behavior” below).

Output: .kici/types/secrets.d.ts

Examples:

Terminal window
# Generate types from the first available source
kici types
# Read key names from one orchestrator
KICI_ORCHESTRATOR_TOKEN=... kici types --orchestrator-url https://ci.example.com
# Use custom .kici directory
kici types --kici-dir packages/app/.kici

How it works:

  1. Reads every context name and its secret key names from the source
  2. Generates a .d.ts file that augments @kici-dev/sdk’s KnownSecretKeys and ContextSecrets interfaces
  3. Writes the file to .kici/types/secrets.d.ts, with a // Source: header that names the source: orchestrator <url>, Platform org <id> or local files

Never downgraded: local secret files never replace a key set read from an orchestrator or the Platform. On an offline laptop with only local files, kici types keeps the existing file and says so. A file written by an older CLI, whose header names the Platform URL, counts as read from the Platform.

After generating types, ctx.secrets.get('MY_KEY') and ctx.secrets.expose('DB_HOST') gain autocomplete and type checking in your IDE.

Git workflow: .kici/types/secrets.d.ts is a local development aid, not source — its content is a snapshot of one org’s secret keys. kici init gitignores .kici/types/, so the file stays out of version control. Each team member runs kici types (or kici compile) to generate their own copy. Do not commit it: a stale committed copy would type-check against secret keys that no longer exist.

Offline behavior: When no source can be reached — no target configured, or the orchestrator or Platform is offline — kici types falls back to the local secret files, and never fails. With no local files either: if a secrets.d.ts already exists, kici types keeps it untouched, so a transient outage does not wipe your real key set. If the file is absent (a fresh clone or unauthenticated CI), kici types writes a valid empty stub. Type checking then degrades to “no known keys” (any key name is accepted) rather than breaking with “module has no exported member”. A token the orchestrator or Platform refuses is an error, not a reason to write a stub.

Auto-regeneration: kici compile automatically runs kici types after successful compilation whenever one of the sources above exists. See the kici compile section for details.

Escape hatch: For dynamic keys not in the generated types, use a cast: (ctx.secrets as any).DYNAMIC_KEY.

List permanently registered workflows on the orchestrator.

Terminal window
kici workflows list [options]

Examples:

Terminal window
# List all registered workflows
kici workflows list
# JSON output for scripting
kici workflows list --json
# Show workflows not updated in 30 days
kici workflows list --stale 30d
# Filter by trigger type
kici workflows list --trigger-type push
# Filter by repository
kici workflows list --repo my-org/my-repo

Install a pre-commit hook that runs kici compile before each commit.

Terminal window
kici hook install [options]

Examples:

Terminal window
# Auto-detect hook tool (Husky, Lefthook, pre-commit, prek)
kici hook install
# Force raw git hook
kici hook install --git

The command auto-detects existing hook tools in your project:

  • Husky (.husky/): Adds kici compile to .husky/pre-commit
  • Lefthook (lefthook.yml, .lefthook.yml, or .config/lefthook.yml): Adds a kici-compile command to the config, then runs npx lefthook install
  • pre-commit (.pre-commit-config.yaml): Adds a kici hook to the config, then runs pre-commit install
  • prek (prek.toml or .prek.toml): Adds a kici hook to .pre-commit-config.yaml, then runs prek install
  • Raw git (--git): Writes .git/hooks/pre-commit

The hook runs npx -y kici@<version> compile, where <version> is the version of the kici CLI that installed the hook, and then stages the result with git add .kici/kici.lock.json, so the commit carries the fresh lock file. When you upgrade @kici-dev/sdk, change the version in the hook too.

If multiple tools are detected, you are prompted to choose. In a non-interactive shell or CI, the command uses the first tool in the list above. If no tool is detected, an interactive shell offers a raw git hook; a non-interactive shell installs nothing and tells you to pass --git.

Open the KiCI documentation site in the default browser. With the llm subcommand, print the LLM-friendly documentation bundle that ships with @kici-dev/compiler — pipe it into a coding agent’s context buffer to brief the agent on authoring conventions without an internet round-trip.

Terminal window
kici docs # open https://docs.kici.dev/
kici docs --no-open # print the URL instead of opening a browser
kici docs llm # print the llms.txt index (a router over the task bundles)
kici docs llm sdk # print the SDK task bundle
kici docs llm full # print llms-full.txt (every page in one file)
kici docs llm sdk --out sdk-context.md # write a bundle to a file

Examples:

Terminal window
# Open the docs site in your browser
kici docs
# Pipe just the SDK bundle into a coding agent (small, task-scoped context)
kici docs llm sdk | claude -- "Read this and help me author a deploy workflow"
# Save the router index for offline reference
kici docs llm --out kici-llms-index.txt

Bundles are regenerated from docs/ every time @kici-dev/compiler is built, so they always match your installed CLI version. The index lists each task bundle — getting-started, sdk, sdk-runtime, cli, cli-remote, patterns, features, features-execution, providers, architecture — with its size and a one-line purpose; pass the bundle id as the topic. Every cross-reference link inside a bundle is an absolute docs.kici.dev URL. The same files are published online following the llms.txt convention.

Compile workflows from .kici/workflows/ to kici.lock.json

Synopsis: kici compile [options]

Options

OptionDefaultDescription
--checkfalseValidate workflows and type-check sources (tsc —noEmit) without writing lock file
--kici-dir <path>.kiciPath to .kici directory
--verbosefalseDetailed output
--watchfalseWatch for changes and recompile

Open the KiCI documentation site in the default browser

Synopsis: kici docs [options]

Options

OptionDefaultDescription
--no-openPrint the docs URL instead of opening a browser

Print KiCI LLM docs bundles. No topic prints the llms.txt index; prints a task bundle (e.g. sdk, cli, cli-remote, patterns, features, providers, architecture, getting-started); “full” prints the complete bundle.

Synopsis: kici docs llm [topic] [options]

Arguments

ArgumentRequiredVariadicDescription
topicnono

Options

OptionDefaultDescription
--out <path>Write the bundle to a file instead of stdout

Generate fixture template for event type

Synopsis: kici fixture <event> [options]

Arguments

ArgumentRequiredVariadicDescription
eventyesnoEvent to generate fixture for (e.g., pr:open, push, schedule, lifecycle:workflow_complete)

Options

OptionDefaultDescription
--output <path>Write to file instead of stdout

Manage pre-commit hooks

Synopsis: kici hook

Install kici compile pre-commit hook

Synopsis: kici hook install [options]

Options

OptionDefaultDescription
--gitfalseUse raw git hook (.git/hooks/pre-commit)

Manage the local dev orchestrator plane

Synopsis: kici local

Attach the local dev plane to the Platform (hybrid)

Synopsis: kici local attach

Detach the local dev plane from the Platform (offline)

Synopsis: kici local detach

Stop the local dev plane

Synopsis: kici local down

Print the local dev plane log paths and rotation policy

Synopsis: kici local logs

Show local dev plane status and control commands

Synopsis: kici local status [options]

Options

OptionDefaultDescription
--jsonfalseEmit machine-readable JSON (exits 0 for every state)

Export the offline dev-signed identity trust root ({ issuer, jwks }) to a file

Synopsis: kici local trust-root <file>

Arguments

ArgumentRequiredVariadicDescription
fileyesnoOutput path for the { issuer, jwks } trust-root JSON

Start (or reuse) the local dev plane

Synopsis: kici local up [options]

Options

OptionDefaultDescription
--offlinefalseForce the independent (offline) plane (does not clear the attachment record)
--connectedfalseForce the connected/hybrid plane (requires an attached, reachable Platform)

Preview which workflows match a trigger event (no execution)

Synopsis: kici preview [event] [options]

Arguments

ArgumentRequiredVariadicDescription
eventnonoEvent type to preview (e.g., push, pr:open, schedule)

Options

OptionDefaultDescription
--branch <name>Override target branch for trigger matching (default: main)
--sha <hash>Override commit SHA
--workflow <name>Filter to specific workflow in display
--job <name>Filter to specific job in display
--debugfalseVerbose internals
--kici-dir <path>.kiciPath to .kici directory
--files <path>Simulate changed file path for trigger matching (repeatable)
--secret <key=value>Inject flat secret (repeatable)
--context <ctx.key=value>Inject context secret (repeatable)

Generate TypeScript declarations for secret contexts

Synopsis: kici types [options]

Options

OptionDefaultDescription
--kici-dir <path>.kiciPath to .kici directory
--orchestrator-url <url>Read secret key names from this orchestrator directly (token: KICI_ORCHESTRATOR_TOKEN or kici connect)

Manage workflow registrations

Synopsis: kici workflows

List permanently registered workflows

Synopsis: kici workflows list [options]

Options

OptionDefaultDescription
--jsonfalseOutput as JSON
--stale <duration>Filter stale registrations (e.g., 30d, 7d)
--trigger-type <type>Filter by trigger type
--repo <repo>Filter by repository