Skip to content

CLI reference

The @kici-dev/compiler package provides the kici CLI for compiling, testing, and managing workflows.

Terminal window
pnpm add -D @kici-dev/compiler

The examples use pnpm, but npm and yarn work too — npm install -D @kici-dev/compiler or yarn add -D @kici-dev/compiler.

Run commands with npx kici or add scripts to your package.json:

{
"scripts": {
"kici:compile": "kici compile",
"kici:test": "kici test"
}
}

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

Terminal window
kici compile [options]

Options:

OptionDefaultDescription
--checkfalseValidate workflows without writing lock file
--watchfalseWatch for changes and recompile
--kici-dir <path>.kiciPath to .kici directory
--verbosefalseDetailed output

Examples:

Terminal window
# Compile all workflows
kici compile
# Validate only (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 without writing the lock file or any other files.

Auto-type regeneration: When authenticated (via kici login), kici compile automatically refreshes .kici/types/secrets.d.ts after each successful compilation. This keeps type declarations in sync with your orchestrator’s secret contexts. The type regeneration is non-blocking — if the orchestrator is unreachable, compilation still succeeds with a warning. The --check flag skips type regeneration since no files are written.

Execute workflows locally or remotely. The run command has two subcommands: local for direct execution without infrastructure, and remote for fixture-based execution through an orchestrator.

Execute workflows locally without orchestrator infrastructure. Compiles workflows, matches triggers against the specified event, expands matrices, and runs jobs with DAG-based parallel scheduling.

Terminal window
kici run local [event] [options]

Arguments:

ArgumentRequiredDescription
eventwhen --pick is unsetEvent type (e.g., push, pr:open, schedule)

Options:

OptionDefaultDescription
-p, --pickfalseInteractively pick a workflow + trigger (see below)
--workflow <name>noneRun only the specified workflow (mutex with --pick)
--job <name>noneRun only the specified job (and its dependencies)
--branch <name>detectedOverride detected git branch
--sha <hash>detectedOverride detected git SHA
--payload <path>nonePath to explicit event payload JSON file
--concurrency <n>CPU coresMax parallel jobs within one run (job-level only). Cross-run concurrency groups declared in workflow({ concurrency: ... }) are enforced separately — see “Concurrency enforcement” below.
--keep-goingfalseContinue after job failure
--containerfalseUse Podman container isolation
--env <KEY=VALUE>noneEnvironment variable override (repeatable)
--files <path>git diffOverride changed file paths (repeatable, default: git diff)
--quietfalseSuppress streaming output (summary only)
--jsonfalseOutput structured JSON result
--junit <path>noneOutput JUnit XML result to file
--debugfalseVerbose internals
--kici-dir <path>.kiciPath to .kici directory
--in-placefalseRun against the real working directory instead of an isolated tmp checkout (see “Execution isolation” below)
--keepfalseAlways retain the isolated tmp checkout (default: keep only on failure)

Interactive workflow selection (--pick / -p):

When you do not remember the event arg for a workflow, pass --pick (or -p) to open an interactive picker. It lists every workflow with a compact summary of its triggers, lets you choose one, and (for multi-trigger workflows) prompts again for which trigger to simulate. The selected trigger is converted back into an event arg and fed through the normal pipeline.

Terminal window
# Open the picker across all triggerable workflows
kici run local --pick
# Scope the picker to a trigger family (e.g. only workflows that react to pr:*)
kici run local pr:open --pick

Rules:

  • --pick is mutually exclusive with --workflow. Passing both exits with code 2.
  • When stdin is not a TTY, --pick prints the available workflows and exits without running anything — fall back to kici run local <event> --workflow <name> in scripts.
  • Passing an event arg together with --pick narrows the picker to workflows that declare at least one trigger in that event family (e.g. schedule --pick shows only scheduled workflows).

Concurrency enforcement:

When the workflow declares a concurrency block, kici run local enforces it across concurrent local invocations on the same machine and user account. The behavior mirrors the orchestrator:

  • The group callback is evaluated against the simulated event (same { branch, event } context that the agent sees), and the resulting key is used as the lock identity. Throwing from group aborts the workflow run with a clear error — there is no fallback to the workflow name.
  • cancelInProgress: true interrupts the holder via SIGTERM, then escalates to SIGKILL after a grace window if the holder does not exit, and proceeds with the new run.
  • Otherwise the new invocation waits in FIFO order. A status line is printed when the wait starts and roughly every five seconds thereafter.
  • Locks live under $XDG_RUNTIME_DIR/kici-local-locks/ on Linux, falling back to os.tmpdir()/kici-local-locks-<uid>/ on platforms without a per-user runtime dir. Each lock file records the holder PID, hostname, workflow name, group key, and start timestamp so concurrent invocations can describe what they are waiting for.
  • Stale locks (the recorded holder PID is gone, per process.kill(pid, 0)) are reclaimed automatically.

Coordination is local only — running the same workflow on two different machines does not serialize across them. That requires the orchestrator.

The SIGTERM-to-SIGKILL grace window defaults to 30 000 ms. Override it with the KICI_LOCAL_LOCK_KILL_GRACE_MS environment variable (positive integer, milliseconds) when iterating on workflows that need longer to clean up on cancellation.

Execution isolation:

By default, kici run local executes steps inside an isolated tmp checkout rather than against your real working directory. Any file a step writes, builds, or deletes — and any git mutation a step performs — lands in that throwaway copy, so casual local runs never touch your tree.

What gets materialized into the isolated checkout has full parity with what kici run remote reconstructs: your current working tree minus gitignored files, with .kiciignore applied to local changes, over a real .git directory. Concretely, the checkout is built from a clone pinned to your current HEAD, with your local overlay (modified, staged, and untracked-but-not-ignored files) copied on top and locally-deleted files removed. Workflows that read git metadata work because the .git directory is present and pinned to your HEAD.

The path is logged at run start (for example, running in /tmp/kici-run-ab12cd) so you can inspect it.

Cleanup policy:

  • On a fully successful run, the isolated checkout is removed.
  • On failure, it is retained and its path is logged so you can inspect the failed state.
  • --keep always retains it, even on success.
  • Retained checkouts are garbage-collected after 72 hours by the next kici run local invocation — copy a checkout elsewhere if you need it longer.

Set the KICI_RUN_DIR environment variable to place the isolated checkout under a base directory other than the system temp directory.

Secrets are always sourced from your real .kici/ directory, not from the isolated checkout. Gitignored secret files (such as .kici/.env.local and .kici/secrets.yaml) are never copied into the checkout, so a step that reads a secret still gets it from the original location.

Pass --in-place to run against the real working directory instead — useful when you explicitly want in-tree execution. --in-place requires no git repository; the default isolated mode does, and fails with an actionable error pointing at --in-place when the directory is not a git repository.

Examples:

Terminal window
# Run workflows matching a push event
kici run local push
# Run only a specific workflow
kici run local push --workflow ci
# Run only a specific job (and its dependencies)
kici run local push --job test
# JSON output for CI scripting
kici run local push --json
# JUnit XML for CI integration
kici run local push --junit results.xml
# Quiet mode (summary only, no streaming)
kici run local push --quiet
# Override branch and SHA
kici run local push --branch main --sha abc1234
# Environment variable overrides
kici run local push --env NODE_ENV=test --env CI=true
# Continue running other jobs after one fails
kici run local push --keep-going

Exit codes:

CodeMeaning
0All workflows succeeded
1One or more jobs failed

Output formats:

  • Default: Streaming job output during execution, followed by a tree-format summary with per-step timing
  • --json: Structured JSON with workflows, jobs, steps, timing, and matrix values
  • --junit <path>: Standard JUnit XML for CI integration (Jenkins, GitLab, etc.)
  • --quiet: Summary only, no streaming output during execution

Execute fixtures remotely through the full CI pipeline. Fixtures are defined in .kici/tests/*.ts using the fixture() factory function. Without arguments, lists available fixtures.

Remote runs route through the Platform. Authenticate with a personal access token (kici login), then target an organization with kici org use <org> or the --org flag. The Platform relays the run to the org’s orchestrator, while your working-tree overlay uploads directly to object storage — see How the run is routed and The two planes below.

The orchestrator must have cache storage configured (KICI_STORAGE_TYPE = s3 or filesystem) with a dev-reachable upload endpoint so the CLI’s direct upload succeeds; see the testing guide and Storage layout for setup.

Terminal window
kici run remote [fixture] [options]

Arguments:

ArgumentRequiredDescription
fixturenoFixture name or glob pattern (omit to list all)

Options:

OptionDefaultDescription
--org <id>activeTarget organization for this run (overrides kici org use)
--orchestrator <name>defaultTarget orchestrator cluster within the org (overrides the per-org default)
--allfalseRun all fixtures
--workflow <name>noneRun a specific workflow directly (bypass triggers)
--parallelfalseRun multiple fixtures concurrently
--no-wait-Fire and forget (print runIds, don’t stream)
--quietfalseMinimal output (only final result)
--jsonfalseMachine-readable JSON output
--junit <path>noneJUnit XML output to file for CI integration
--historyfalseShow table of recent test runs
--context <ctx.key=value>noneInject a namespaced context secret, uploaded encrypted (repeatable)
--env <KEY=VALUE>noneProvide a per-run secret, uploaded encrypted (repeatable) — see testing guide
--debugfalseVerbose internals
--kici-dir <path>.kiciPath to .kici directory

Examples:

Terminal window
# List available fixtures
kici run remote
# Run a single fixture against the active org
kici run remote push-main
# Target a specific org for this run
kici run remote push-main --org xyz789ghi012
# Target a specific orchestrator cluster within the org
kici run remote push-main --orchestrator us-east
# Run all push-related fixtures
kici run remote push-*
# Run everything
kici run remote --all
# Run a specific workflow directly (bypass trigger matching)
kici run remote --workflow ci
# Quiet mode -- just pass/fail
kici run remote push-main --quiet
# JSON output for scripting
kici run remote push-main --json
# Fire and forget
kici run remote push-main --no-wait
# View recent test run history
kici run remote --history

Exit codes:

CodeMeaning
0All matched workflows passed
1One or more workflows failed

A remote run is dispatched to your active organization — the one set with kici org use <org>, or overridden per-run with --org <id>. The org is resolved in this order:

  1. The --org <id> flag, if provided.
  2. Otherwise the active org saved in your global config by kici org use <org>.
  3. If neither is set, the command errors and asks you to select an org with kici org use or pass --org.

The orchestrator anchors the org without any manual webhook source: it auto-provisions a system-managed remote source (routing key remote:<orgId>) that maps to its bound organization, so even a zero-source org is immediately routable for remote runs. You never set a routing key for a remote run — selecting the org is enough.

When an org has more than one connected orchestrator cluster, the CLI picks the target cluster in this order:

  1. The --orchestrator <name> flag, if provided.
  2. Otherwise the per-org default cluster, set with kici orchestrators use <name>.
  3. If the org has exactly one connected orchestrator, it is auto-selected.
  4. Otherwise the run errors with the list of connected clusters, and you pass --orchestrator <name> to choose one. Run kici orchestrators list to see the available cluster names.

kici run remote uses two independent paths:

  • Control plane — run initiation, trigger, status, log retrieval, and cancellation flow from your machine through the Platform, which relays them over a WebSocket connection to the org’s orchestrator. Logs are delivered by the CLI polling the Platform for log chunks (tracked by a monotonic line cursor) and run status until the run reaches a terminal state; there is no direct streaming socket to the orchestrator.
  • Data plane — your working-tree overlay tarball uploads directly from your machine to the orchestrator’s object store via a presigned PUT URL. The overlay never passes through the Platform. This is why the orchestrator’s object-store upload endpoint must be reachable from your machine; see Storage layout.

An orchestrator with no Platform connection cannot serve remote runs — the Platform is the service that offers them. For executing workflow steps on your own machine without an orchestrator (no scaler, agents, or environments), use kici run local.

kici run remote works even if the repo has never been pushed to GitHub. When no remote is detected:

  • The entire repo content is uploaded (not just a diff overlay)
  • The lock file is sent inline (no GitHub API fetch)
  • Steps that use git commands will fail (no .git directory in the remote workspace)
  • Build cache (__build__ jobs) is skipped for local repos
  • Environments must have allowLocalExecution: true to be accessible from local runs (default is false)

Destination routing is unchanged for fresh repos: the run still goes to your active org through the Platform.

For a detailed guide on writing fixtures, configuring secrets, and understanding the upload flow, see Testing guide.

List the orchestrator clusters connected to an organization, and set the per-org default cluster used by kici run remote. Requires kici login and an active org (or pass --org).

Terminal window
kici orchestrators list [--org <id>]
kici orchestrators use <clusterName> [--org <id>]

kici orchestrators list prints the org’s connected orchestrator clusters, so you know what to pass to --orchestrator (or to kici orchestrators use).

kici orchestrators use <clusterName> sets the default orchestrator cluster for the org, stored per-org in your global config. Subsequent kici run remote invocations target that cluster unless overridden with --orchestrator.

Examples:

Terminal window
# List the active org's connected clusters
kici orchestrators list
# List a specific org's clusters
kici orchestrators list --org xyz789ghi012
# Set the default cluster for the active org
kici orchestrators use us-east
# Set the default cluster for a specific org
kici orchestrators use us-east --org xyz789ghi012

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

Terminal window
kici test [event] [options]

Arguments:

ArgumentRequiredDescription
eventnoEvent type to preview (e.g., push, pr:open, schedule)

Options:

OptionDefaultDescription
--workflow <name>noneFilter to specific workflow
--job <name>noneFilter to specific job
--branch <name>mainOverride target branch for trigger matching
--sha <hash>noneOverride commit SHA
--files <path>noneSimulate changed file path for trigger matching (repeatable)
--secret <key=value>noneInject flat secret (repeatable)
--context <ctx.key=value>noneInject context secret (repeatable)
--debugfalseVerbose internals
--kici-dir <path>.kiciPath to .kici directory

Examples:

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

Exit codes:

CodeMeaning
0Preview completed (including zero matches)
1Error

Migration from old kici test <fixture>: If you were using kici test <fixture-name> for remote fixture execution, use kici run remote <fixture-name> instead. For local workflow execution, use kici run local <event>.

Authenticate with KiCI via browser-based OAuth (default) or API key (--token).

By default, kici login opens your browser for OIDC authentication using PKCE. In headless environments (SSH, CI, containers), it automatically switches to the RFC 8628 device authorization flow where you visit a URL and enter a code.

After OAuth, the CLI exchanges the OIDC token for a personal access token (PAT) stored in the config directory (~/.kici/config by default, overridable with KICI_CONFIG_DIR).

Terminal window
kici login [options]

Options:

OptionDefaultDescription
--token <key>noneAPI key for direct authentication (legacy)
--devicefalseForce device authorization flow (headless/SSH)
--platform-endpoint <url>nonePlatform API base URL

Environment variables:

VariableDefaultDescription
KICI_PLATFORM_URLhttps://api.kici.devPlatform API base URL (override for a self-hosted Platform)
KICI_OIDC_ISSUERhttps://auth.kici.dev/realms/kici-internalOIDC issuer URL (override for a self-hosted Platform)
KICI_OIDC_CLIENT_IDkici-cliOIDC client ID (override for a self-hosted Platform)
KICI_BROWSER_CMDuses open packageCustom browser command with {url} placeholder, or none to suppress
KICI_CALLBACK_PORTrandomFixed port for OAuth PKCE callback server
KICI_CONFIG_DIR~/.kiciOverride config directory

Examples:

Terminal window
# Browser-based OAuth login (default)
kici login
# Force device flow (for SSH/headless)
kici login --device
# Legacy API key login
kici login --token kici_sk_abc123...
# Log in against a self-hosted Platform
kici login --platform-endpoint https://platform.example.com
# Suppress browser opening (print authorize URL to stdout)
KICI_BROWSER_CMD=none kici login
# Use custom browser command
KICI_BROWSER_CMD='firefox {url}' kici login
# Fixed callback port and custom config directory
KICI_CALLBACK_PORT=19876 KICI_CONFIG_DIR=/tmp/kici-test kici login

Headless detection: The CLI automatically detects headless environments by checking for SSH_CLIENT, SSH_TTY, CI, GITHUB_ACTIONS, GITLAB_CI, container, or DOCKER_CONTAINER env vars, and on Linux, the absence of DISPLAY and WAYLAND_DISPLAY.

Revoke your personal access token on the server and clear local credentials.

If the server is unreachable, local credentials are still cleared (the PAT will expire automatically). Non-auth config fields (active org, default clusters, etc.) are preserved.

Terminal window
kici logout

Examples:

Terminal window
# Log out and revoke PAT
kici logout

Manage organization context. Requires a PAT (run kici login first).

List organizations you belong to. The active org is marked with a star (*).

Terminal window
kici org list

Example output:

Organizations:
* Personal (owner) abc123def456
My team (admin) xyz789ghi012

Switch the active organization by name (case-insensitive) or ID.

Terminal window
kici org use <name>

Arguments:

ArgumentRequiredDescription
nameyesOrganization name or ID

Examples:

Terminal window
# Switch by name
kici org use "My team"
# Switch by ID
kici org use xyz789ghi012

Show the current active organization.

Terminal window
kici org current

Show the orchestrators, scalers, and agents serving your organization — the terminal equivalent of the dashboard Diagnostics page. Reads the same org-scoped data the dashboard does, so it needs kici login and an active org (kici org use <name>).

The output has three parts: a one-line header (runs in the last 24h, success rate, average duration, queued/running job counts), any infrastructure alerts (only shown when present), and a tree of each orchestrator with its scalers and agents. Each agent line shows its labels, platform/architecture, active/maximum concurrency, and heartbeat age.

Terminal window
kici diagnostics [options]

Options:

OptionDefaultDescription
--jsonfalseMachine-readable JSON output
--verbosefalseShow extended per-agent fields (host, node, memory)
--orchestrator <id>allScope the tree to one orchestrator connection id

Examples:

Terminal window
# Show the full infrastructure tree
kici diagnostics
# Extended per-agent detail
kici diagnostics --verbose
# Only one orchestrator's scalers and agents
kici diagnostics --orchestrator conn-abc123
# Machine-readable output
kici diagnostics --json

Inspect and manage execution runs from the terminal — the equivalent of the dashboard Runs page. All kici runs subcommands read/write the same org-scoped data as the dashboard, so they require kici login and an active org (kici org use <name>).

List runs with optional filters. Output is a table (run id, workflow, status, branch, trigger, started, duration); pagination is reported at the bottom.

Terminal window
kici runs list [options]

Options:

OptionDefaultDescription
--status <s>allFilter by run status
--workflow <w>allFilter by workflow name
--branch <b>allFilter by branch/ref
--repo <r>allFilter by repository
--trigger <t>allFilter by trigger type
--source <routingKey>allFilter by source routing key
--since <ts>noneOnly runs since this ISO-8601 or epoch ms
--page <n>1Page number (server page size is fixed at 20)
--jsonfalseMachine-readable JSON output
Terminal window
kici runs list
kici runs list --status running
kici runs list --workflow ci --branch main
kici runs list --json | jq '.runs[].runId'

Show a run’s summary header plus its jobs-and-steps tree (name, status, duration, exit code). If the run id is not on the Platform but exists in your local run history (from kici run local), the local record is shown instead.

Terminal window
kici runs show <run-id> [options]
OptionDefaultDescription
--jsonfalseMachine-readable JSON output
Terminal window
kici runs show abc123
kici runs show abc123 --json

Print each job/step’s log lines in order, with headers.

Terminal window
kici runs logs <run-id> [options]
OptionDefaultDescription
--job <name>allOnly print logs for this job
-f, --followfalseTail logs for a live run until it ends
--jsonfalseMachine-readable JSON output
Terminal window
kici runs logs abc123
kici runs logs abc123 --job build
kici runs logs abc123 --follow

Re-trigger a completed run. Prints the new run id. The server enforces a short cooldown between reruns of the same run.

Terminal window
kici runs rerun <run-id> [options]
OptionDefaultDescription
--jsonfalseMachine-readable JSON output
Terminal window
kici runs rerun abc123

Cancel a single run, or all in-progress runs on a branch.

Terminal window
kici runs cancel [run-id] [options]
ArgumentRequiredDescription
run-idnoRun ID to cancel
OptionDefaultDescription
--forcefalseForce cancel (kill immediately, skip hooks)
--branch <name>noneCancel all in-progress runs on this branch
Terminal window
kici runs cancel abc123
kici runs cancel abc123 --force
kici runs cancel --branch feature/wip

When --json is set on any of these commands, kici emits only the JSON document on stdout — the kici v<version> banner is suppressed — so the output is safe to pipe into jq or JSON.parse. The same holds for the other --json commands (kici run remote --json, kici workflows list --json) and for --quiet.

Approve a held approval gate so the run resumes. Identify the held element by run ID, optionally narrowed to a job and step.

Terminal window
kici approve <run-id> [options]

Arguments:

ArgumentRequiredDescription
run-idyesRun ID holding the gate to approve

Options:

OptionDefaultDescription
--job <name>noneApprove a held job (omit for a workflow-level hold)
--step <name>noneApprove a held step (used with --job)
--reason <text>noneOptional note recorded with the approval

Examples:

Terminal window
# Approve a workflow-level hold
kici approve abc123
# Approve a held job
kici approve abc123 --job deploy-production
# Approve a held step
kici approve abc123 --job migrate-and-deploy --step apply-migration

You must be eligible for at least one unsatisfied clause (a member of a named team, or a named user) and hold the environments:write or ci_trust:write permission. The command reports whether the element was released, how many clauses remain, or that it was rejected.

Reject a held approval gate. A rejection fails the held element and the run. A reason is required.

Terminal window
kici reject <run-id> --reason <text> [options]

Arguments:

ArgumentRequiredDescription
run-idyesRun ID holding the gate to reject

Options:

OptionDefaultDescription
--reason <text>noneRequired. Reason recorded with the rejection
--job <name>noneReject a held job (omit for a workflow-level hold)
--step <name>noneReject a held step (used with --job)

Examples:

Terminal window
# Reject a held job with a reason
kici reject abc123 --job deploy-production --reason "Wrong release branch"

List secret contexts available for test runs. Shows context names and key names (not values).

Terminal window
kici secrets list [options]

Options:

OptionDefaultDescription
--endpoint <url>noneOrchestrator URL override

Each “context” corresponds to an environment configured on the orchestrator. The output lists every environment whose allowLocalExecution flag is true (the gate that lets CLI-initiated test runs resolve secrets through that environment), along with the secret key names reachable from the environment’s bound scopes.

Only key names are shown — secret values are never returned over this endpoint.

Prerequisites: authenticate via kici login and select an active organization with kici org use <name>.

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

Terminal window
kici types [options]

Options:

OptionDefaultDescription
--kici-dir <path>.kiciPath to .kici directory
--endpoint <url>noneOrchestrator URL override

Prerequisites: Must be authenticated via kici login.

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

Examples:

Terminal window
# Generate types from orchestrator
kici types
# Use custom .kici directory
kici types --kici-dir packages/app/.kici
# Override orchestrator endpoint
kici types --endpoint https://my-orchestrator.example.com

How it works:

  1. Fetches all environment metadata (environment names and secret key names) from the orchestrator
  2. Generates a .d.ts file that augments @kici-dev/sdk’s KnownSecretKeys and EnvironmentSecrets interfaces
  3. Writes the file to .kici/types/secrets.d.ts

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

Git workflow: Commit the generated .kici/types/secrets.d.ts so team members get type checking without needing orchestrator access. Run kici types to refresh when environments change.

Auto-regeneration: kici compile automatically runs kici types after successful compilation when authenticated. 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.

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

Terminal window
kici fixture <event> [options]

Arguments:

ArgumentRequiredDescription
eventyesEvent to generate fixture for

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, 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>.

Options:

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

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

Initialize a .kici/ directory with default workflow templates.

Terminal window
kici init [options]

Options:

OptionDefaultDescription
--forcefalseOverwrite existing .kici/ directory
--skip-installfalseCreate files without installing dependencies
--package-manager <npm|pnpm|yarn>auto-detectForce a package manager for the install step (default: detect from your repo)
--mjsfalseJavaScript-only mode (no TypeScript, no deps)
--no-agents-mdwrites AGENTS.mdSkip writing .kici/AGENTS.md (the LLM authoring context file)
--private-registry <url>noneScaffold a workflow registries: entry pointing at <url> (e.g. CodeArtifact, GH Packages, Verdaccio)
--private-registry-scope <scope>noneOptional npm package scope (e.g. @my-org) for the private registry
--private-registry-secret <ref>production:NPM_TOKENQualified secret reference (env:NAME) the private registry token comes from

Examples:

Terminal window
# Interactive initialization
kici init
# Overwrite existing setup
kici init --force
# Skip dependency install (faster, install manually later)
kici init --skip-install
# Force a specific package manager (default: detect from your repo)
kici init --package-manager pnpm
# JavaScript mode (no TypeScript)
kici init --mjs
# Skip writing the AGENTS.md LLM authoring context file
kici init --no-agents-md
# Scaffold a workflow registries entry for a private npm registry
kici init --private-registry https://npm.pkg.github.com/ \
--private-registry-scope @my-org \
--private-registry-secret production:GITHUB_PACKAGES_TOKEN

What it creates:

.kici/
workflows/
hello-world.ts # Minimal push workflow
pr-checks.ts # Comprehensive PR workflow
tests/
push-test.ts # Sample test fixture
types/ # Directory for generated type declarations (kici types)
package.json # Dependencies (@kici-dev/sdk)
tsconfig.json # TypeScript configuration (includes types/**/*.d.ts)
.kiciignore # Default exclusion patterns for test uploads

In interactive mode (TTY), kici init prompts you to:

  1. Select which workflow templates to include
  2. Optionally install a pre-commit hook

Package manager: the dependency install step uses the package manager detected for your repo — the packageManager field in the nearest package.json (Corepack convention), then a lockfile in the project root (pnpm-lock.yaml → pnpm, yarn.lock → yarn, package-lock.json → npm), then the package manager that invoked kici (pnpm dlx / yarn dlx / npx), defaulting to npm. Pass --package-manager <npm|pnpm|yarn> to override detection, or --skip-install to set up the files and install later yourself.

Development mode: When KICI_DEV=true or package.json has "kici": { "development": true }, the generated package.json uses prerelease-compatible version ranges (>=0.0.1-0) so npm resolves Verdaccio’s prerelease builds.

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

Terminal window
kici hook install [options]

Options:

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

Examples:

Terminal window
# Auto-detect hook tool (husky, lint-staged, etc.)
kici hook install
# Force raw git hook
kici hook install --git

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

  • Husky: Adds to .husky/pre-commit
  • lint-staged: Adds to lint-staged configuration
  • Raw git: Writes .git/hooks/pre-commit

If multiple tools are detected, you are prompted to choose.

List all webhook entrypoints for the current project. Reads the compiled lock file and displays webhook URLs grouped by type (git provider, generic webhooks, scheduled, event-driven).

Terminal window
kici endpoints [options]

Options:

OptionDefaultDescription
--kici-dir <path>.kiciPath to .kici directory

Prerequisites: Run kici compile first to generate the lock file.

Examples:

Terminal window
# List all webhook entrypoints
kici endpoints
# Custom .kici directory
kici endpoints --kici-dir packages/app/.kici

List permanently registered workflows on the orchestrator.

Terminal window
kici workflows list [options]

Options:

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

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

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://kici.dev/docs/
kici docs --no-open # print the URL instead of opening a browser
kici docs llm # print llms-full.txt (the full bundle) to stdout
kici docs llm --index # print llms.txt (the curated link index) to stdout
kici docs llm --out path/to/file.md # write the bundle to a file

Examples:

Terminal window
# Open the docs site in your browser
kici docs
# Pipe the full LLM bundle into a coding agent
kici docs llm | claude -- "Read this and help me author a deploy workflow"
# Save the curated index for offline reference
kici docs llm --index --out kici-llms.txt

The bundle is regenerated from docs/ every time @kici-dev/compiler is built, so it always matches your installed CLI version. The same content is available online at https://kici.dev/llms.txt and https://kici.dev/llms-full.txt following the llms.txt convention.

Operator-facing commands for running instances.

Trigger graceful drain on a worker instance. Sends a POST request to the worker’s /drain endpoint.

Terminal window
kici admin drain-worker [options]

Options:

OptionRequiredDescription
--url <url>yesWorker URL (e.g., http://worker-host:10143)

Examples:

Terminal window
# Drain a local worker
kici admin drain-worker --url http://localhost:10143
# Drain a remote worker
kici admin drain-worker --url http://worker-2.internal:10143

Exit codes:

CodeMeaning
0Drain request accepted
1Error (unreachable or request fail)

Verify a KiCI build-provenance attestation bundle offline. A bundle is the signed package a workflow step produces via ctx.attestProvenance(...): a DSSE-wrapped SLSA in-toto statement, the ephemeral public key that signed it, and the KiCI identity token that anchors the build context. For the end-to-end attest → verify → view journey, see the build provenance guide. Verification establishes the full chain — the identity token verifies against the trusted issuer’s JWKS, the DSSE signature verifies against the bundled key, and the statement’s build context must match the token’s claims (a mismatch is a hard failure). When an [artifact] is given, its SHA-256 digest is also matched against the attestation subject.

Terminal window
kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-file> [options]

Arguments:

ArgumentRequiredDescription
[artifact]noArtifact path to digest-check against the attestation subject digest.

Options:

OptionRequiredDescription
--bundle <path-or-url>yesPath or http(s) URL to the attestation bundle JSON.
--trust-root <url-or-file>yesTrusted issuer (see below). The token issuer is pinned to it, never taken from the token.
--audience <aud>noExpected token audience (defaults to the KiCI provenance audience).
--jsonnoPrint the structured verification result as JSON instead of human-readable output.

Trust root: the verifier never trusts the issuer named inside the token — you supply the trusted issuer out-of-band via --trust-root, in one of two forms:

  • Online — an HTTPS issuer URL. The verifier fetches <url>/.well-known/openid-configuration, reads its issuer and jwks_uri, and fetches the JWKS. The token’s iss is pinned to the discovery document’s issuer.

  • Offline — a self-contained trust-root file. A local JSON file with the issuer and JWKS inlined, so no network access is needed (air-gapped verification):

    {
    "issuer": "https://platform.example/issuer",
    "jwks": {
    "keys": [
    { "kty": "EC", "crv": "P-256", "x": "...", "y": "...", "alg": "ES256", "kid": "..." }
    ]
    }
    }

Examples:

Terminal window
# Online: verify a bundle against a deployed issuer, digest-checking the artifact
kici verify-attestation ./dist/app.tgz \
--bundle ./app.tgz.kici.json \
--trust-root https://platform.example/issuer
# Offline / air-gapped: verify against a self-contained trust-root file
kici verify-attestation ./dist/app.tgz \
--bundle ./app.tgz.kici.json \
--trust-root ./kici-trust-root.json
# Machine-readable result for scripting
kici verify-attestation --bundle ./app.tgz.kici.json \
--trust-root https://platform.example/issuer --json

Exit codes:

CodeMeaning
0Verified — signature, identity, build context (and digest, if checked) all pass
1Not verified, or an error (missing flag, unreadable bundle, unreachable trust root)

The CLI discovers workflows by scanning .kici/workflows/*.ts (or .mjs in MJS mode). Each file should export default a single workflow:

.kici/workflows/ci.ts
import { workflow, job, step, pr } from '@kici-dev/sdk';
export default workflow('ci', {
on: pr(),
jobs: [
/* ... */
],
});

Multiple workflow files are supported — each becomes a separate workflow in kici.lock.json.

The kici compile command produces .kici/kici.lock.json inside the .kici directory. This file:

  • Contains all workflow definitions in a portable JSON format
  • Is used by the orchestrator to evaluate triggers without code checkout
  • Should be committed to version control
  • Is regenerated on every kici compile run

Use kici compile --check in CI to validate that workflows are correct without writing files. For the full story on drift, pre-commit/CI, and agent-side verification, see Lock file and workflow drift.

All commands follow a consistent exit code convention:

CodeMeaning
0Success
1Failure (see output)

Use --debug (on kici run local, kici run remote, kici test) or --verbose (on kici compile) for detailed output:

Terminal window
# Shows trigger matching, rule evaluation, decision traces
kici run local push --debug
# Shows detailed compilation steps
kici compile --verbose
# Shows trigger matching preview
kici test pr:open --debug

Set KICI_DEBUG=true for additional internal debug output across all commands.

VariableDescription
KICI_DEVSet to true for development mode
KICI_DEBUGSet to true for verbose internal output
CIWhen true, disables interactive prompts
  • Getting started — install the SDK and write your first workflow
  • Testing guide — writing fixtures, remote test runs, secret contexts, and repo state transfer
  • SDK reference — complete API for the workflow definitions that the CLI compiles
  • Workflow patterns — example workflows to compile and test with these commands