@kici-dev/compiler 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-banner.d.ts +6 -3
- package/dist/cli-banner.js +13 -5
- package/dist/cli.js +66 -43
- package/dist/commands/check-mode.d.ts +1 -1
- package/dist/commands/compile.js +3 -3
- package/dist/commands/index.d.ts +5 -1
- package/dist/commands/index.js +6 -3
- package/dist/commands/init.js +1 -1
- package/dist/commands/local-trust-root.d.ts +6 -0
- package/dist/commands/local-trust-root.js +52 -0
- package/dist/commands/local.d.ts +39 -0
- package/dist/commands/local.js +137 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +40 -0
- package/dist/commands/logout.js +7 -0
- package/dist/commands/preview.js +1 -1
- package/dist/commands/run-banner.d.ts +31 -0
- package/dist/commands/run-banner.js +25 -0
- package/dist/commands/run-routed.d.ts +53 -0
- package/dist/commands/run-routed.js +176 -0
- package/dist/commands/run.d.ts +0 -17
- package/dist/commands/run.js +7 -50
- package/dist/commands/secrets-list.d.ts +2 -2
- package/dist/commands/secrets-list.js +4 -4
- package/dist/commands/types.d.ts +3 -3
- package/dist/commands/types.js +4 -4
- package/dist/execution/executor.js +7 -7
- package/dist/generators/secrets-dts.d.ts +9 -9
- package/dist/generators/secrets-dts.js +12 -12
- package/dist/llm-context/llms-architecture.txt +2 -2
- package/dist/llm-context/llms-cli.txt +674 -340
- package/dist/llm-context/llms-features.txt +334 -336
- package/dist/llm-context/llms-full.txt +1207 -892
- package/dist/llm-context/llms-getting-started.txt +7 -15
- package/dist/llm-context/llms-patterns.txt +5 -23
- package/dist/llm-context/llms-providers.txt +10 -1
- package/dist/llm-context/llms-sdk.txt +12 -12
- package/dist/llm-context/llms.txt +5 -5
- package/dist/local-executor/secret-loader.d.ts +1 -1
- package/dist/local-plane/orchestrator-process.d.ts +65 -0
- package/dist/local-plane/orchestrator-process.js +115 -0
- package/dist/local-plane/paths.d.ts +39 -0
- package/dist/local-plane/paths.js +54 -0
- package/dist/local-plane/plane-manager.d.ts +151 -0
- package/dist/local-plane/plane-manager.js +340 -0
- package/dist/local-plane/plane-seed.d.ts +76 -0
- package/dist/local-plane/plane-seed.js +59 -0
- package/dist/local-plane/plane-trigger.d.ts +62 -0
- package/dist/local-plane/plane-trigger.js +97 -0
- package/dist/local-plane/platform-attach.d.ts +53 -0
- package/dist/local-plane/platform-attach.js +111 -0
- package/dist/local-plane/postgres.d.ts +44 -0
- package/dist/local-plane/postgres.js +165 -0
- package/dist/local-plane/resolve-plane.d.ts +37 -0
- package/dist/local-plane/resolve-plane.js +76 -0
- package/dist/local-plane/run-follow.d.ts +41 -0
- package/dist/local-plane/run-follow.js +104 -0
- package/dist/local-plane/scaler-config.d.ts +54 -0
- package/dist/local-plane/scaler-config.js +114 -0
- package/dist/local-plane/secret-seed.d.ts +59 -0
- package/dist/local-plane/secret-seed.js +112 -0
- package/dist/local-plane/source-provider.d.ts +43 -0
- package/dist/local-plane/source-provider.js +165 -0
- package/dist/local-plane/trusted-routing.d.ts +32 -0
- package/dist/local-plane/trusted-routing.js +47 -0
- package/dist/lockfile/generator.js +7 -7
- package/dist/remote/dashboard-client.d.ts +7 -7
- package/dist/remote/dashboard-client.js +7 -7
- package/dist/remote/platform-client.d.ts +1 -1
- package/dist/remote/secret-loader.d.ts +18 -0
- package/dist/{local-executor → remote}/secret-loader.js +4 -4
- package/dist/remote/secret-upload.d.ts +1 -1
- package/dist/remote/secret-upload.js +2 -2
- package/dist/remote/uploader.d.ts +1 -1
- package/dist/remote/uploader.js +2 -2
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +2 -2
- package/dist/templates/package-json.js +1 -1
- package/dist/test-runner/job-executor.js +1 -1
- package/dist/test-runner/runs-on-display.d.ts +9 -0
- package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
- package/dist/test-runner/step-context.d.ts +1 -1
- package/dist/test-runner/step-context.js +2 -2
- package/dist/types.d.ts +6 -6
- package/package.json +7 -4
- package/sbom.spdx.json +9884 -1459
- package/dist/local-executor/dag-scheduler.js +0 -183
- package/dist/local-executor/index.js +0 -378
- package/dist/local-executor/job-runner.js +0 -411
- package/dist/local-executor/materializer.js +0 -132
- package/dist/local-executor/output-streamer.js +0 -168
- package/dist/local-executor/payload-generator.js +0 -138
- package/dist/local-executor/picker.js +0 -109
- package/dist/local-executor/to-event-payload.js +0 -21
- package/dist/local-executor/types.js +0 -2
- package/dist/local-executor/workflow-lock.js +0 -0
|
@@ -40,7 +40,7 @@ Guide to the KiCI web dashboard. Covers navigation (sidebar, org switcher, mobil
|
|
|
40
40
|
|
|
41
41
|
How to run and write tests for KiCI workflows, including remote test execution with `kici run remote`, fixture-based testing, and overlay mode for uncommitted changes.
|
|
42
42
|
|
|
43
|
-
### [
|
|
43
|
+
### [Contexts](https://docs.kici.dev/user/contexts/)
|
|
44
44
|
|
|
45
45
|
Configure deployment environments (staging, production, review/\*) with variables, scoped secrets, and protection rules. Covers the SDK API (`environment`, `env`, `concurrencyGroup` on jobs), the 8-layer variable merge precedence, protection rules (branch restrictions, required reviewers, wait timers, concurrency), dashboard management, type generation, and migration from the legacy contexts system.
|
|
46
46
|
|
|
@@ -279,21 +279,13 @@ Decision Summary:
|
|
|
279
279
|
|
|
280
280
|
## Run locally
|
|
281
281
|
|
|
282
|
-
Execute matched workflows locally with `kici run local`:
|
|
282
|
+
Execute matched workflows locally with `kici run <event> --local`:
|
|
283
283
|
|
|
284
284
|
```bash
|
|
285
|
-
npx kici run
|
|
285
|
+
npx kici run pr:open --local
|
|
286
286
|
```
|
|
287
287
|
|
|
288
|
-
This compiles, matches triggers, and runs all matched jobs with DAG-based parallel scheduling.
|
|
289
|
-
|
|
290
|
-
If you do not want to remember the event arg, pass `--pick` (or `-p`) and pick from a list of workflows instead:
|
|
291
|
-
|
|
292
|
-
```bash
|
|
293
|
-
npx kici run local --pick
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
The picker lists each workflow with a summary of its declared triggers, derives the event arg for the one you choose, and runs it through the same pipeline.
|
|
288
|
+
This compiles, matches triggers, and runs all matched jobs on this machine — which joins as an ephemeral agent through the warm local dev plane — with DAG-based parallel scheduling.
|
|
297
289
|
|
|
298
290
|
## Workflow dependencies
|
|
299
291
|
|
|
@@ -418,14 +410,14 @@ Or add the flag to your root `package.json`:
|
|
|
418
410
|
|
|
419
411
|
## Authoring KiCI workflows with LLM coding agents
|
|
420
412
|
|
|
421
|
-
KiCI is LLM-ready by design. Because workflows are real, typed TypeScript, coding agents reason over the SDK's `.d.ts` signatures instead of guessing a bespoke YAML DSL — and they verify their own pipelines with the same `kici preview` and `kici run local` loop you use, so there's no push-to-find-out round-trip. First-class agent context ships in the box, so an agent is briefed the moment it opens the project.
|
|
413
|
+
KiCI is LLM-ready by design. Because workflows are real, typed TypeScript, coding agents reason over the SDK's `.d.ts` signatures instead of guessing a bespoke YAML DSL — and they verify their own pipelines with the same `kici preview` and `kici run <event> --local` loop you use, so there's no push-to-find-out round-trip. First-class agent context ships in the box, so an agent is briefed the moment it opens the project.
|
|
422
414
|
|
|
423
415
|
KiCI ships first-class context for LLM coding agents (Claude Code, Cursor, Aider, etc.). When you scaffold a project with `kici init`, the CLI writes `.kici/AGENTS.md`, a one-page briefing that tells the agent:
|
|
424
416
|
|
|
425
417
|
- where the SDK type declarations live (`node_modules/@kici-dev/sdk/dist/index.d.ts`)
|
|
426
418
|
- the five canonical authoring patterns with runnable examples
|
|
427
419
|
- the anti-patterns that catch agents off-guard (no YAML, no `/dist/...` imports, no top-level `await`)
|
|
428
|
-
- the local commands the agent should drive (`kici compile --check`, `kici preview`, `kici run local`, `kici docs llm`)
|
|
420
|
+
- the local commands the agent should drive (`kici compile --check`, `kici preview`, `kici run <event> --local`, `kici docs llm`)
|
|
429
421
|
|
|
430
422
|
If you don't want the file, pass `--no-agents-md` to `kici init`, or delete the file afterwards — KiCI never reads it at runtime.
|
|
431
423
|
|
|
@@ -516,7 +508,7 @@ If you're not sure, pick Docker / Podman.
|
|
|
516
508
|
|
|
517
509
|
## Looking for the laptop-only path?
|
|
518
510
|
|
|
519
|
-
Both quickstarts deploy a real orchestrator + agent. If you only want to write a workflow and dry-run it on your laptop with no infrastructure, [Getting started](https://docs.kici.dev/user/getting-started/) covers `kici preview` and `kici run local` instead.
|
|
511
|
+
Both quickstarts deploy a real orchestrator + agent. If you only want to write a workflow and dry-run it on your laptop with no infrastructure, [Getting started](https://docs.kici.dev/user/getting-started/) covers `kici preview` and `kici run <event> --local` instead.
|
|
520
512
|
|
|
521
513
|
---
|
|
522
514
|
|
|
@@ -714,7 +706,7 @@ Sometimes you want a workflow that does **not** fire on pushes, pull requests, t
|
|
|
714
706
|
|
|
715
707
|
There are two ways to "explicitly invoke" a `dispatch()` workflow:
|
|
716
708
|
|
|
717
|
-
1. **Locally from your laptop**, with `kici run local
|
|
709
|
+
1. **Locally from your laptop**, with `kici run dispatch --local` — this machine joins as an ephemeral agent through the warm local dev plane, so no orchestrator deployment is required. This is the path to use while you haven't wired the repo to a deployed KiCI orchestrator.
|
|
718
710
|
2. **Remotely**, if the repo is connected to a KiCI orchestrator via a GitHub App, by calling GitHub's repository-dispatch API: `curl -X POST -H "Authorization: token <PAT>" -H "Accept: application/vnd.github+json" https://api.github.com/repos/<owner>/<repo>/dispatches -d '{"event_type":"hello"}'`. GitHub fans the webhook out to the App, the orchestrator normalizes it into a KiCI `dispatch` event (see `packages/orchestrator/src/providers/github/normalizer.ts`), and the matched workflow runs.
|
|
719
711
|
|
|
720
712
|
Note that GitHub's `workflow_dispatch` event (the "Run workflow" button / `/actions/workflows/.../dispatches` API) is GitHub-Actions-internal and is **not** delivered to KiCI. The SDK has no `workflowDispatch()` trigger. Only `repository_dispatch` reaches KiCI.
|
|
@@ -737,36 +729,18 @@ export default workflow('hello-world', {
|
|
|
737
729
|
});
|
|
738
730
|
```
|
|
739
731
|
|
|
740
|
-
Run it locally, without any orchestrator
|
|
732
|
+
Run it locally, without any orchestrator deployment:
|
|
741
733
|
|
|
742
734
|
```bash
|
|
743
735
|
npx kici compile # regenerate .kici/kici.lock.json
|
|
744
|
-
npx kici run local
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
`kici run local` compiles the workflow, matches triggers against a simulated `dispatch` event, and executes the matched jobs directly on your machine with DAG-based scheduling. No webhook, no GitHub, no deployed orchestrator involved. See [`kici run local`](https://docs.kici.dev/user/cli-reference/#kici-run-local) for options like `--job`, `--env`, `--json`, and `--junit`.
|
|
748
|
-
|
|
749
|
-
### Scoping to a single workflow
|
|
750
|
-
|
|
751
|
-
Because `kici run local dispatch` matches **every** workflow that listens for a `dispatch` event, running it in a repo with several dispatch-triggered workflows will fire all of them. Narrow execution to one with `--workflow <name>`:
|
|
752
|
-
|
|
753
|
-
```bash
|
|
754
|
-
npx kici run local dispatch --workflow hello-world
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
`--workflow` is a post-match filter: the workflow still has to have a trigger that matches the event argument. If `hello-world` does not list a `dispatch()` trigger, the command reports `No workflow named "hello-world" matched the event` and exits successfully without running anything.
|
|
758
|
-
|
|
759
|
-
If you do not want to memorise event args, use the interactive picker instead:
|
|
760
|
-
|
|
761
|
-
```bash
|
|
762
|
-
npx kici run local --pick
|
|
736
|
+
npx kici run dispatch --local
|
|
763
737
|
```
|
|
764
738
|
|
|
765
|
-
|
|
739
|
+
`kici run dispatch --local` compiles the workflow, matches triggers against a simulated `dispatch` event, and executes the matched jobs on this machine — which joins as an ephemeral agent through the warm local dev plane — with DAG-based scheduling. No webhook, no GitHub, no deployed orchestrator involved. See [`kici run <event> --local`](https://docs.kici.dev/user/cli-reference/#kici-run-event---local) for options like `--env`, `--in-place`, and `--offline`.
|
|
766
740
|
|
|
767
741
|
### Unfiltered vs typed `dispatch()`
|
|
768
742
|
|
|
769
|
-
Leave `dispatch()` unfiltered while you drive it from `kici run local`. The CLI
|
|
743
|
+
Leave `dispatch()` unfiltered while you drive it from `kici run <event> --local`. The CLI simulates a dispatch event with no event type (i.e. `action` is undefined), so a trigger defined as `dispatch({ types: ['deploy', 'rollback'] })` will not match `kici run dispatch --local` — the typed form is intended for real `repository_dispatch` deliveries from the orchestrator.
|
|
770
744
|
|
|
771
745
|
## Conditional execution with rules
|
|
772
746
|
|
|
@@ -2012,8 +1986,8 @@ function workflow(name: string, options: WorkflowOptions): Workflow;
|
|
|
2012
1986
|
| `options.rules` | `Rule[]` | no | Conditions that must pass for execution |
|
|
2013
1987
|
| `options.description` | `string` | no | Human-readable description |
|
|
2014
1988
|
| `options.hashFiles` | `string[]` | no | Extra repo-relative paths or globs mixed into the workflow content hash. Changes invalidate the source cache. |
|
|
2015
|
-
| `options.registries` | `Registry[]` | no | Private npm registries the agent authenticates against before `npm install`. Each `tokenSecret` uses qualified `<
|
|
2016
|
-
| `options.installEnv` | `string[]` | no | Qualified `<
|
|
1989
|
+
| `options.registries` | `Registry[]` | no | Private npm registries the agent authenticates against before `npm install`. Each `tokenSecret` uses qualified `<context>:<secret>` syntax. |
|
|
1990
|
+
| `options.installEnv` | `string[]` | no | Qualified `<context>:<secret>` refs projected as env vars onto the install subprocess (used with a customer-committed `.kici/.npmrc`). |
|
|
2017
1991
|
| `options.onCancel` | `HookInput` | no | Runs when the workflow is cancelled |
|
|
2018
1992
|
| `options.cleanup` | `HookInput` | no | Always runs after the workflow (success, failure, or cancel) |
|
|
2019
1993
|
| `options.onSuccess` | `HookInput` | no | Runs on workflow success |
|
|
@@ -2564,7 +2538,7 @@ step('fetch-token', {
|
|
|
2564
2538
|
- **Timeout is per-attempt.** Each attempt gets the step's full `timeout` budget — a timed-out attempt counts as one failed attempt and is retried while attempts remain. The total wall-clock can therefore approach `maxAttempts * (timeout + delay)`, so keep `maxAttempts` and `maxDelayMs` sane (the job-level `timeout` still bounds the whole job).
|
|
2565
2539
|
- **Retries exhaust before `continueOnError`.** A step with both retries first; only the _final_ failure is then softened to a warning by `continueOnError`.
|
|
2566
2540
|
|
|
2567
|
-
`retry` works identically under `kici run local` and on a remote agent, and applies to dynamically-generated job steps too. The `retryIf` predicate is an in-memory function: it is honored at execution time but never serialized into the lock file.
|
|
2541
|
+
`retry` works identically under `kici run <event> --local` and on a remote agent, and applies to dynamically-generated job steps too. The `retryIf` predicate is an in-memory function: it is honored at execution time but never serialized into the lock file.
|
|
2568
2542
|
|
|
2569
2543
|
> **Retry vs. wait-until-condition.** `retry` re-runs a step that _throws_. To poll until a condition becomes true (a port listening, a `/health` endpoint returning 200, a unit becoming active), use [`waitForStep`](https://docs.kici.dev/user/sdk/wait-for/) instead — it is purpose-built for declarative wait-for-condition with intervals, a timeout, and on-timeout handling.
|
|
2570
2544
|
|
|
@@ -2650,7 +2624,7 @@ const deploy = job('deploy', {
|
|
|
2650
2624
|
|
|
2651
2625
|
**Important:** `needs` must be declared explicitly. Output chaining does not auto-infer dependencies -- you must list job dependencies in `needs` even if you access their outputs via `.result`.
|
|
2652
2626
|
|
|
2653
|
-
Cross-job output chaining works in both local execution (`kici run local`) and remote pipeline execution. The orchestrator's needs-aware dispatch scheduler guarantees upstream jobs reach a terminal state before downstream jobs dispatch, and upstream outputs are transported to the downstream agent sandbox via the `upstreamJobOutputs` field on `job.dispatch`. See [needs-scheduler](https://docs.kici.dev/architecture/execution/needs-scheduler/) for the full dispatch semantics.
|
|
2627
|
+
Cross-job output chaining works in both local execution (`kici run <event> --local`) and remote pipeline execution. The orchestrator's needs-aware dispatch scheduler guarantees upstream jobs reach a terminal state before downstream jobs dispatch, and upstream outputs are transported to the downstream agent sandbox via the `upstreamJobOutputs` field on `job.dispatch`. See [needs-scheduler](https://docs.kici.dev/architecture/execution/needs-scheduler/) for the full dispatch semantics.
|
|
2654
2628
|
|
|
2655
2629
|
### Job dependencies (`needs`)
|
|
2656
2630
|
|
|
@@ -3391,7 +3365,7 @@ inside a fan-out job nests its concurrency inside each fan-out child.
|
|
|
3391
3365
|
## Local vs remote execution
|
|
3392
3366
|
|
|
3393
3367
|
Run remotely (the orchestrator + agent), parallel children execute concurrently
|
|
3394
|
-
and each surfaces as its own dashboard step. `kici run local` executes the same
|
|
3368
|
+
and each surfaces as its own dashboard step. `kici run <event> --local` executes the same
|
|
3395
3369
|
children in array order in its single-process model — the results are identical,
|
|
3396
3370
|
only the wall-clock and the live fail-fast cancellation differ. Use a remote run
|
|
3397
3371
|
to observe the concurrent timeline.
|
|
@@ -3531,7 +3505,7 @@ Every variant carries the shared `EventBase` fields — `type`, `action`, `targe
|
|
|
3531
3505
|
|
|
3532
3506
|
Matrix configurations expand a single job into multiple instances, one per parameter combination. Maximum 256 combinations.
|
|
3533
3507
|
|
|
3534
|
-
Expansion happens at **dispatch time**: the orchestrator materializes the matrix into N execution jobs — one per combination, each dispatched to its own agent — before any job runs. Each instance receives its combination as `ctx.matrix`. This is identical whether the workflow runs via `kici run local` or remotely through a webhook trigger, and the dashboard groups the N instances under one parent node.
|
|
3508
|
+
Expansion happens at **dispatch time**: the orchestrator materializes the matrix into N execution jobs — one per combination, each dispatched to its own agent — before any job runs. Each instance receives its combination as `ctx.matrix`. This is identical whether the workflow runs via `kici run <event> --local` or remotely through a webhook trigger, and the dashboard groups the N instances under one parent node.
|
|
3535
3509
|
|
|
3536
3510
|
### Static array (single dimension)
|
|
3537
3511
|
|
|
@@ -3677,7 +3651,7 @@ step('collect', async ({ jobOutputs }) => {
|
|
|
3677
3651
|
});
|
|
3678
3652
|
```
|
|
3679
3653
|
|
|
3680
|
-
The downstream job waits for **all** matrix combinations to terminate before it dispatches. A non-matrix upstream keeps the flat outputs shape. The envelope is identical under `kici run local` and the remote path.
|
|
3654
|
+
The downstream job waits for **all** matrix combinations to terminate before it dispatches. A non-matrix upstream keeps the flat outputs shape. The envelope is identical under `kici run <event> --local` and the remote path.
|
|
3681
3655
|
|
|
3682
3656
|
### Matrix type guards
|
|
3683
3657
|
|
|
@@ -4601,14 +4575,14 @@ verify → view journey, including how to verify a bundle with `kici verify-atte
|
|
|
4601
4575
|
|
|
4602
4576
|
Workflows access secrets through `ctx.secrets` on `StepContext`. Use `await ctx.secrets.get('KEY')` to retrieve a value (rejects with `SecretNotFoundError` if the key is missing, fail-fast on typos), `ctx.secrets.has('KEY')` for a synchronous existence check, and `await ctx.secrets.expose('KEY')` when you need the value as a `process.env` entry for a child process.
|
|
4603
4577
|
|
|
4604
|
-
### Declaring the secret
|
|
4578
|
+
### Declaring the secret context
|
|
4605
4579
|
|
|
4606
|
-
Each job picks its secret
|
|
4580
|
+
Each job picks its secret context via the `context` option on `job()`. The orchestrator resolves the context's scoped-secret store at dispatch time, evaluates access rules, and sends the decrypted secrets to the agent:
|
|
4607
4581
|
|
|
4608
4582
|
```typescript
|
|
4609
4583
|
const deploy = job('deploy', {
|
|
4610
4584
|
runsOn: 'linux',
|
|
4611
|
-
|
|
4585
|
+
context: 'production',
|
|
4612
4586
|
steps: [
|
|
4613
4587
|
/* ... */
|
|
4614
4588
|
],
|
|
@@ -4620,11 +4594,11 @@ export default workflow('deploy', {
|
|
|
4620
4594
|
});
|
|
4621
4595
|
```
|
|
4622
4596
|
|
|
4623
|
-
`
|
|
4597
|
+
`context` accepts either a static string or an async function `(event) => string | Promise<string>` for dynamic resolution at trigger-evaluation time. The resolved context's secrets are flattened into `ctx.secrets`.
|
|
4624
4598
|
|
|
4625
4599
|
### Accessing secrets (ctx.secrets)
|
|
4626
4600
|
|
|
4627
|
-
`ctx.secrets` provides flat access to the secrets resolved for the job's
|
|
4601
|
+
`ctx.secrets` provides flat access to the secrets resolved for the job's context.
|
|
4628
4602
|
|
|
4629
4603
|
```typescript
|
|
4630
4604
|
step('deploy', async ({ secrets }) => {
|
|
@@ -6127,7 +6101,7 @@ The dashboard is a browser SPA on top of the same `/api/v1/*` surface, so anythi
|
|
|
6127
6101
|
|
|
6128
6102
|
- **Auth & identity:** `/cli/exchange-token`, `/pats`, `/user`, `/identity-links`, `/github-oauth`, `/invites`, `/invites/pending`, `/invites/:inviteId/{accept,decline}`
|
|
6129
6103
|
- **Org & membership:** `/orgs`, `/orgs/:customerId`, `/orgs/:customerId/{members,roles,api-keys,orchestrator-keys,service-accounts,billing,trust-policies}`
|
|
6130
|
-
- **Workflows & runs:** `/orgs/:customerId/{runs,registrations,workflows,held-runs,
|
|
6104
|
+
- **Workflows & runs:** `/orgs/:customerId/{runs,registrations,workflows,held-runs,contexts,secrets,global-workflows}`
|
|
6131
6105
|
- **Webhooks & event log:** `/orgs/:customerId/{sources,webhook-endpoints,event-log}`
|
|
6132
6106
|
- **Diagnostics & activity:** `/orgs/:customerId/{diagnostics,activity,access-log}`
|
|
6133
6107
|
|
|
@@ -6251,15 +6225,6 @@ Compile workflows from `.kici/workflows/` to `kici.lock.json`.
|
|
|
6251
6225
|
kici compile [options]
|
|
6252
6226
|
```
|
|
6253
6227
|
|
|
6254
|
-
**Options:**
|
|
6255
|
-
|
|
6256
|
-
| Option | Default | Description |
|
|
6257
|
-
| ------------------- | ------- | -------------------------------------------- |
|
|
6258
|
-
| `--check` | `false` | Validate workflows without writing lock file |
|
|
6259
|
-
| `--watch` | `false` | Watch for changes and recompile |
|
|
6260
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
6261
|
-
| `--verbose` | `false` | Detailed output |
|
|
6262
|
-
|
|
6263
6228
|
**Examples:**
|
|
6264
6229
|
|
|
6265
6230
|
```bash
|
|
@@ -6292,69 +6257,21 @@ The `--check` flag is useful in CI pipelines and pre-commit hooks. It validates
|
|
|
6292
6257
|
|
|
6293
6258
|
### kici run
|
|
6294
6259
|
|
|
6295
|
-
Execute workflows locally or remotely.
|
|
6296
|
-
|
|
6297
|
-
#### kici run local
|
|
6298
|
-
|
|
6299
|
-
Execute workflows locally without orchestrator infrastructure. Compiles workflows, matches triggers against the specified event, expands matrices, and runs jobs with DAG-based parallel scheduling.
|
|
6300
|
-
|
|
6301
|
-
```bash
|
|
6302
|
-
kici run local [event] [options]
|
|
6303
|
-
```
|
|
6304
|
-
|
|
6305
|
-
**Arguments:**
|
|
6306
|
-
|
|
6307
|
-
| Argument | Required | Description |
|
|
6308
|
-
| -------- | ---------------------- | ------------------------------------------------ |
|
|
6309
|
-
| `event` | when `--pick` is unset | Event type (e.g., `push`, `pr:open`, `schedule`) |
|
|
6260
|
+
Execute workflows locally or remotely. A bare `kici run [event]` performs a real routed run with this machine as the ephemeral agent; the `remote` subcommand runs fixtures through an orchestrator.
|
|
6310
6261
|
|
|
6311
|
-
|
|
6262
|
+
#### kici run <event> --local
|
|
6312
6263
|
|
|
6313
|
-
|
|
6314
|
-
| --------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
6315
|
-
| `-p, --pick` | `false` | Interactively pick a workflow + trigger (see below) |
|
|
6316
|
-
| `--workflow <name>` | none | Run only the specified workflow (mutex with `--pick`) |
|
|
6317
|
-
| `--job <name>` | none | Run only the specified job (and its dependencies) |
|
|
6318
|
-
| `--branch <name>` | detected | Override detected git branch |
|
|
6319
|
-
| `--sha <hash>` | detected | Override detected git SHA |
|
|
6320
|
-
| `--payload <path>` | none | Path to explicit event payload JSON file |
|
|
6321
|
-
| `--concurrency <n>` | CPU cores | Max parallel jobs **within one run** (job-level only). Cross-run [concurrency groups](https://docs.kici.dev/user/concurrency/) declared in `workflow({ concurrency: ... })` are enforced separately — see "Concurrency enforcement" below. |
|
|
6322
|
-
| `--keep-going` | `false` | Continue after job failure |
|
|
6323
|
-
| `--container` | `false` | Use Podman container isolation |
|
|
6324
|
-
| `--env <KEY=VALUE>` | none | Environment variable override (repeatable) |
|
|
6325
|
-
| `--input <KEY=VALUE>` | none | Typed workflow-dispatch input (repeatable) — coerced + validated against the workflow's `dispatch({ inputs })` schema, exposed as `ctx.dispatchInputs` (see [triggers → typed dispatch inputs](https://docs.kici.dev/user/sdk/triggers/#typed-dispatch-inputs)) |
|
|
6326
|
-
| `--files <path>` | git diff | Override changed file paths (repeatable, default: git diff) |
|
|
6327
|
-
| `--quiet` | `false` | Suppress streaming output (summary only) |
|
|
6328
|
-
| `--json` | `false` | Output structured JSON result |
|
|
6329
|
-
| `--junit <path>` | none | Output JUnit XML result to file |
|
|
6330
|
-
| `--debug` | `false` | Verbose internals |
|
|
6331
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
6332
|
-
| `--in-place` | `false` | Run against the real working directory instead of an isolated tmp checkout (see "Execution isolation" below) |
|
|
6333
|
-
| `--keep` | `false` | Always retain the isolated tmp checkout (default: keep only on failure) |
|
|
6334
|
-
| `--check` | `false` | Run in [check mode](https://docs.kici.dev/user/idempotent-steps/): each step reports drift instead of applying; the run still exits 0 |
|
|
6335
|
-
| `--fail-on-drift` | `false` | In check mode, exit non-zero if any step reports drift (no effect without `--check`) |
|
|
6264
|
+
Run a workflow on this machine as a real routed dispatch. `kici run <event> --local` compiles your workflows, matches triggers against the specified event, expands matrices, and executes the matched jobs — this machine joins as an ephemeral agent through the warm local dev plane. No orchestrator deployment is required.
|
|
6336
6265
|
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
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.
|
|
6266
|
+
`kici run local` (the old direct-execution subcommand) is retired: every run is now a real routed dispatch. Invoking `kici run local <event>` prints a hint pointing at `kici run <event> --local` and exits without running.
|
|
6340
6267
|
|
|
6341
6268
|
```bash
|
|
6342
|
-
|
|
6343
|
-
kici run local --pick
|
|
6344
|
-
|
|
6345
|
-
# Scope the picker to a trigger family (e.g. only workflows that react to pr:*)
|
|
6346
|
-
kici run local pr:open --pick
|
|
6269
|
+
kici run [event] --local [options]
|
|
6347
6270
|
```
|
|
6348
6271
|
|
|
6349
|
-
Rules:
|
|
6350
|
-
|
|
6351
|
-
- `--pick` is mutually exclusive with `--workflow`. Passing both exits with code 2.
|
|
6352
|
-
- 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.
|
|
6353
|
-
- 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).
|
|
6354
|
-
|
|
6355
6272
|
**Concurrency enforcement:**
|
|
6356
6273
|
|
|
6357
|
-
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:
|
|
6274
|
+
When the workflow declares a `concurrency` block, `kici run <event> --local` enforces it across concurrent local invocations on the same machine and user account. The behavior mirrors the orchestrator:
|
|
6358
6275
|
|
|
6359
6276
|
- 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.
|
|
6360
6277
|
- `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.
|
|
@@ -6368,7 +6285,7 @@ The `SIGTERM`-to-`SIGKILL` grace window defaults to 30 000 ms. Override it with
|
|
|
6368
6285
|
|
|
6369
6286
|
**Execution isolation:**
|
|
6370
6287
|
|
|
6371
|
-
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.
|
|
6288
|
+
By default, `kici run <event> --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.
|
|
6372
6289
|
|
|
6373
6290
|
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`.
|
|
6374
6291
|
|
|
@@ -6378,8 +6295,7 @@ Cleanup policy:
|
|
|
6378
6295
|
|
|
6379
6296
|
- On a fully successful run, the isolated checkout is removed.
|
|
6380
6297
|
- On failure, it is retained and its path is logged so you can inspect the failed state.
|
|
6381
|
-
-
|
|
6382
|
-
- Retained checkouts are garbage-collected after 72 hours by the next `kici run local` invocation — copy a checkout elsewhere if you need it longer.
|
|
6298
|
+
- Retained checkouts are garbage-collected after 72 hours by the next `kici run <event> --local` invocation — copy a checkout elsewhere if you need it longer.
|
|
6383
6299
|
|
|
6384
6300
|
Set the `KICI_RUN_DIR` environment variable to place the isolated checkout under a base directory other than the system temp directory.
|
|
6385
6301
|
|
|
@@ -6390,32 +6306,23 @@ Pass `--in-place` to run against the real working directory instead — useful w
|
|
|
6390
6306
|
**Examples:**
|
|
6391
6307
|
|
|
6392
6308
|
```bash
|
|
6393
|
-
# Run workflows matching a push event
|
|
6394
|
-
kici run local
|
|
6309
|
+
# Run workflows matching a push event on this machine
|
|
6310
|
+
kici run push --local
|
|
6395
6311
|
|
|
6396
|
-
# Run
|
|
6397
|
-
kici run
|
|
6312
|
+
# Run a pull-request-open workflow locally
|
|
6313
|
+
kici run pr:open --local
|
|
6398
6314
|
|
|
6399
|
-
#
|
|
6400
|
-
kici run
|
|
6401
|
-
|
|
6402
|
-
# JSON output for CI scripting
|
|
6403
|
-
kici run local push --json
|
|
6404
|
-
|
|
6405
|
-
# JUnit XML for CI integration
|
|
6406
|
-
kici run local push --junit results.xml
|
|
6407
|
-
|
|
6408
|
-
# Quiet mode (summary only, no streaming)
|
|
6409
|
-
kici run local push --quiet
|
|
6315
|
+
# Reuse the working tree instead of an isolated clone
|
|
6316
|
+
kici run push --local --in-place
|
|
6410
6317
|
|
|
6411
|
-
#
|
|
6412
|
-
kici run
|
|
6318
|
+
# Force the throwaway/offline plane
|
|
6319
|
+
kici run push --local --offline
|
|
6413
6320
|
|
|
6414
6321
|
# Environment variable overrides
|
|
6415
|
-
kici run
|
|
6322
|
+
kici run push --local --env NODE_ENV=test --env CI=true
|
|
6416
6323
|
|
|
6417
|
-
#
|
|
6418
|
-
kici run
|
|
6324
|
+
# Quiet mode (summary only, no streaming)
|
|
6325
|
+
kici run push --local --quiet
|
|
6419
6326
|
```
|
|
6420
6327
|
|
|
6421
6328
|
**Exit codes:**
|
|
@@ -6425,20 +6332,13 @@ kici run local push --keep-going
|
|
|
6425
6332
|
| 0 | All workflows succeeded |
|
|
6426
6333
|
| 1 | One or more jobs failed |
|
|
6427
6334
|
|
|
6428
|
-
**Output formats:**
|
|
6429
|
-
|
|
6430
|
-
- **Default:** Streaming job output during execution, followed by a tree-format summary with per-step timing
|
|
6431
|
-
- **`--json`:** Structured JSON with workflows, jobs, steps, timing, and matrix values
|
|
6432
|
-
- **`--junit <path>`:** Standard JUnit XML for CI integration (Jenkins, GitLab, etc.)
|
|
6433
|
-
- **`--quiet`:** Summary only, no streaming output during execution
|
|
6434
|
-
|
|
6435
6335
|
#### kici run remote
|
|
6436
6336
|
|
|
6437
6337
|
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.
|
|
6438
6338
|
|
|
6439
6339
|
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](https://docs.kici.dev/user/cli-reference/#how-the-run-is-routed) and [The two planes](https://docs.kici.dev/user/cli-reference/#the-two-planes) below.
|
|
6440
6340
|
|
|
6441
|
-
Like `kici run local`, `kici run remote` recompiles your workflows (`.kici/workflows` → `kici.lock.json`) before dispatching, so the orchestrator matches and dispatches against your current workflow definitions — a brand-new or edited workflow takes effect without a separate `kici compile`. A compile or validation error aborts the run before anything is uploaded.
|
|
6341
|
+
Like `kici run <event> --local`, `kici run remote` recompiles your workflows (`.kici/workflows` → `kici.lock.json`) before dispatching, so the orchestrator matches and dispatches against your current workflow definitions — a brand-new or edited workflow takes effect without a separate `kici compile`. A compile or validation error aborts the run before anything is uploaded.
|
|
6442
6342
|
|
|
6443
6343
|
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](https://docs.kici.dev/user/testing-guide/) and [Storage layout](https://docs.kici.dev/operator/orchestrator/storage-layout/) for setup.
|
|
6444
6344
|
|
|
@@ -6446,39 +6346,6 @@ The orchestrator must have **cache storage configured** (`KICI_STORAGE_TYPE` = `
|
|
|
6446
6346
|
kici run remote [fixture] [options]
|
|
6447
6347
|
```
|
|
6448
6348
|
|
|
6449
|
-
**Arguments:**
|
|
6450
|
-
|
|
6451
|
-
| Argument | Required | Description |
|
|
6452
|
-
| --------- | -------- | ----------------------------------------------- |
|
|
6453
|
-
| `fixture` | no | Fixture name or glob pattern (omit to list all) |
|
|
6454
|
-
|
|
6455
|
-
**Options:**
|
|
6456
|
-
|
|
6457
|
-
| Option | Default | Description |
|
|
6458
|
-
| --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
6459
|
-
| `--org <id>` | active | Target organization for this run (overrides `kici org use`) |
|
|
6460
|
-
| `--orchestrator <name>` | default | Target orchestrator cluster within the org (overrides the per-org default) |
|
|
6461
|
-
| `--all` | `false` | Run all fixtures |
|
|
6462
|
-
| `-p, --pick` | `false` | Interactively pick fixtures to run (multi-select; mutex with a fixture arg, `--all`, and `--workflow`) |
|
|
6463
|
-
| `--workflow <name>` | none | Run a specific workflow directly (bypass triggers) |
|
|
6464
|
-
| `--parallel` | `false` | Run multiple fixtures concurrently |
|
|
6465
|
-
| `--no-wait` | - | Fire and forget (print runIds, don't stream) |
|
|
6466
|
-
| `--quiet` | `false` | Minimal output (only final result) |
|
|
6467
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6468
|
-
| `--junit <path>` | none | JUnit XML output to file for CI integration |
|
|
6469
|
-
| `--history` | `false` | Show table of recent test runs |
|
|
6470
|
-
| `--context <ctx.key=value>` | none | Inject a namespaced context secret, uploaded encrypted (repeatable) |
|
|
6471
|
-
| `--env <KEY=VALUE>` | none | Provide a per-run secret, uploaded encrypted (repeatable) — see [testing guide](https://docs.kici.dev/user/testing-guide/) |
|
|
6472
|
-
| `--input <KEY=VALUE>` | none | Typed workflow-dispatch input (repeatable) — validated + coerced + defaulted on the orchestrator from the lock descriptor, exposed as `ctx.dispatchInputs` (see [triggers → typed dispatch inputs](https://docs.kici.dev/user/sdk/triggers/#typed-dispatch-inputs)) |
|
|
6473
|
-
| `--target <selector>` | none | Narrow `runsOnAll` jobs to hosts matching this label selector (repeatable, AND-combined) |
|
|
6474
|
-
| `--target-allow-empty` | `false` | A `--target` that narrows a `runsOnAll` job to zero hosts skips it instead of failing |
|
|
6475
|
-
| `--debug` | `false` | Verbose internals |
|
|
6476
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
6477
|
-
| `--routing-key <key>` | none | Override the routing key for this run (advanced; selecting the org normally suffices — see [How the run is routed](https://docs.kici.dev/user/cli-reference/#how-the-run-is-routed)) |
|
|
6478
|
-
| `--check` | `false` | Run in [check mode](https://docs.kici.dev/user/idempotent-steps/): each step reports drift instead of applying |
|
|
6479
|
-
| `--fail-on-drift` | `false` | In check mode, fail the run if any step reports drift (no effect without `--check`) |
|
|
6480
|
-
| `--approve-all, --yes` | `false` | Auto-approve every [approval gate](https://docs.kici.dev/user/approvals/) this run holds on (run-scoped; eligibility still enforced) |
|
|
6481
|
-
|
|
6482
6349
|
`--approve-all` works in `--json` / `--quiet` mode: the run still auto-approves each gate it holds on, and the auto-approve diagnostics are written to stderr so stdout stays a pure JSON (or summary-only) payload. Without `--approve-all`, a `--json` / `--quiet` run that hits a gate stays held and prints a one-line "run held; approve via the dashboard or `kici approve <run-id>`" notice to stderr per hold.
|
|
6483
6350
|
|
|
6484
6351
|
**Examples:**
|
|
@@ -6600,7 +6467,7 @@ When an org has more than one connected orchestrator cluster, the CLI picks the
|
|
|
6600
6467
|
- **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.
|
|
6601
6468
|
- **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](https://docs.kici.dev/operator/orchestrator/storage-layout/).
|
|
6602
6469
|
|
|
6603
|
-
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`](https://docs.kici.dev/user/cli-reference/#kici-run-local).
|
|
6470
|
+
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 <event> --local`](https://docs.kici.dev/user/cli-reference/#kici-run-event---local).
|
|
6604
6471
|
|
|
6605
6472
|
#### Fresh repos (no GitHub remote)
|
|
6606
6473
|
|
|
@@ -6653,26 +6520,6 @@ Preview which workflows match a trigger event (dry-run, no execution). Useful fo
|
|
|
6653
6520
|
kici preview [event] [options]
|
|
6654
6521
|
```
|
|
6655
6522
|
|
|
6656
|
-
**Arguments:**
|
|
6657
|
-
|
|
6658
|
-
| Argument | Required | Description |
|
|
6659
|
-
| -------- | -------- | ----------------------------------------------------------- |
|
|
6660
|
-
| `event` | no | Event type to preview (e.g., `push`, `pr:open`, `schedule`) |
|
|
6661
|
-
|
|
6662
|
-
**Options:**
|
|
6663
|
-
|
|
6664
|
-
| Option | Default | Description |
|
|
6665
|
-
| --------------------------- | ------- | ------------------------------------------------------------ |
|
|
6666
|
-
| `--workflow <name>` | none | Filter to specific workflow |
|
|
6667
|
-
| `--job <name>` | none | Filter to specific job |
|
|
6668
|
-
| `--branch <name>` | `main` | Override target branch for trigger matching |
|
|
6669
|
-
| `--sha <hash>` | none | Override commit SHA |
|
|
6670
|
-
| `--files <path>` | none | Simulate changed file path for trigger matching (repeatable) |
|
|
6671
|
-
| `--secret <key=value>` | none | Inject flat secret (repeatable) |
|
|
6672
|
-
| `--context <ctx.key=value>` | none | Inject context secret (repeatable) |
|
|
6673
|
-
| `--debug` | `false` | Verbose internals |
|
|
6674
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
6675
|
-
|
|
6676
6523
|
**Examples:**
|
|
6677
6524
|
|
|
6678
6525
|
```bash
|
|
@@ -6699,7 +6546,7 @@ kici preview push --files src/index.ts --files README.md
|
|
|
6699
6546
|
| 0 | Preview completed (including zero matches) |
|
|
6700
6547
|
| 1 | Error |
|
|
6701
6548
|
|
|
6702
|
-
**Migration from the old `test` command:** The dry-run preview command was renamed from `test` to `preview`. If you were using the old `test` command with a fixture name for remote fixture execution, use `kici run remote <fixture-name>` instead. For local workflow execution, use `kici run
|
|
6549
|
+
**Migration from the old `test` command:** The dry-run preview command was renamed from `test` to `preview`. If you were using the old `test` command with a fixture name for remote fixture execution, use `kici run remote <fixture-name>` instead. For local workflow execution, use `kici run <event> --local`.
|
|
6703
6550
|
|
|
6704
6551
|
### kici login
|
|
6705
6552
|
|
|
@@ -6715,16 +6562,6 @@ After OAuth, the CLI exchanges the OIDC token for a personal access token (PAT)
|
|
|
6715
6562
|
kici login [options]
|
|
6716
6563
|
```
|
|
6717
6564
|
|
|
6718
|
-
**Options:**
|
|
6719
|
-
|
|
6720
|
-
| Option | Default | Description |
|
|
6721
|
-
| --------------------------- | ------- | --------------------------------------------------- |
|
|
6722
|
-
| `--token <key>` | none | API key for direct authentication (legacy) |
|
|
6723
|
-
| `--device` | false | Force device authorization flow (headless/SSH) |
|
|
6724
|
-
| `--platform-endpoint <url>` | none | Platform relay URL |
|
|
6725
|
-
| `--oidc-issuer <url>` | none | OIDC issuer URL (selects a non-default environment) |
|
|
6726
|
-
| `--routing-key <key>` | none | Routing key for webhook source identification |
|
|
6727
|
-
|
|
6728
6565
|
**Environment variables:**
|
|
6729
6566
|
|
|
6730
6567
|
| Variable | Default | Description |
|
|
@@ -6810,12 +6647,6 @@ Switch the active organization by name (case-insensitive) or ID.
|
|
|
6810
6647
|
kici org use <name>
|
|
6811
6648
|
```
|
|
6812
6649
|
|
|
6813
|
-
**Arguments:**
|
|
6814
|
-
|
|
6815
|
-
| Argument | Required | Description |
|
|
6816
|
-
| -------- | -------- | ----------------------- |
|
|
6817
|
-
| `name` | yes | Organization name or ID |
|
|
6818
|
-
|
|
6819
6650
|
**Examples:**
|
|
6820
6651
|
|
|
6821
6652
|
```bash
|
|
@@ -6851,14 +6682,6 @@ concurrency, and heartbeat age.
|
|
|
6851
6682
|
kici diagnostics [options]
|
|
6852
6683
|
```
|
|
6853
6684
|
|
|
6854
|
-
**Options:**
|
|
6855
|
-
|
|
6856
|
-
| Option | Default | Description |
|
|
6857
|
-
| --------------------- | ------- | --------------------------------------------------- |
|
|
6858
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6859
|
-
| `--verbose` | `false` | Show extended per-agent fields (host, node, memory) |
|
|
6860
|
-
| `--orchestrator <id>` | all | Scope the tree to one orchestrator connection id |
|
|
6861
|
-
|
|
6862
6685
|
**Examples:**
|
|
6863
6686
|
|
|
6864
6687
|
```bash
|
|
@@ -6891,20 +6714,6 @@ branch, trigger, started, duration); pagination is reported at the bottom.
|
|
|
6891
6714
|
kici runs list [options]
|
|
6892
6715
|
```
|
|
6893
6716
|
|
|
6894
|
-
**Options:**
|
|
6895
|
-
|
|
6896
|
-
| Option | Default | Description |
|
|
6897
|
-
| ----------------------- | ------- | --------------------------------------------- |
|
|
6898
|
-
| `--status <s>` | all | Filter by run status |
|
|
6899
|
-
| `--workflow <w>` | all | Filter by workflow name |
|
|
6900
|
-
| `--branch <b>` | all | Filter by branch/ref |
|
|
6901
|
-
| `--repo <r>` | all | Filter by repository |
|
|
6902
|
-
| `--trigger <t>` | all | Filter by trigger type |
|
|
6903
|
-
| `--source <routingKey>` | all | Filter by source routing key |
|
|
6904
|
-
| `--since <ts>` | none | Only runs since this ISO-8601 or epoch ms |
|
|
6905
|
-
| `--page <n>` | `1` | Page number (server page size is fixed at 20) |
|
|
6906
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6907
|
-
|
|
6908
6717
|
```bash
|
|
6909
6718
|
kici runs list
|
|
6910
6719
|
kici runs list --status running
|
|
@@ -6916,16 +6725,12 @@ kici runs list --json | jq '.runs[].runId'
|
|
|
6916
6725
|
|
|
6917
6726
|
Show a run's summary header plus its jobs-and-steps tree (name, status,
|
|
6918
6727
|
duration, exit code). If the run id is not on the Platform but exists in your
|
|
6919
|
-
local run history (from `kici run local`), the local record is shown instead.
|
|
6728
|
+
local run history (from `kici run <event> --local`), the local record is shown instead.
|
|
6920
6729
|
|
|
6921
6730
|
```bash
|
|
6922
6731
|
kici runs show <run-id> [options]
|
|
6923
6732
|
```
|
|
6924
6733
|
|
|
6925
|
-
| Option | Default | Description |
|
|
6926
|
-
| -------- | ------- | ---------------------------- |
|
|
6927
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6928
|
-
|
|
6929
6734
|
```bash
|
|
6930
6735
|
kici runs show abc123
|
|
6931
6736
|
kici runs show abc123 --json
|
|
@@ -6939,12 +6744,6 @@ Print each job/step's log lines in order, with headers.
|
|
|
6939
6744
|
kici runs logs <run-id> [options]
|
|
6940
6745
|
```
|
|
6941
6746
|
|
|
6942
|
-
| Option | Default | Description |
|
|
6943
|
-
| -------------- | ------- | -------------------------------------- |
|
|
6944
|
-
| `--job <name>` | all | Only print logs for this job |
|
|
6945
|
-
| `-f, --follow` | `false` | Tail logs for a live run until it ends |
|
|
6946
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6947
|
-
|
|
6948
6747
|
```bash
|
|
6949
6748
|
kici runs logs abc123
|
|
6950
6749
|
kici runs logs abc123 --job build
|
|
@@ -6960,10 +6759,6 @@ cooldown between reruns of the same run.
|
|
|
6960
6759
|
kici runs rerun <run-id> [options]
|
|
6961
6760
|
```
|
|
6962
6761
|
|
|
6963
|
-
| Option | Default | Description |
|
|
6964
|
-
| -------- | ------- | ---------------------------- |
|
|
6965
|
-
| `--json` | `false` | Machine-readable JSON output |
|
|
6966
|
-
|
|
6967
6762
|
```bash
|
|
6968
6763
|
kici runs rerun abc123
|
|
6969
6764
|
```
|
|
@@ -6976,15 +6771,6 @@ Cancel a single run, or all in-progress runs on a branch.
|
|
|
6976
6771
|
kici runs cancel [run-id] [options]
|
|
6977
6772
|
```
|
|
6978
6773
|
|
|
6979
|
-
| Argument | Required | Description |
|
|
6980
|
-
| -------- | -------- | ---------------- |
|
|
6981
|
-
| `run-id` | no | Run ID to cancel |
|
|
6982
|
-
|
|
6983
|
-
| Option | Default | Description |
|
|
6984
|
-
| ----------------- | ------- | ------------------------------------------- |
|
|
6985
|
-
| `--force` | `false` | Force cancel (kill immediately, skip hooks) |
|
|
6986
|
-
| `--branch <name>` | none | Cancel all in-progress runs on this branch |
|
|
6987
|
-
|
|
6988
6774
|
```bash
|
|
6989
6775
|
kici runs cancel abc123
|
|
6990
6776
|
kici runs cancel abc123 --force
|
|
@@ -7005,19 +6791,6 @@ Approve a held [approval gate](https://docs.kici.dev/user/approvals/) so the run
|
|
|
7005
6791
|
kici approve <run-id> [options]
|
|
7006
6792
|
```
|
|
7007
6793
|
|
|
7008
|
-
**Arguments:**
|
|
7009
|
-
|
|
7010
|
-
| Argument | Required | Description |
|
|
7011
|
-
| -------- | -------- | ---------------------------------- |
|
|
7012
|
-
| `run-id` | yes | Run ID holding the gate to approve |
|
|
7013
|
-
|
|
7014
|
-
**Options:**
|
|
7015
|
-
|
|
7016
|
-
| Option | Default | Description |
|
|
7017
|
-
| ---------------- | ------- | ---------------------------------------------------- |
|
|
7018
|
-
| `--job <name>` | none | Approve a held job (omit for a workflow-level hold) |
|
|
7019
|
-
| `--step <index>` | none | Approve a held step by its index (used with `--job`) |
|
|
7020
|
-
|
|
7021
6794
|
**Examples:**
|
|
7022
6795
|
|
|
7023
6796
|
```bash
|
|
@@ -7031,7 +6804,7 @@ kici approve abc123 --job deploy-production
|
|
|
7031
6804
|
kici approve abc123 --job migrate-and-deploy --step 1
|
|
7032
6805
|
```
|
|
7033
6806
|
|
|
7034
|
-
You must be eligible for at least one unsatisfied clause (a member of a named team, or a named user) and hold the `
|
|
6807
|
+
You must be eligible for at least one unsatisfied clause (a member of a named team, or a named user) and hold the `contexts:write` or `ci_trust:write` permission. The command reports whether the element was released, how many clauses remain, or that it was rejected.
|
|
7035
6808
|
|
|
7036
6809
|
### kici reject
|
|
7037
6810
|
|
|
@@ -7041,20 +6814,6 @@ Reject a held [approval gate](https://docs.kici.dev/user/approvals/). A rejectio
|
|
|
7041
6814
|
kici reject <run-id> --reason <text> [options]
|
|
7042
6815
|
```
|
|
7043
6816
|
|
|
7044
|
-
**Arguments:**
|
|
7045
|
-
|
|
7046
|
-
| Argument | Required | Description |
|
|
7047
|
-
| -------- | -------- | --------------------------------- |
|
|
7048
|
-
| `run-id` | yes | Run ID holding the gate to reject |
|
|
7049
|
-
|
|
7050
|
-
**Options:**
|
|
7051
|
-
|
|
7052
|
-
| Option | Default | Description |
|
|
7053
|
-
| ----------------- | ------- | --------------------------------------------------- |
|
|
7054
|
-
| `--reason <text>` | none | Required. Reason recorded with the rejection |
|
|
7055
|
-
| `--job <name>` | none | Reject a held job (omit for a workflow-level hold) |
|
|
7056
|
-
| `--step <index>` | none | Reject a held step by its index (used with `--job`) |
|
|
7057
|
-
|
|
7058
6817
|
**Examples:**
|
|
7059
6818
|
|
|
7060
6819
|
```bash
|
|
@@ -7070,7 +6829,7 @@ List secret contexts available for test runs. Shows context names and key names
|
|
|
7070
6829
|
kici secrets list
|
|
7071
6830
|
```
|
|
7072
6831
|
|
|
7073
|
-
Each
|
|
6832
|
+
Each context corresponds to a context configured on the orchestrator. The output lists every context whose `allowLocalExecution` flag is `true` (the gate that lets CLI-initiated test runs resolve secrets through that context), along with the secret key names reachable from the context's bound scopes.
|
|
7074
6833
|
|
|
7075
6834
|
Only key names are shown — secret values are never returned over this endpoint.
|
|
7076
6835
|
|
|
@@ -7099,18 +6858,12 @@ See [Drive KiCI from your coding agent](https://docs.kici.dev/user/ai-agents/) f
|
|
|
7099
6858
|
|
|
7100
6859
|
### kici types
|
|
7101
6860
|
|
|
7102
|
-
Generate TypeScript declaration files from orchestrator environment metadata. The generated `.d.ts` file augments the SDK's `KnownSecretKeys` and `
|
|
6861
|
+
Generate TypeScript declaration files from orchestrator environment metadata. The generated `.d.ts` file augments the SDK's `KnownSecretKeys` and `ContextSecrets` interfaces, providing compile-time autocomplete and type checking for secret key names.
|
|
7103
6862
|
|
|
7104
6863
|
```bash
|
|
7105
6864
|
kici types [options]
|
|
7106
6865
|
```
|
|
7107
6866
|
|
|
7108
|
-
**Options:**
|
|
7109
|
-
|
|
7110
|
-
| Option | Default | Description |
|
|
7111
|
-
| ------------------- | ------- | ----------------------- |
|
|
7112
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7113
|
-
|
|
7114
6867
|
**Prerequisites:** Must be authenticated via `kici login`.
|
|
7115
6868
|
|
|
7116
6869
|
**Output:** `.kici/types/secrets.d.ts`
|
|
@@ -7128,7 +6881,7 @@ kici types --kici-dir packages/app/.kici
|
|
|
7128
6881
|
**How it works:**
|
|
7129
6882
|
|
|
7130
6883
|
1. Fetches all environment metadata (environment names and secret key names) from the orchestrator
|
|
7131
|
-
2. Generates a `.d.ts` file that augments `@kici-dev/sdk`'s `KnownSecretKeys` and `
|
|
6884
|
+
2. Generates a `.d.ts` file that augments `@kici-dev/sdk`'s `KnownSecretKeys` and `ContextSecrets` interfaces
|
|
7132
6885
|
3. Writes the file to `.kici/types/secrets.d.ts`
|
|
7133
6886
|
|
|
7134
6887
|
After generating types, `ctx.secrets.get('MY_KEY')` and `ctx.secrets.expose('DB_HOST')` gain autocomplete and type checking in your IDE.
|
|
@@ -7147,20 +6900,8 @@ Generate a fixture template for an event type. Useful for creating custom test p
|
|
|
7147
6900
|
kici fixture <event> [options]
|
|
7148
6901
|
```
|
|
7149
6902
|
|
|
7150
|
-
**Arguments:**
|
|
7151
|
-
|
|
7152
|
-
| Argument | Required | Description |
|
|
7153
|
-
| -------- | -------- | ----------------------------- |
|
|
7154
|
-
| `event` | yes | Event to generate fixture for |
|
|
7155
|
-
|
|
7156
6903
|
**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>`.
|
|
7157
6904
|
|
|
7158
|
-
**Options:**
|
|
7159
|
-
|
|
7160
|
-
| Option | Default | Description |
|
|
7161
|
-
| ----------------- | ------- | ------------------------------- |
|
|
7162
|
-
| `--output <path>` | stdout | Write to file instead of stdout |
|
|
7163
|
-
|
|
7164
6905
|
**Examples:**
|
|
7165
6906
|
|
|
7166
6907
|
```bash
|
|
@@ -7189,19 +6930,6 @@ Initialize a `.kici/` directory with default workflow templates.
|
|
|
7189
6930
|
kici init [options]
|
|
7190
6931
|
```
|
|
7191
6932
|
|
|
7192
|
-
**Options:**
|
|
7193
|
-
|
|
7194
|
-
| Option | Default | Description |
|
|
7195
|
-
| ------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
7196
|
-
| `--force` | `false` | Overwrite existing `.kici/` directory |
|
|
7197
|
-
| `--skip-install` | `false` | Create files without installing dependencies |
|
|
7198
|
-
| `--package-manager <npm\|pnpm\|yarn>` | auto-detect | Force a package manager for the install step (default: detect from your repo) |
|
|
7199
|
-
| `--mjs` | `false` | JavaScript-only mode (no TypeScript, no deps) |
|
|
7200
|
-
| `--no-agents-md` | writes `AGENTS.md` | Skip writing `.kici/AGENTS.md` (the LLM authoring context file) |
|
|
7201
|
-
| `--private-registry <url>` | none | Scaffold a workflow `registries:` entry pointing at `<url>` (e.g. CodeArtifact, GH Packages, Verdaccio) |
|
|
7202
|
-
| `--private-registry-scope <scope>` | none | Optional npm package scope (e.g. `@my-org`) for the private registry |
|
|
7203
|
-
| `--private-registry-secret <ref>` | `production:NPM_TOKEN` | Qualified secret reference (`env:NAME`) the private registry token comes from |
|
|
7204
|
-
|
|
7205
6933
|
**Examples:**
|
|
7206
6934
|
|
|
7207
6935
|
```bash
|
|
@@ -7261,12 +6989,6 @@ Install a pre-commit hook that runs `kici compile` before each commit.
|
|
|
7261
6989
|
kici hook install [options]
|
|
7262
6990
|
```
|
|
7263
6991
|
|
|
7264
|
-
**Options:**
|
|
7265
|
-
|
|
7266
|
-
| Option | Default | Description |
|
|
7267
|
-
| ------- | ------- | ------------------------------------------ |
|
|
7268
|
-
| `--git` | `false` | Use raw git hook (`.git/hooks/pre-commit`) |
|
|
7269
|
-
|
|
7270
6992
|
**Examples:**
|
|
7271
6993
|
|
|
7272
6994
|
```bash
|
|
@@ -7293,12 +7015,6 @@ List all webhook entrypoints for the current project. Reads the compiled lock fi
|
|
|
7293
7015
|
kici endpoints [options]
|
|
7294
7016
|
```
|
|
7295
7017
|
|
|
7296
|
-
**Options:**
|
|
7297
|
-
|
|
7298
|
-
| Option | Default | Description |
|
|
7299
|
-
| ------------------- | ------- | ----------------------- |
|
|
7300
|
-
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7301
|
-
|
|
7302
7018
|
**Prerequisites:** Run `kici compile` first to generate the lock file.
|
|
7303
7019
|
|
|
7304
7020
|
**Examples:**
|
|
@@ -7319,15 +7035,6 @@ List permanently registered workflows on the orchestrator.
|
|
|
7319
7035
|
kici workflows list [options]
|
|
7320
7036
|
```
|
|
7321
7037
|
|
|
7322
|
-
**Options:**
|
|
7323
|
-
|
|
7324
|
-
| Option | Default | Description |
|
|
7325
|
-
| ----------------------- | ------- | ---------------------------------------------- |
|
|
7326
|
-
| `--json` | `false` | Output as JSON |
|
|
7327
|
-
| `--stale <duration>` | none | Filter stale registrations (e.g., `30d`, `7d`) |
|
|
7328
|
-
| `--trigger-type <type>` | none | Filter by trigger type |
|
|
7329
|
-
| `--repo <repo>` | none | Filter by repository |
|
|
7330
|
-
|
|
7331
7038
|
**Examples:**
|
|
7332
7039
|
|
|
7333
7040
|
```bash
|
|
@@ -7387,12 +7094,6 @@ Trigger graceful drain on a worker instance. Sends a POST request to the worker'
|
|
|
7387
7094
|
kici admin drain-worker [options]
|
|
7388
7095
|
```
|
|
7389
7096
|
|
|
7390
|
-
**Options:**
|
|
7391
|
-
|
|
7392
|
-
| Option | Required | Description |
|
|
7393
|
-
| ------------- | -------- | --------------------------------------------- |
|
|
7394
|
-
| `--url <url>` | yes | Worker URL (e.g., `http://worker-host:10143`) |
|
|
7395
|
-
|
|
7396
7097
|
**Examples:**
|
|
7397
7098
|
|
|
7398
7099
|
```bash
|
|
@@ -7420,21 +7121,6 @@ On success the output prints the **origin org** (the customer's public org id
|
|
|
7420
7121
|
kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-file>] [options]
|
|
7421
7122
|
```
|
|
7422
7123
|
|
|
7423
|
-
**Arguments:**
|
|
7424
|
-
|
|
7425
|
-
| Argument | Required | Description |
|
|
7426
|
-
| ------------ | -------- | --------------------------------------------------------------------- |
|
|
7427
|
-
| `[artifact]` | no | Artifact path to digest-check against the attestation subject digest. |
|
|
7428
|
-
|
|
7429
|
-
**Options:**
|
|
7430
|
-
|
|
7431
|
-
| Option | Required | Description |
|
|
7432
|
-
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
7433
|
-
| `--bundle <path-or-url>` | yes | Path or `http(s)` URL to the attestation bundle JSON. |
|
|
7434
|
-
| `--trust-root <url-or-file>` | no | Trusted issuer (see below). Defaults to the hosted KiCI platform. The token issuer is pinned to it, never taken from the token. |
|
|
7435
|
-
| `--audience <aud>` | no | Expected token audience (defaults to the KiCI provenance audience). |
|
|
7436
|
-
| `--json` | no | Print the structured verification result as JSON instead of human-readable output. |
|
|
7437
|
-
|
|
7438
7124
|
**Trust root:** `--trust-root` defaults to the hosted KiCI platform's provenance issuer — the same platform you `kici login` against (see [Which trust root do I use?](https://docs.kici.dev/user/provenance/#which-trust-root-do-i-use)), so the common case needs no flag. The verifier never trusts the issuer named inside the token; supplying it out-of-band is what prevents a forged bundle from self-attesting. To override the default, pass `--trust-root` in one of two forms:
|
|
7439
7125
|
|
|
7440
7126
|
- **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`.
|
|
@@ -7490,194 +7176,816 @@ the authoritative anchor.
|
|
|
7490
7176
|
| 0 | Verified — signature, identity, build context (and digest, if checked) all pass |
|
|
7491
7177
|
| 1 | Not verified, or an error (missing `--bundle`, unreadable bundle, unreachable trust root) |
|
|
7492
7178
|
|
|
7493
|
-
##
|
|
7179
|
+
## Command reference
|
|
7494
7180
|
|
|
7495
|
-
The
|
|
7181
|
+
The exhaustive, always-current list of every `kici` command with its arguments and options, generated from the CLI's command tree so it never drifts from the shipped binary. The sections above add concepts and worked examples; the reference below is the authoritative signature list.
|
|
7496
7182
|
|
|
7497
|
-
|
|
7498
|
-
// .kici/workflows/ci.ts
|
|
7499
|
-
import { workflow, job, step, pr } from '@kici-dev/sdk';
|
|
7183
|
+
<!-- BEGIN GENERATED: kici-commands (do not edit; run the doc generator) -->
|
|
7500
7184
|
|
|
7501
|
-
|
|
7502
|
-
on: pr(),
|
|
7503
|
-
jobs: [
|
|
7504
|
-
/* ... */
|
|
7505
|
-
],
|
|
7506
|
-
});
|
|
7507
|
-
```
|
|
7185
|
+
### `kici admin`
|
|
7508
7186
|
|
|
7509
|
-
|
|
7187
|
+
Operator-facing commands for running instances
|
|
7510
7188
|
|
|
7511
|
-
|
|
7189
|
+
Synopsis: `kici admin`
|
|
7512
7190
|
|
|
7513
|
-
|
|
7191
|
+
### `kici admin drain-worker`
|
|
7514
7192
|
|
|
7515
|
-
|
|
7516
|
-
- Is used by the orchestrator to evaluate triggers without code checkout
|
|
7517
|
-
- Should be committed to version control
|
|
7518
|
-
- Is regenerated on every `kici compile` run
|
|
7193
|
+
Trigger graceful drain on a worker instance
|
|
7519
7194
|
|
|
7520
|
-
|
|
7195
|
+
Synopsis: `kici admin drain-worker [options]`
|
|
7521
7196
|
|
|
7522
|
-
|
|
7197
|
+
**Options**
|
|
7523
7198
|
|
|
7524
|
-
|
|
7199
|
+
| Option | Default | Description |
|
|
7200
|
+
| ------------- | ------- | -------------------------------------------- |
|
|
7201
|
+
| `--url <url>` | | Worker URL (e.g., http://worker-host:<port>) |
|
|
7525
7202
|
|
|
7526
|
-
|
|
7527
|
-
| ---- | -------------------- |
|
|
7528
|
-
| 0 | Success |
|
|
7529
|
-
| 1 | Failure (see output) |
|
|
7203
|
+
### `kici approve`
|
|
7530
7204
|
|
|
7531
|
-
|
|
7205
|
+
Approve a held approval gate for a run
|
|
7532
7206
|
|
|
7533
|
-
|
|
7207
|
+
Synopsis: `kici approve <run-id> [options]`
|
|
7534
7208
|
|
|
7535
|
-
|
|
7536
|
-
# Shows trigger matching, rule evaluation, decision traces
|
|
7537
|
-
kici run local push --debug
|
|
7209
|
+
**Arguments**
|
|
7538
7210
|
|
|
7539
|
-
|
|
7540
|
-
|
|
7211
|
+
| Argument | Required | Variadic | Description |
|
|
7212
|
+
| -------- | -------- | -------- | ------------------------------------- |
|
|
7213
|
+
| `run-id` | yes | no | Run ID whose approval gate to approve |
|
|
7541
7214
|
|
|
7542
|
-
|
|
7543
|
-
kici preview pr:open --debug
|
|
7544
|
-
```
|
|
7215
|
+
**Options**
|
|
7545
7216
|
|
|
7546
|
-
|
|
7217
|
+
| Option | Default | Description |
|
|
7218
|
+
| ---------------- | ------- | ------------------------------------------- |
|
|
7219
|
+
| `--job <name>` | | Approve the hold for a specific job |
|
|
7220
|
+
| `--step <index>` | | Approve a step-scoped hold (requires --job) |
|
|
7547
7221
|
|
|
7548
|
-
|
|
7222
|
+
### `kici compile`
|
|
7549
7223
|
|
|
7550
|
-
|
|
7551
|
-
| ------------ | ----------------------------------------- |
|
|
7552
|
-
| `KICI_DEV` | Set to `true` for development mode |
|
|
7553
|
-
| `KICI_DEBUG` | Set to `true` for verbose internal output |
|
|
7554
|
-
| `CI` | When `true`, disables interactive prompts |
|
|
7224
|
+
Compile workflows from .kici/workflows/ to kici.lock.json
|
|
7555
7225
|
|
|
7556
|
-
|
|
7226
|
+
Synopsis: `kici compile [options]`
|
|
7557
7227
|
|
|
7558
|
-
|
|
7559
|
-
- [Testing guide](https://docs.kici.dev/user/testing-guide/) -- writing fixtures, remote test runs, secret contexts, and repo state transfer
|
|
7560
|
-
- [SDK reference](https://docs.kici.dev/user/sdk-reference/) -- complete API for the workflow definitions that the CLI compiles
|
|
7561
|
-
- [Workflow patterns](https://docs.kici.dev/user/workflow-patterns/) -- example workflows to compile and test with these commands
|
|
7228
|
+
**Options**
|
|
7562
7229
|
|
|
7563
|
-
|
|
7230
|
+
| Option | Default | Description |
|
|
7231
|
+
| ------------------- | ------- | -------------------------------------------- |
|
|
7232
|
+
| `--check` | `false` | Validate workflows without writing lock file |
|
|
7233
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7234
|
+
| `--verbose` | `false` | Detailed output |
|
|
7235
|
+
| `--watch` | `false` | Watch for changes and recompile |
|
|
7564
7236
|
|
|
7565
|
-
|
|
7237
|
+
### `kici diagnostics`
|
|
7566
7238
|
|
|
7567
|
-
|
|
7239
|
+
Show orchestrators, scalers, and agents (mirrors the dashboard Diagnostics page)
|
|
7568
7240
|
|
|
7569
|
-
|
|
7241
|
+
Synopsis: `kici diagnostics [options]`
|
|
7570
7242
|
|
|
7571
|
-
|
|
7243
|
+
**Options**
|
|
7572
7244
|
|
|
7573
|
-
|
|
7245
|
+
| Option | Default | Description |
|
|
7246
|
+
| --------------------- | ------- | ----------------------------------- |
|
|
7247
|
+
| `--json` | `false` | Output raw JSON |
|
|
7248
|
+
| `--verbose` | `false` | Show extended per-agent fields |
|
|
7249
|
+
| `--orchestrator <id>` | | Scope the tree to one connection id |
|
|
7574
7250
|
|
|
7575
|
-
|
|
7576
|
-
| ------------ | ------------------------------------ | ------------------- |
|
|
7577
|
-
| `onCancel` | After step/job/workflow is cancelled | Step, Job, Workflow |
|
|
7578
|
-
| `cleanup` | Always (success, failure, or cancel) | Step, Job, Workflow |
|
|
7579
|
-
| `onSuccess` | After job/workflow succeeds | Job, Workflow |
|
|
7580
|
-
| `onFailure` | After job/workflow fails | Job, Workflow |
|
|
7581
|
-
| `beforeStep` | Before each step in a job | Job |
|
|
7582
|
-
| `afterStep` | After each step in a job | Job |
|
|
7251
|
+
### `kici docs`
|
|
7583
7252
|
|
|
7584
|
-
|
|
7253
|
+
Open the KiCI documentation site in the default browser
|
|
7585
7254
|
|
|
7586
|
-
|
|
7255
|
+
Synopsis: `kici docs [options]`
|
|
7587
7256
|
|
|
7588
|
-
|
|
7589
|
-
import { workflow, job, step, push } from '@kici-dev/sdk';
|
|
7257
|
+
**Options**
|
|
7590
7258
|
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
job('deploy-prod', {
|
|
7595
|
-
runsOn: 'linux',
|
|
7596
|
-
steps: [
|
|
7597
|
-
step('deploy', async ({ $ }) => {
|
|
7598
|
-
await $`kubectl apply -f manifests/`;
|
|
7599
|
-
}),
|
|
7600
|
-
],
|
|
7601
|
-
onCancel: async (ctx) => {
|
|
7602
|
-
console.log(`Deploy cancelled: ${ctx.outcome.reason}`);
|
|
7603
|
-
await ctx.$`kubectl rollout undo deployment/app`;
|
|
7604
|
-
},
|
|
7605
|
-
cleanup: async (ctx) => {
|
|
7606
|
-
// Always runs -- release lock, notify team, etc.
|
|
7607
|
-
await ctx.$`curl -X POST https://slack.com/webhook -d '{"text": "Deploy ${ctx.outcome.status}"}'`;
|
|
7608
|
-
},
|
|
7609
|
-
onSuccess: async (ctx) => {
|
|
7610
|
-
console.log(`Deploy succeeded in ${ctx.outcome.duration}ms`);
|
|
7611
|
-
},
|
|
7612
|
-
onFailure: async (ctx) => {
|
|
7613
|
-
console.log(`Deploy failed at step: ${ctx.outcome.failedStep}`);
|
|
7614
|
-
},
|
|
7615
|
-
gracePeriod: 60, // 60 seconds before SIGKILL on cancel
|
|
7616
|
-
}),
|
|
7617
|
-
],
|
|
7618
|
-
});
|
|
7619
|
-
```
|
|
7259
|
+
| Option | Default | Description |
|
|
7260
|
+
| ----------- | ------- | ----------------------------------------------- |
|
|
7261
|
+
| `--no-open` | | Print the docs URL instead of opening a browser |
|
|
7620
7262
|
|
|
7621
|
-
###
|
|
7263
|
+
### `kici docs llm`
|
|
7622
7264
|
|
|
7623
|
-
|
|
7624
|
-
step('download-artifacts', {
|
|
7625
|
-
run: async ({ $ }) => {
|
|
7626
|
-
await $`wget https://artifacts.example.com/build.tar.gz`;
|
|
7627
|
-
},
|
|
7628
|
-
onCancel: async (ctx) => {
|
|
7629
|
-
// Clean up partial downloads
|
|
7630
|
-
await ctx.$`rm -f build.tar.gz`;
|
|
7631
|
-
},
|
|
7632
|
-
cleanup: async (ctx) => {
|
|
7633
|
-
await ctx.$`rm -rf /tmp/staging`;
|
|
7634
|
-
},
|
|
7635
|
-
});
|
|
7636
|
-
```
|
|
7265
|
+
Print KiCI LLM docs bundles. No topic prints the llms.txt index; <topic> prints a task bundle (e.g. sdk, cli, patterns, features, providers, architecture, getting-started); "full" prints the complete bundle.
|
|
7637
7266
|
|
|
7638
|
-
|
|
7267
|
+
Synopsis: `kici docs llm [topic] [options]`
|
|
7639
7268
|
|
|
7640
|
-
|
|
7641
|
-
workflow('ci', {
|
|
7642
|
-
on: push({ branches: ['main'] }),
|
|
7643
|
-
jobs: [
|
|
7644
|
-
/* ... */
|
|
7645
|
-
],
|
|
7646
|
-
onCancel: async (ctx) => {
|
|
7647
|
-
// Notify when any job in the workflow is cancelled
|
|
7648
|
-
console.log('CI workflow cancelled');
|
|
7649
|
-
},
|
|
7650
|
-
cleanup: async (ctx) => {
|
|
7651
|
-
// Always runs after all jobs complete
|
|
7652
|
-
console.log(`CI workflow finished with status: ${ctx.outcome.status}`);
|
|
7653
|
-
},
|
|
7654
|
-
});
|
|
7655
|
-
```
|
|
7269
|
+
**Arguments**
|
|
7656
7270
|
|
|
7657
|
-
|
|
7271
|
+
| Argument | Required | Variadic | Description |
|
|
7272
|
+
| -------- | -------- | -------- | ----------- |
|
|
7273
|
+
| `topic` | no | no | |
|
|
7658
7274
|
|
|
7659
|
-
|
|
7275
|
+
**Options**
|
|
7660
7276
|
|
|
7661
|
-
|
|
7277
|
+
| Option | Default | Description |
|
|
7278
|
+
| -------------- | ------- | -------------------------------------------- |
|
|
7279
|
+
| `--out <path>` | | Write the bundle to a file instead of stdout |
|
|
7662
7280
|
|
|
7663
|
-
|
|
7664
|
-
interface OutcomeMetadata {
|
|
7665
|
-
/** Final status of the job/workflow. */
|
|
7666
|
-
status: 'cancelled' | 'success' | 'failed';
|
|
7667
|
-
/** Reason for cancellation (e.g., "User requested", "Superseded by run #42"). */
|
|
7668
|
-
reason?: string;
|
|
7669
|
-
/** Name of the step that caused failure (for onFailure hooks). */
|
|
7670
|
-
failedStep?: string;
|
|
7671
|
-
/** Outputs from all completed steps. */
|
|
7672
|
-
stepOutputs: Record<string, unknown>;
|
|
7673
|
-
/** Total execution duration in milliseconds. */
|
|
7674
|
-
duration: number;
|
|
7675
|
-
}
|
|
7676
|
-
```
|
|
7281
|
+
### `kici endpoints`
|
|
7677
7282
|
|
|
7678
|
-
|
|
7283
|
+
List all webhook entrypoints for the current project
|
|
7679
7284
|
|
|
7680
|
-
|
|
7285
|
+
Synopsis: `kici endpoints [options]`
|
|
7286
|
+
|
|
7287
|
+
**Options**
|
|
7288
|
+
|
|
7289
|
+
| Option | Default | Description |
|
|
7290
|
+
| ------------------- | ------- | ----------------------- |
|
|
7291
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7292
|
+
|
|
7293
|
+
### `kici fixture`
|
|
7294
|
+
|
|
7295
|
+
Generate fixture template for event type
|
|
7296
|
+
|
|
7297
|
+
Synopsis: `kici fixture <event> [options]`
|
|
7298
|
+
|
|
7299
|
+
**Arguments**
|
|
7300
|
+
|
|
7301
|
+
| Argument | Required | Variadic | Description |
|
|
7302
|
+
| -------- | -------- | -------- | ------------------------------------------------------------------------------------------ |
|
|
7303
|
+
| `event` | yes | no | Event to generate fixture for (e.g., pr:open, push, schedule, lifecycle:workflow_complete) |
|
|
7304
|
+
|
|
7305
|
+
**Options**
|
|
7306
|
+
|
|
7307
|
+
| Option | Default | Description |
|
|
7308
|
+
| ----------------- | ------- | ------------------------------- |
|
|
7309
|
+
| `--output <path>` | | Write to file instead of stdout |
|
|
7310
|
+
|
|
7311
|
+
### `kici hook`
|
|
7312
|
+
|
|
7313
|
+
Manage pre-commit hooks
|
|
7314
|
+
|
|
7315
|
+
Synopsis: `kici hook`
|
|
7316
|
+
|
|
7317
|
+
### `kici hook install`
|
|
7318
|
+
|
|
7319
|
+
Install kici compile pre-commit hook
|
|
7320
|
+
|
|
7321
|
+
Synopsis: `kici hook install [options]`
|
|
7322
|
+
|
|
7323
|
+
**Options**
|
|
7324
|
+
|
|
7325
|
+
| Option | Default | Description |
|
|
7326
|
+
| ------- | ------- | ---------------------------------------- |
|
|
7327
|
+
| `--git` | `false` | Use raw git hook (.git/hooks/pre-commit) |
|
|
7328
|
+
|
|
7329
|
+
### `kici init`
|
|
7330
|
+
|
|
7331
|
+
Initialize .kici/ directory with default workflows
|
|
7332
|
+
|
|
7333
|
+
Synopsis: `kici init [options]`
|
|
7334
|
+
|
|
7335
|
+
**Options**
|
|
7336
|
+
|
|
7337
|
+
| Option | Default | Description |
|
|
7338
|
+
| ---------------------------------- | ---------------------- | --------------------------------------------------------------------------- | --- | ------------------------------------------------------------------- |
|
|
7339
|
+
| `--force` | `false` | Overwrite existing .kici/ directory |
|
|
7340
|
+
| `--skip-install` | `false` | Create files without installing dependencies |
|
|
7341
|
+
| `--package-manager <npm | pnpm | yarn>` | | Force a package manager for the install step (default: auto-detect) |
|
|
7342
|
+
| `--mjs` | `false` | JavaScript-only mode (no TypeScript, no dependencies) |
|
|
7343
|
+
| `--no-agents-md` | | Skip writing .kici/AGENTS.md (LLM authoring context) |
|
|
7344
|
+
| `--private-registry <url>` | | Scaffold a workflow registries: entry pointing at <url> |
|
|
7345
|
+
| `--private-registry-scope <scope>` | | Optional npm package scope (e.g. @my-org) for the private registry |
|
|
7346
|
+
| `--private-registry-secret <ref>` | `production:NPM_TOKEN` | Qualified secret reference (env:NAME) the private registry token comes from |
|
|
7347
|
+
| `--use-verdaccio-local` | `false` | |
|
|
7348
|
+
|
|
7349
|
+
### `kici local`
|
|
7350
|
+
|
|
7351
|
+
Manage the local dev orchestrator plane
|
|
7352
|
+
|
|
7353
|
+
Synopsis: `kici local`
|
|
7354
|
+
|
|
7355
|
+
### `kici local attach`
|
|
7356
|
+
|
|
7357
|
+
Attach the local dev plane to the Platform (hybrid)
|
|
7358
|
+
|
|
7359
|
+
Synopsis: `kici local attach`
|
|
7360
|
+
|
|
7361
|
+
### `kici local detach`
|
|
7362
|
+
|
|
7363
|
+
Detach the local dev plane from the Platform (offline)
|
|
7364
|
+
|
|
7365
|
+
Synopsis: `kici local detach`
|
|
7366
|
+
|
|
7367
|
+
### `kici local down`
|
|
7368
|
+
|
|
7369
|
+
Stop the local dev plane
|
|
7370
|
+
|
|
7371
|
+
Synopsis: `kici local down`
|
|
7372
|
+
|
|
7373
|
+
### `kici local logs`
|
|
7374
|
+
|
|
7375
|
+
Print the local dev plane orchestrator log path
|
|
7376
|
+
|
|
7377
|
+
Synopsis: `kici local logs`
|
|
7378
|
+
|
|
7379
|
+
### `kici local status`
|
|
7380
|
+
|
|
7381
|
+
Show local dev plane status and control commands
|
|
7382
|
+
|
|
7383
|
+
Synopsis: `kici local status`
|
|
7384
|
+
|
|
7385
|
+
### `kici local trust-root`
|
|
7386
|
+
|
|
7387
|
+
Export the offline dev-signed identity trust root ({ issuer, jwks }) to a file
|
|
7388
|
+
|
|
7389
|
+
Synopsis: `kici local trust-root <file>`
|
|
7390
|
+
|
|
7391
|
+
**Arguments**
|
|
7392
|
+
|
|
7393
|
+
| Argument | Required | Variadic | Description |
|
|
7394
|
+
| -------- | -------- | -------- | ---------------------------------------------------- |
|
|
7395
|
+
| `file` | yes | no | Output path for the { issuer, jwks } trust-root JSON |
|
|
7396
|
+
|
|
7397
|
+
### `kici local up`
|
|
7398
|
+
|
|
7399
|
+
Start (or reuse) the local dev plane
|
|
7400
|
+
|
|
7401
|
+
Synopsis: `kici local up [options]`
|
|
7402
|
+
|
|
7403
|
+
**Options**
|
|
7404
|
+
|
|
7405
|
+
| Option | Default | Description |
|
|
7406
|
+
| ------------- | ------- | ---------------------------------------------------------------------------- |
|
|
7407
|
+
| `--offline` | `false` | Force the independent (offline) plane (does not clear the attachment record) |
|
|
7408
|
+
| `--connected` | `false` | Force the connected/hybrid plane (requires an attached, reachable Platform) |
|
|
7409
|
+
|
|
7410
|
+
### `kici login`
|
|
7411
|
+
|
|
7412
|
+
Authenticate with KiCI via browser OAuth (default) or API key (--token)
|
|
7413
|
+
|
|
7414
|
+
Synopsis: `kici login [options]`
|
|
7415
|
+
|
|
7416
|
+
**Options**
|
|
7417
|
+
|
|
7418
|
+
| Option | Default | Description |
|
|
7419
|
+
| --------------------------- | ------- | ----------------------------------------------------------------------------------- |
|
|
7420
|
+
| `--token <key>` | | API key for direct authentication (legacy) |
|
|
7421
|
+
| `--device` | | Force device authorization flow (for headless/SSH environments) |
|
|
7422
|
+
| `--platform-endpoint <url>` | | Platform relay URL |
|
|
7423
|
+
| `--oidc-issuer <url>` | | OIDC issuer URL (defaults to the hosted KiCI IdP unless a flag/env selects another) |
|
|
7424
|
+
| `--routing-key <key>` | | Routing key for webhook source identification |
|
|
7425
|
+
| `--no-attach` | | Skip the post-login prompt to attach the local dev plane |
|
|
7426
|
+
|
|
7427
|
+
### `kici logout`
|
|
7428
|
+
|
|
7429
|
+
Revoke PAT and clear local credentials
|
|
7430
|
+
|
|
7431
|
+
Synopsis: `kici logout`
|
|
7432
|
+
|
|
7433
|
+
### `kici orchestrators`
|
|
7434
|
+
|
|
7435
|
+
Inspect the org's orchestrator clusters and pick a default for run remote
|
|
7436
|
+
|
|
7437
|
+
Synopsis: `kici orchestrators`
|
|
7438
|
+
|
|
7439
|
+
### `kici orchestrators list`
|
|
7440
|
+
|
|
7441
|
+
List the connected orchestrator clusters for the active org
|
|
7442
|
+
|
|
7443
|
+
Synopsis: `kici orchestrators list [options]`
|
|
7444
|
+
|
|
7445
|
+
**Options**
|
|
7446
|
+
|
|
7447
|
+
| Option | Default | Description |
|
|
7448
|
+
| ------------ | ------- | ---------------------------------------------- |
|
|
7449
|
+
| `--org <id>` | | Target organization (overrides the active org) |
|
|
7450
|
+
|
|
7451
|
+
### `kici orchestrators use`
|
|
7452
|
+
|
|
7453
|
+
Set the per-org default orchestrator cluster for run remote
|
|
7454
|
+
|
|
7455
|
+
Synopsis: `kici orchestrators use <name> [options]`
|
|
7456
|
+
|
|
7457
|
+
**Arguments**
|
|
7458
|
+
|
|
7459
|
+
| Argument | Required | Variadic | Description |
|
|
7460
|
+
| -------- | -------- | -------- | ------------------------- |
|
|
7461
|
+
| `name` | yes | no | Orchestrator cluster name |
|
|
7462
|
+
|
|
7463
|
+
**Options**
|
|
7464
|
+
|
|
7465
|
+
| Option | Default | Description |
|
|
7466
|
+
| ------------ | ------- | ---------------------------------------------- |
|
|
7467
|
+
| `--org <id>` | | Target organization (overrides the active org) |
|
|
7468
|
+
|
|
7469
|
+
### `kici org`
|
|
7470
|
+
|
|
7471
|
+
Manage organizations
|
|
7472
|
+
|
|
7473
|
+
Synopsis: `kici org`
|
|
7474
|
+
|
|
7475
|
+
### `kici org current`
|
|
7476
|
+
|
|
7477
|
+
Show current active organization
|
|
7478
|
+
|
|
7479
|
+
Synopsis: `kici org current`
|
|
7480
|
+
|
|
7481
|
+
### `kici org list`
|
|
7482
|
+
|
|
7483
|
+
List organizations you belong to
|
|
7484
|
+
|
|
7485
|
+
Synopsis: `kici org list`
|
|
7486
|
+
|
|
7487
|
+
### `kici org use`
|
|
7488
|
+
|
|
7489
|
+
Switch active organization
|
|
7490
|
+
|
|
7491
|
+
Synopsis: `kici org use <name>`
|
|
7492
|
+
|
|
7493
|
+
**Arguments**
|
|
7494
|
+
|
|
7495
|
+
| Argument | Required | Variadic | Description |
|
|
7496
|
+
| -------- | -------- | -------- | ----------------------- |
|
|
7497
|
+
| `name` | yes | no | Organization name or ID |
|
|
7498
|
+
|
|
7499
|
+
### `kici pat`
|
|
7500
|
+
|
|
7501
|
+
Manage personal access tokens
|
|
7502
|
+
|
|
7503
|
+
Synopsis: `kici pat`
|
|
7504
|
+
|
|
7505
|
+
### `kici pat create`
|
|
7506
|
+
|
|
7507
|
+
Mint a personal access token (use --agent for a coding-agent token)
|
|
7508
|
+
|
|
7509
|
+
Synopsis: `kici pat create [options]`
|
|
7510
|
+
|
|
7511
|
+
**Options**
|
|
7512
|
+
|
|
7513
|
+
| Option | Default | Description |
|
|
7514
|
+
| ----------------------- | ------- | ---------------------------------------------- |
|
|
7515
|
+
| `--name <name>` | | Token name (defaults to the agent label) |
|
|
7516
|
+
| `--agent` | `false` | Mint an agent-kind PAT for the KiCI MCP server |
|
|
7517
|
+
| `--expires-in-days <n>` | | Custom expiry in days |
|
|
7518
|
+
|
|
7519
|
+
### `kici preview`
|
|
7520
|
+
|
|
7521
|
+
Preview which workflows match a trigger event (no execution)
|
|
7522
|
+
|
|
7523
|
+
Synopsis: `kici preview [event] [options]`
|
|
7524
|
+
|
|
7525
|
+
**Arguments**
|
|
7526
|
+
|
|
7527
|
+
| Argument | Required | Variadic | Description |
|
|
7528
|
+
| -------- | -------- | -------- | ----------------------------------------------------- |
|
|
7529
|
+
| `event` | no | no | Event type to preview (e.g., push, pr:open, schedule) |
|
|
7530
|
+
|
|
7531
|
+
**Options**
|
|
7532
|
+
|
|
7533
|
+
| Option | Default | Description |
|
|
7534
|
+
| --------------------------- | ------- | ------------------------------------------------------------ |
|
|
7535
|
+
| `--branch <name>` | | Override target branch for trigger matching (default: main) |
|
|
7536
|
+
| `--sha <hash>` | | Override commit SHA |
|
|
7537
|
+
| `--workflow <name>` | | Filter to specific workflow in display |
|
|
7538
|
+
| `--job <name>` | | Filter to specific job in display |
|
|
7539
|
+
| `--debug` | `false` | Verbose internals |
|
|
7540
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7541
|
+
| `--files <path>` | | Simulate changed file path for trigger matching (repeatable) |
|
|
7542
|
+
| `--secret <key=value>` | | Inject flat secret (repeatable) |
|
|
7543
|
+
| `--context <ctx.key=value>` | | Inject context secret (repeatable) |
|
|
7544
|
+
|
|
7545
|
+
### `kici reject`
|
|
7546
|
+
|
|
7547
|
+
Reject a held approval gate for a run
|
|
7548
|
+
|
|
7549
|
+
Synopsis: `kici reject <run-id> [options]`
|
|
7550
|
+
|
|
7551
|
+
**Arguments**
|
|
7552
|
+
|
|
7553
|
+
| Argument | Required | Variadic | Description |
|
|
7554
|
+
| -------- | -------- | -------- | ------------------------------------ |
|
|
7555
|
+
| `run-id` | yes | no | Run ID whose approval gate to reject |
|
|
7556
|
+
|
|
7557
|
+
**Options**
|
|
7558
|
+
|
|
7559
|
+
| Option | Default | Description |
|
|
7560
|
+
| ----------------- | ------- | ------------------------------------------ |
|
|
7561
|
+
| `--job <name>` | | Reject the hold for a specific job |
|
|
7562
|
+
| `--step <index>` | | Reject a step-scoped hold (requires --job) |
|
|
7563
|
+
| `--reason <text>` | | Reason for the rejection |
|
|
7564
|
+
|
|
7565
|
+
### `kici run`
|
|
7566
|
+
|
|
7567
|
+
Execute workflows locally or remotely
|
|
7568
|
+
|
|
7569
|
+
Synopsis: `kici run [event] [options]`
|
|
7570
|
+
|
|
7571
|
+
**Arguments**
|
|
7572
|
+
|
|
7573
|
+
| Argument | Required | Variadic | Description |
|
|
7574
|
+
| -------- | -------- | -------- | ------------------------------------------------------ |
|
|
7575
|
+
| `event` | no | no | Event type for a routed local run (e.g. push, pr:open) |
|
|
7576
|
+
|
|
7577
|
+
**Options**
|
|
7578
|
+
|
|
7579
|
+
| Option | Default | Description |
|
|
7580
|
+
| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
7581
|
+
| `--local` | `false` | Route the run with this machine as the ephemeral agent |
|
|
7582
|
+
| `--offline` | `false` | Force the throwaway/independent plane (offline) |
|
|
7583
|
+
| `--connected` | `false` | Force the connected/hybrid plane (requires attachment) |
|
|
7584
|
+
| `--in-place` | `false` | Reuse the working tree directly instead of an isolated clone |
|
|
7585
|
+
| `--trusted` | `false` | Route to the trusted fleet agent profile: steps see the ambient host env (minus the agent identity). Alias: --no-sandbox |
|
|
7586
|
+
| `--no-sandbox` | | Alias for --trusted (the bwrap sandbox is already off by default) |
|
|
7587
|
+
| `--env <KEY=VALUE>` | | Per-run secret (repeatable) |
|
|
7588
|
+
| `--payload <path>` | | Dispatch payload JSON { action?, client_payload? } for a routed dispatch run |
|
|
7589
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7590
|
+
| `--quiet` | `false` | Suppress the banner + streaming output |
|
|
7591
|
+
| `--debug` | `false` | Verbose internals |
|
|
7592
|
+
|
|
7593
|
+
### `kici run remote`
|
|
7594
|
+
|
|
7595
|
+
Execute fixtures remotely via orchestrator
|
|
7596
|
+
|
|
7597
|
+
Synopsis: `kici run remote [fixture] [options]`
|
|
7598
|
+
|
|
7599
|
+
**Arguments**
|
|
7600
|
+
|
|
7601
|
+
| Argument | Required | Variadic | Description |
|
|
7602
|
+
| --------- | -------- | -------- | ----------------------------------------------------- |
|
|
7603
|
+
| `fixture` | no | no | Fixture name or glob pattern (omit to list available) |
|
|
7604
|
+
|
|
7605
|
+
**Options**
|
|
7606
|
+
|
|
7607
|
+
| Option | Default | Description |
|
|
7608
|
+
| --------------------------- | ------- | ------------------------------------------------------------------------------------------- |
|
|
7609
|
+
| `--workflow <name>` | | Run a specific workflow directly (bypass triggers) |
|
|
7610
|
+
| `--all` | `false` | Run all available fixtures |
|
|
7611
|
+
| `-p, --pick` | `false` | Interactively pick fixtures to run |
|
|
7612
|
+
| `--parallel` | `false` | Run matching fixtures concurrently |
|
|
7613
|
+
| `--no-wait` | | Fire and forget (print runIds, don't stream) |
|
|
7614
|
+
| `--quiet` | `false` | Suppress output except final result |
|
|
7615
|
+
| `--json` | `false` | Output structured JSON result |
|
|
7616
|
+
| `--junit <path>` | | Output JUnit XML result |
|
|
7617
|
+
| `--history` | `false` | Show recent run history |
|
|
7618
|
+
| `--routing-key <key>` | | Override routing key for this run |
|
|
7619
|
+
| `--org <id>` | | Target organization (overrides the active org) |
|
|
7620
|
+
| `--orchestrator <name>` | | Target orchestrator cluster (overrides the per-org default) |
|
|
7621
|
+
| `--debug` | `false` | Verbose internals |
|
|
7622
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7623
|
+
| `--context <ctx.key=value>` | | Inject a namespaced context secret, uploaded encrypted to the orchestrator (repeatable) |
|
|
7624
|
+
| `--env <KEY=VALUE>` | | Provide a per-run secret (repeatable); uploaded encrypted to the orchestrator |
|
|
7625
|
+
| `--check` | `false` | Run in check mode: report drift, change nothing |
|
|
7626
|
+
| `--fail-on-drift` | `false` | In check mode, exit non-zero if any step reports drift |
|
|
7627
|
+
| `--target <selector>` | | Narrow runsOnAll jobs to hosts matching this label selector (repeatable, AND-combined) |
|
|
7628
|
+
| `--target-allow-empty` | `false` | A --target that narrows a runsOnAll job to zero hosts skips it instead of failing |
|
|
7629
|
+
| `--input <KEY=VALUE>` | | Typed workflow-dispatch input (repeatable) |
|
|
7630
|
+
| `--yes, --approve-all` | `false` | Auto-approve every approval gate this run holds on (run-scoped; eligibility still enforced) |
|
|
7631
|
+
|
|
7632
|
+
### `kici runs`
|
|
7633
|
+
|
|
7634
|
+
Inspect and manage execution runs
|
|
7635
|
+
|
|
7636
|
+
Synopsis: `kici runs`
|
|
7637
|
+
|
|
7638
|
+
### `kici runs cancel`
|
|
7639
|
+
|
|
7640
|
+
Cancel a run, or all in-progress runs on a branch
|
|
7641
|
+
|
|
7642
|
+
Synopsis: `kici runs cancel [run-id] [options]`
|
|
7643
|
+
|
|
7644
|
+
**Arguments**
|
|
7645
|
+
|
|
7646
|
+
| Argument | Required | Variadic | Description |
|
|
7647
|
+
| -------- | -------- | -------- | ---------------- |
|
|
7648
|
+
| `run-id` | no | no | Run ID to cancel |
|
|
7649
|
+
|
|
7650
|
+
**Options**
|
|
7651
|
+
|
|
7652
|
+
| Option | Default | Description |
|
|
7653
|
+
| ----------------- | ------- | ------------------------------------------- |
|
|
7654
|
+
| `--force` | `false` | Force cancel (kill immediately, skip hooks) |
|
|
7655
|
+
| `--branch <name>` | | Cancel all in-progress runs on this branch |
|
|
7656
|
+
|
|
7657
|
+
### `kici runs list`
|
|
7658
|
+
|
|
7659
|
+
List execution runs (mirrors the dashboard Runs page)
|
|
7660
|
+
|
|
7661
|
+
Synopsis: `kici runs list [options]`
|
|
7662
|
+
|
|
7663
|
+
**Options**
|
|
7664
|
+
|
|
7665
|
+
| Option | Default | Description |
|
|
7666
|
+
| ----------------------- | ------- | -------------------------------------- |
|
|
7667
|
+
| `--status <s>` | | Filter by status |
|
|
7668
|
+
| `--workflow <w>` | | Filter by workflow name |
|
|
7669
|
+
| `--branch <b>` | | Filter by branch/ref |
|
|
7670
|
+
| `--repo <r>` | | Filter by repository |
|
|
7671
|
+
| `--trigger <t>` | | Filter by trigger type |
|
|
7672
|
+
| `--source <routingKey>` | | Filter by source routing key |
|
|
7673
|
+
| `--since <ts>` | | Only runs since (ISO-8601 or epoch ms) |
|
|
7674
|
+
| `--page <n>` | | Page number |
|
|
7675
|
+
| `--json` | `false` | Output raw JSON |
|
|
7676
|
+
|
|
7677
|
+
### `kici runs logs`
|
|
7678
|
+
|
|
7679
|
+
Print step logs for a run
|
|
7680
|
+
|
|
7681
|
+
Synopsis: `kici runs logs <run-id> [options]`
|
|
7682
|
+
|
|
7683
|
+
**Arguments**
|
|
7684
|
+
|
|
7685
|
+
| Argument | Required | Variadic | Description |
|
|
7686
|
+
| -------- | -------- | -------- | ----------- |
|
|
7687
|
+
| `run-id` | yes | no | Run ID |
|
|
7688
|
+
|
|
7689
|
+
**Options**
|
|
7690
|
+
|
|
7691
|
+
| Option | Default | Description |
|
|
7692
|
+
| -------------- | ------- | ------------------------ |
|
|
7693
|
+
| `--job <name>` | | Only logs for this job |
|
|
7694
|
+
| `-f, --follow` | `false` | Tail logs for a live run |
|
|
7695
|
+
| `--json` | `false` | Output raw JSON |
|
|
7696
|
+
|
|
7697
|
+
### `kici runs rerun`
|
|
7698
|
+
|
|
7699
|
+
Re-trigger a run
|
|
7700
|
+
|
|
7701
|
+
Synopsis: `kici runs rerun <run-id> [options]`
|
|
7702
|
+
|
|
7703
|
+
**Arguments**
|
|
7704
|
+
|
|
7705
|
+
| Argument | Required | Variadic | Description |
|
|
7706
|
+
| -------- | -------- | -------- | --------------- |
|
|
7707
|
+
| `run-id` | yes | no | Run ID to rerun |
|
|
7708
|
+
|
|
7709
|
+
**Options**
|
|
7710
|
+
|
|
7711
|
+
| Option | Default | Description |
|
|
7712
|
+
| -------- | ------- | --------------- |
|
|
7713
|
+
| `--json` | `false` | Output raw JSON |
|
|
7714
|
+
|
|
7715
|
+
### `kici runs show`
|
|
7716
|
+
|
|
7717
|
+
Show a run summary with its jobs and steps
|
|
7718
|
+
|
|
7719
|
+
Synopsis: `kici runs show <run-id> [options]`
|
|
7720
|
+
|
|
7721
|
+
**Arguments**
|
|
7722
|
+
|
|
7723
|
+
| Argument | Required | Variadic | Description |
|
|
7724
|
+
| -------- | -------- | -------- | ----------------- |
|
|
7725
|
+
| `run-id` | yes | no | Run ID to inspect |
|
|
7726
|
+
|
|
7727
|
+
**Options**
|
|
7728
|
+
|
|
7729
|
+
| Option | Default | Description |
|
|
7730
|
+
| -------- | ------- | --------------- |
|
|
7731
|
+
| `--json` | `false` | Output raw JSON |
|
|
7732
|
+
|
|
7733
|
+
### `kici secrets`
|
|
7734
|
+
|
|
7735
|
+
Manage secrets
|
|
7736
|
+
|
|
7737
|
+
Synopsis: `kici secrets`
|
|
7738
|
+
|
|
7739
|
+
### `kici secrets list`
|
|
7740
|
+
|
|
7741
|
+
List test-available secret contexts
|
|
7742
|
+
|
|
7743
|
+
Synopsis: `kici secrets list`
|
|
7744
|
+
|
|
7745
|
+
### `kici types`
|
|
7746
|
+
|
|
7747
|
+
Generate TypeScript declarations for secret contexts
|
|
7748
|
+
|
|
7749
|
+
Synopsis: `kici types [options]`
|
|
7750
|
+
|
|
7751
|
+
**Options**
|
|
7752
|
+
|
|
7753
|
+
| Option | Default | Description |
|
|
7754
|
+
| ------------------- | ------- | ----------------------- |
|
|
7755
|
+
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
7756
|
+
|
|
7757
|
+
### `kici verify-attestation`
|
|
7758
|
+
|
|
7759
|
+
Verify a KiCI provenance attestation bundle offline
|
|
7760
|
+
|
|
7761
|
+
Synopsis: `kici verify-attestation [artifact] [options]`
|
|
7762
|
+
|
|
7763
|
+
**Arguments**
|
|
7764
|
+
|
|
7765
|
+
| Argument | Required | Variadic | Description |
|
|
7766
|
+
| ---------- | -------- | -------- | ------------------------------------------------------------------------ |
|
|
7767
|
+
| `artifact` | no | no | Artifact path to digest-check against the attestation subject (optional) |
|
|
7768
|
+
|
|
7769
|
+
**Options**
|
|
7770
|
+
|
|
7771
|
+
| Option | Default | Description |
|
|
7772
|
+
| ---------------------------- | ------- | --------------------------------------------------------------------------------------------- |
|
|
7773
|
+
| `--bundle <path>` | | Path or URL to the attestation bundle JSON |
|
|
7774
|
+
| `--trust-root <url-or-file>` | | Trusted issuer URL, or a self-contained { issuer, jwks } file (default: hosted KiCI platform) |
|
|
7775
|
+
| `--audience <aud>` | | Expected token audience |
|
|
7776
|
+
| `--json` | `false` | Output structured JSON result |
|
|
7777
|
+
|
|
7778
|
+
### `kici workflows`
|
|
7779
|
+
|
|
7780
|
+
Manage workflow registrations
|
|
7781
|
+
|
|
7782
|
+
Synopsis: `kici workflows`
|
|
7783
|
+
|
|
7784
|
+
### `kici workflows list`
|
|
7785
|
+
|
|
7786
|
+
List permanently registered workflows
|
|
7787
|
+
|
|
7788
|
+
Synopsis: `kici workflows list [options]`
|
|
7789
|
+
|
|
7790
|
+
**Options**
|
|
7791
|
+
|
|
7792
|
+
| Option | Default | Description |
|
|
7793
|
+
| ----------------------- | ------- | ------------------------------------------ |
|
|
7794
|
+
| `--json` | `false` | Output as JSON |
|
|
7795
|
+
| `--stale <duration>` | | Filter stale registrations (e.g., 30d, 7d) |
|
|
7796
|
+
| `--trigger-type <type>` | | Filter by trigger type |
|
|
7797
|
+
| `--repo <repo>` | | Filter by repository |
|
|
7798
|
+
|
|
7799
|
+
<!-- END GENERATED: kici-commands -->
|
|
7800
|
+
|
|
7801
|
+
## Workflow discovery
|
|
7802
|
+
|
|
7803
|
+
The CLI discovers workflows by scanning `.kici/workflows/*.ts` (or `.mjs` in MJS mode). Each file should `export default` a single workflow:
|
|
7804
|
+
|
|
7805
|
+
```typescript
|
|
7806
|
+
// .kici/workflows/ci.ts
|
|
7807
|
+
import { workflow, job, step, pr } from '@kici-dev/sdk';
|
|
7808
|
+
|
|
7809
|
+
export default workflow('ci', {
|
|
7810
|
+
on: pr(),
|
|
7811
|
+
jobs: [
|
|
7812
|
+
/* ... */
|
|
7813
|
+
],
|
|
7814
|
+
});
|
|
7815
|
+
```
|
|
7816
|
+
|
|
7817
|
+
Multiple workflow files are supported -- each becomes a separate workflow in `kici.lock.json`.
|
|
7818
|
+
|
|
7819
|
+
## Lock file
|
|
7820
|
+
|
|
7821
|
+
The `kici compile` command produces `.kici/kici.lock.json` inside the `.kici` directory. This file:
|
|
7822
|
+
|
|
7823
|
+
- Contains all workflow definitions in a portable JSON format
|
|
7824
|
+
- Is used by the orchestrator to evaluate triggers without code checkout
|
|
7825
|
+
- Should be committed to version control
|
|
7826
|
+
- Is regenerated on every `kici compile` run
|
|
7827
|
+
|
|
7828
|
+
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](https://docs.kici.dev/user/lock-file-and-drift/).
|
|
7829
|
+
|
|
7830
|
+
## Exit codes
|
|
7831
|
+
|
|
7832
|
+
All commands follow a consistent exit code convention:
|
|
7833
|
+
|
|
7834
|
+
| Code | Meaning |
|
|
7835
|
+
| ---- | -------------------- |
|
|
7836
|
+
| 0 | Success |
|
|
7837
|
+
| 1 | Failure (see output) |
|
|
7838
|
+
|
|
7839
|
+
## Debug output
|
|
7840
|
+
|
|
7841
|
+
Use `--debug` (on `kici run <event> --local`, `kici run remote`, `kici preview`) or `--verbose` (on `kici compile`) for detailed output:
|
|
7842
|
+
|
|
7843
|
+
```bash
|
|
7844
|
+
# Shows trigger matching, rule evaluation, decision traces
|
|
7845
|
+
kici run push --local --debug
|
|
7846
|
+
|
|
7847
|
+
# Shows detailed compilation steps
|
|
7848
|
+
kici compile --verbose
|
|
7849
|
+
|
|
7850
|
+
# Shows trigger matching preview
|
|
7851
|
+
kici preview pr:open --debug
|
|
7852
|
+
```
|
|
7853
|
+
|
|
7854
|
+
Set `KICI_DEBUG=true` for additional internal debug output across all commands.
|
|
7855
|
+
|
|
7856
|
+
## Environment variables
|
|
7857
|
+
|
|
7858
|
+
| Variable | Description |
|
|
7859
|
+
| ------------ | ----------------------------------------- |
|
|
7860
|
+
| `KICI_DEV` | Set to `true` for development mode |
|
|
7861
|
+
| `KICI_DEBUG` | Set to `true` for verbose internal output |
|
|
7862
|
+
| `CI` | When `true`, disables interactive prompts |
|
|
7863
|
+
|
|
7864
|
+
## See also
|
|
7865
|
+
|
|
7866
|
+
- [Getting started](https://docs.kici.dev/user/getting-started/) -- install the SDK and write your first workflow
|
|
7867
|
+
- [Testing guide](https://docs.kici.dev/user/testing-guide/) -- writing fixtures, remote test runs, secret contexts, and repo state transfer
|
|
7868
|
+
- [SDK reference](https://docs.kici.dev/user/sdk-reference/) -- complete API for the workflow definitions that the CLI compiles
|
|
7869
|
+
- [Workflow patterns](https://docs.kici.dev/user/workflow-patterns/) -- example workflows to compile and test with these commands
|
|
7870
|
+
|
|
7871
|
+
---
|
|
7872
|
+
|
|
7873
|
+
## Lifecycle hooks
|
|
7874
|
+
|
|
7875
|
+
Source: https://docs.kici.dev/user/hooks/
|
|
7876
|
+
|
|
7877
|
+
Hooks are callbacks that run at specific points in the execution lifecycle. They let you react to outcomes (cancellation, success, failure) and perform cleanup without affecting the execution flow.
|
|
7878
|
+
|
|
7879
|
+
## Hook types
|
|
7880
|
+
|
|
7881
|
+
KiCI supports six hook types at three levels (step, job, workflow):
|
|
7882
|
+
|
|
7883
|
+
| Hook | When it runs | Available on |
|
|
7884
|
+
| ------------ | ------------------------------------ | ------------------- |
|
|
7885
|
+
| `onCancel` | After step/job/workflow is cancelled | Step, Job, Workflow |
|
|
7886
|
+
| `cleanup` | Always (success, failure, or cancel) | Step, Job, Workflow |
|
|
7887
|
+
| `onSuccess` | After job/workflow succeeds | Job, Workflow |
|
|
7888
|
+
| `onFailure` | After job/workflow fails | Job, Workflow |
|
|
7889
|
+
| `beforeStep` | Before each step in a job | Job |
|
|
7890
|
+
| `afterStep` | After each step in a job | Job |
|
|
7891
|
+
|
|
7892
|
+
## Basic usage
|
|
7893
|
+
|
|
7894
|
+
### Job-level hooks
|
|
7895
|
+
|
|
7896
|
+
```typescript
|
|
7897
|
+
import { workflow, job, step, push } from '@kici-dev/sdk';
|
|
7898
|
+
|
|
7899
|
+
export default workflow('deploy', {
|
|
7900
|
+
on: push({ branches: ['main'] }),
|
|
7901
|
+
jobs: [
|
|
7902
|
+
job('deploy-prod', {
|
|
7903
|
+
runsOn: 'linux',
|
|
7904
|
+
steps: [
|
|
7905
|
+
step('deploy', async ({ $ }) => {
|
|
7906
|
+
await $`kubectl apply -f manifests/`;
|
|
7907
|
+
}),
|
|
7908
|
+
],
|
|
7909
|
+
onCancel: async (ctx) => {
|
|
7910
|
+
console.log(`Deploy cancelled: ${ctx.outcome.reason}`);
|
|
7911
|
+
await ctx.$`kubectl rollout undo deployment/app`;
|
|
7912
|
+
},
|
|
7913
|
+
cleanup: async (ctx) => {
|
|
7914
|
+
// Always runs -- release lock, notify team, etc.
|
|
7915
|
+
await ctx.$`curl -X POST https://slack.com/webhook -d '{"text": "Deploy ${ctx.outcome.status}"}'`;
|
|
7916
|
+
},
|
|
7917
|
+
onSuccess: async (ctx) => {
|
|
7918
|
+
console.log(`Deploy succeeded in ${ctx.outcome.duration}ms`);
|
|
7919
|
+
},
|
|
7920
|
+
onFailure: async (ctx) => {
|
|
7921
|
+
console.log(`Deploy failed at step: ${ctx.outcome.failedStep}`);
|
|
7922
|
+
},
|
|
7923
|
+
gracePeriod: 60, // 60 seconds before SIGKILL on cancel
|
|
7924
|
+
}),
|
|
7925
|
+
],
|
|
7926
|
+
});
|
|
7927
|
+
```
|
|
7928
|
+
|
|
7929
|
+
### Step-level hooks
|
|
7930
|
+
|
|
7931
|
+
```typescript
|
|
7932
|
+
step('download-artifacts', {
|
|
7933
|
+
run: async ({ $ }) => {
|
|
7934
|
+
await $`wget https://artifacts.example.com/build.tar.gz`;
|
|
7935
|
+
},
|
|
7936
|
+
onCancel: async (ctx) => {
|
|
7937
|
+
// Clean up partial downloads
|
|
7938
|
+
await ctx.$`rm -f build.tar.gz`;
|
|
7939
|
+
},
|
|
7940
|
+
cleanup: async (ctx) => {
|
|
7941
|
+
await ctx.$`rm -rf /tmp/staging`;
|
|
7942
|
+
},
|
|
7943
|
+
});
|
|
7944
|
+
```
|
|
7945
|
+
|
|
7946
|
+
### Workflow-level hooks
|
|
7947
|
+
|
|
7948
|
+
```typescript
|
|
7949
|
+
workflow('ci', {
|
|
7950
|
+
on: push({ branches: ['main'] }),
|
|
7951
|
+
jobs: [
|
|
7952
|
+
/* ... */
|
|
7953
|
+
],
|
|
7954
|
+
onCancel: async (ctx) => {
|
|
7955
|
+
// Notify when any job in the workflow is cancelled
|
|
7956
|
+
console.log('CI workflow cancelled');
|
|
7957
|
+
},
|
|
7958
|
+
cleanup: async (ctx) => {
|
|
7959
|
+
// Always runs after all jobs complete
|
|
7960
|
+
console.log(`CI workflow finished with status: ${ctx.outcome.status}`);
|
|
7961
|
+
},
|
|
7962
|
+
});
|
|
7963
|
+
```
|
|
7964
|
+
|
|
7965
|
+
## Hook context
|
|
7966
|
+
|
|
7967
|
+
Hook functions receive the same `StepContext` as regular steps (`$`, `ctx`, `log`, `env`), plus an `outcome` object with metadata about the execution result.
|
|
7968
|
+
|
|
7969
|
+
### ctx.outcome
|
|
7970
|
+
|
|
7971
|
+
```typescript
|
|
7972
|
+
interface OutcomeMetadata {
|
|
7973
|
+
/** Final status of the job/workflow. */
|
|
7974
|
+
status: 'cancelled' | 'success' | 'failed';
|
|
7975
|
+
/** Reason for cancellation (e.g., "User requested", "Superseded by run #42"). */
|
|
7976
|
+
reason?: string;
|
|
7977
|
+
/** Name of the step that caused failure (for onFailure hooks). */
|
|
7978
|
+
failedStep?: string;
|
|
7979
|
+
/** Outputs from all completed steps. */
|
|
7980
|
+
stepOutputs: Record<string, unknown>;
|
|
7981
|
+
/** Total execution duration in milliseconds. */
|
|
7982
|
+
duration: number;
|
|
7983
|
+
}
|
|
7984
|
+
```
|
|
7985
|
+
|
|
7986
|
+
### Capabilities
|
|
7987
|
+
|
|
7988
|
+
Hooks can do everything regular steps can:
|
|
7681
7989
|
|
|
7682
7990
|
- Run shell commands via `$`
|
|
7683
7991
|
- Set environment variables via `ctx.setEnv()` and prepend to `PATH` via `ctx.addPath()`
|
|
@@ -7836,14 +8144,14 @@ Each workflow entry includes:
|
|
|
7836
8144
|
| `contentHash` | SHA-256 of the raw workflow source mixed with `compileSchemaVersion` (and an `assetDigest` of declared `hashFiles` when present): `SHA-256(compileSchemaVersion + ":" + rawSource [+ "\0" + assetDigest])`. The orchestrator uses this as the source-tarball cache key and the agent re-computes it against the extracted source to detect drift. |
|
|
7837
8145
|
| `compileSchemaVersion` | Compiler schema version used when computing `contentHash` (currently `5`). The hash input is line-ending-normalized (CRLF → LF) so a lock file produced on Linux matches the agent's hash on Windows where Git's `core.autocrlf=true` rewrites checked-out text to CRLF. Bumping the schema version invalidates every existing source cache entry even if source is unchanged, which is the correct behavior when the compile-time or runtime contract changes. |
|
|
7838
8146
|
| `triggers` | Trigger definitions extracted from the workflow (used by the orchestrator for event matching). |
|
|
7839
|
-
| `jobs` | Job definitions with scheduling metadata (runsOn, needs, matrix,
|
|
8147
|
+
| `jobs` | Job definitions with scheduling metadata (runsOn, needs, matrix, contexts, concurrency, container, checkout, gracePeriod, label routing, dynamic fields, etc.). |
|
|
7840
8148
|
| `rules` | Workflow-level conditional rules (optional). Stored as dynamic references since rule functions cannot be serialized. |
|
|
7841
8149
|
| `description` | Optional workflow description. |
|
|
7842
8150
|
| `hashFiles` | Declared glob patterns for extra files included in the content hash (optional). See [extra files in the content hash](https://docs.kici.dev/user/lock-file-and-drift/#extra-files-in-the-content-hash-hashfiles). |
|
|
7843
8151
|
| `resolvedHashFiles` | Resolved file paths from `hashFiles` at compile time (optional). Recorded so the agent can verify without re-discovering. |
|
|
7844
8152
|
| `contexts` | Secret contexts declared by the workflow (optional). The orchestrator validates access to each context before dispatch. |
|
|
7845
8153
|
| `registries` | Private npm registry declarations the agent authenticates against before install (optional): `url`, `scope`, `tokenSecret` reference, `alwaysAuth`. Resolved token bytes never appear in the lock file. See [private registries](https://docs.kici.dev/user/private-registries/). |
|
|
7846
|
-
| `installEnv` | Extra qualified secret refs (`<
|
|
8154
|
+
| `installEnv` | Extra qualified secret refs (`<context>:<secret-name>`) projected as env vars on the install subprocess for use with a committed `.kici/.npmrc` (optional). See [private registries](https://docs.kici.dev/user/private-registries/). |
|
|
7847
8155
|
| `concurrency` | Workflow-level concurrency config: `hasGroup`, `cancelInProgress`, `max` (optional). See [concurrency groups](https://docs.kici.dev/user/concurrency/). |
|
|
7848
8156
|
| `timeout` | Whole-run wall-clock timeout in milliseconds (optional). The orchestrator reads this at run creation to set the run deadline. |
|
|
7849
8157
|
| Hook flags | Boolean flags (`hasOnCancel`, `hasCleanup`, `hasOnSuccess`, `hasOnFailure`) indicating which lifecycle hooks are defined. Job entries additionally have `hasBeforeStep` and `hasAfterStep`. |
|
|
@@ -8071,12 +8379,12 @@ export const pushWithSecrets = fixture('push-with-secrets', {
|
|
|
8071
8379
|
|
|
8072
8380
|
This maps the `db` secret context to the `test-database` context, and `api` to `test-api-keys`.
|
|
8073
8381
|
|
|
8074
|
-
This mapping is honored by **both** `kici run local` and `kici run remote`:
|
|
8382
|
+
This mapping is honored by **both** `kici run <event> --local` and `kici run remote`:
|
|
8075
8383
|
|
|
8076
|
-
- For **`kici run local`** (see [`kici run local`](https://docs.kici.dev/user/cli-reference/#kici-run-local)), each named context is resolved from your local secret files (`.kici/.secrets`, `.env.local`, `secrets.yaml`, and `--env` flags).
|
|
8077
|
-
- For **`kici run remote`**, each named context maps to an orchestrator **
|
|
8384
|
+
- For a local **`kici run <event> --local`** (see [`kici run <event> --local`](https://docs.kici.dev/user/cli-reference/#kici-run-event---local)), each named context is resolved from your local secret files (`.kici/.secrets`, `.env.local`, `secrets.yaml`, and `--env` flags).
|
|
8385
|
+
- For **`kici run remote`**, each named context maps to an orchestrator **context**, and the orchestrator resolves that context's secrets for the run. The target context must be flagged `allowLocalExecution: true` — mapping a context to a missing or non-test context rejects the run (see [Secret contexts for testing](https://docs.kici.dev/user/testing-guide/#secret-contexts-for-testing) below).
|
|
8078
8386
|
|
|
8079
|
-
**A fixture `secrets:` mapping is fail-closed; a job's bound `
|
|
8387
|
+
**A fixture `secrets:` mapping is fail-closed; a job's bound `context:` is not.** The reject above applies only to the fixture `secrets:` mapping — an explicit request for that context's secrets. A job's own bound `context:` (`job('deploy', { context: 'production', … })`) is treated differently on a test run: if it resolves to a non-test or unconfigured context it is **skipped with a warning**, not rejected, so a job that deploys to production in real runs stays locally testable for its non-secret logic. `kici run remote` prints a warning naming the skipped context(s), and the dashboard run view shows the same notice. See [Skip-on-test](https://docs.kici.dev/user/contexts/#multiple-contexts-per-job) in the contexts guide.
|
|
8080
8388
|
|
|
8081
8389
|
### Async fixtures
|
|
8082
8390
|
|
|
@@ -8211,14 +8519,14 @@ The goal of the test-secret model is to let test runs reach **test-only credenti
|
|
|
8211
8519
|
|
|
8212
8520
|
### CLI-uploaded local secrets
|
|
8213
8521
|
|
|
8214
|
-
`kici run remote` collects the same local secret values that `kici run local` reads — `.kici/.secrets`, `.kici/.env.local`, `.kici/secrets.yaml`, and any `--env KEY=VALUE` flags — and uploads them **encrypted** to the orchestrator alongside the run. The orchestrator decrypts them only to inject them into the agent for that run; the control plane never sees the values.
|
|
8522
|
+
`kici run remote` collects the same local secret values that `kici run <event> --local` reads — `.kici/.secrets`, `.kici/.env.local`, `.kici/secrets.yaml`, and any `--env KEY=VALUE` flags — and uploads them **encrypted** to the orchestrator alongside the run. The orchestrator decrypts them only to inject them into the agent for that run; the control plane never sees the values.
|
|
8215
8523
|
|
|
8216
8524
|
```bash
|
|
8217
8525
|
# Provide an ad-hoc test value for a single remote run
|
|
8218
8526
|
kici run remote push-main --env KICI_DATABASE_URL=postgresql://localhost/test
|
|
8219
8527
|
```
|
|
8220
8528
|
|
|
8221
|
-
`--env` provides a **flat** per-run override; `--context <ctx>.<KEY>=<value>` is its sibling for a **namespaced** per-run override, placing the value under the named context `ctx`. Both are uploaded **encrypted** and follow the same precedence rule below — a CLI-supplied value wins over the orchestrator test-
|
|
8529
|
+
`--env` provides a **flat** per-run override; `--context <ctx>.<KEY>=<value>` is its sibling for a **namespaced** per-run override, placing the value under the named context `ctx`. Both are uploaded **encrypted** and follow the same precedence rule below — a CLI-supplied value wins over the orchestrator test-context secret on a key collision.
|
|
8222
8530
|
|
|
8223
8531
|
```bash
|
|
8224
8532
|
# Provide a namespaced per-run value under the 'db' context
|
|
@@ -8227,14 +8535,14 @@ kici run remote push-db --context db.KICI_DATABASE_URL=postgresql://localhost/te
|
|
|
8227
8535
|
|
|
8228
8536
|
Because these values originate on your machine, they are the natural place to put throwaway test credentials without touching any orchestrator-stored secret.
|
|
8229
8537
|
|
|
8230
|
-
### Orchestrator test-
|
|
8538
|
+
### Orchestrator test-context secrets
|
|
8231
8539
|
|
|
8232
8540
|
In addition to your uploaded values, the orchestrator resolves test-scoped secrets from its own store for a remote test run:
|
|
8233
8541
|
|
|
8234
|
-
- The job's own declared `
|
|
8235
|
-
- Each fixture `secrets: { ctx: envName }` mapping resolves the named
|
|
8542
|
+
- The job's own declared `context` contributes its resolved secrets (flat). Static strings and **pure dynamic functions** both participate: a pure `context:` function (see [Dynamic values](https://docs.kici.dev/user/dynamic-values/)) is evaluated against the fixture's simulated event, and the resolved name is gated and resolved like a static one. Impure dynamic functions (those requiring an init job) are not evaluated for test runs — use a fixture `secrets:` mapping (or `--context`) to supply such a job's secrets.
|
|
8543
|
+
- Each fixture `secrets: { ctx: envName }` mapping resolves the named context's secrets under the namespaced context `ctx`.
|
|
8236
8544
|
|
|
8237
|
-
Both paths are restricted to
|
|
8545
|
+
Both paths are restricted to contexts flagged `allowLocalExecution: true`. A production context left at the default `false` is never resolvable for a test run.
|
|
8238
8546
|
|
|
8239
8547
|
```typescript
|
|
8240
8548
|
export const pushWithDb = fixture('push-db', {
|
|
@@ -8252,31 +8560,31 @@ step('migrate', async (ctx) => {
|
|
|
8252
8560
|
|
|
8253
8561
|
### Precedence: CLI values win
|
|
8254
8562
|
|
|
8255
|
-
When a key exists in both sources, the **CLI-uploaded local value wins** over the orchestrator test-
|
|
8563
|
+
When a key exists in both sources, the **CLI-uploaded local value wins** over the orchestrator test-context value. This makes a local override a per-run knob: set `--env KICI_DATABASE_URL=...` (or put it in `.kici/.secrets`) to shadow the test context's value for just that run, without changing anything on the orchestrator.
|
|
8256
8564
|
|
|
8257
|
-
### Fail-closed on non-test
|
|
8565
|
+
### Fail-closed on non-test contexts
|
|
8258
8566
|
|
|
8259
8567
|
Test-run secret resolution is fail-closed:
|
|
8260
8568
|
|
|
8261
|
-
- If a fixture maps a context
|
|
8262
|
-
- If a fixture maps a context
|
|
8263
|
-
- The `allowLocalExecution` gate applies to **all** remote test runs: a run whose matched workflow targets
|
|
8569
|
+
- If a fixture maps to a context that does not exist, the run is **rejected**.
|
|
8570
|
+
- If a fixture maps to a context whose `allowLocalExecution` is `false`, the run is **rejected**.
|
|
8571
|
+
- The `allowLocalExecution` gate applies to **all** remote test runs: a run whose matched workflow targets a context with the flag off is rejected, so a test run can never resolve production secrets.
|
|
8264
8572
|
|
|
8265
|
-
### The `allowLocalExecution`
|
|
8573
|
+
### The `allowLocalExecution` context flag
|
|
8266
8574
|
|
|
8267
|
-
Each
|
|
8575
|
+
Each context carries an `allowLocalExecution` flag (default `false`) that controls test-run access to that context and to its secrets. Production contexts should leave it at `false`; create a dedicated test context with `allowLocalExecution: true` that binds only test-only secret scopes for the jobs you want test runs to use.
|
|
8268
8576
|
|
|
8269
8577
|
The flag is set by the orchestrator operator, either via the CLI:
|
|
8270
8578
|
|
|
8271
8579
|
```bash
|
|
8272
|
-
kici-admin
|
|
8580
|
+
kici-admin context set-policy --env test-database --allow-local-execution true
|
|
8273
8581
|
```
|
|
8274
8582
|
|
|
8275
|
-
or via the dashboard's "Test runs" toggle on the
|
|
8583
|
+
or via the dashboard's "Test runs" toggle on the context detail page. `kici secrets list` only surfaces contexts whose `allowLocalExecution` is `true`, so production contexts are never advertised as test-accessible.
|
|
8276
8584
|
|
|
8277
8585
|
### Local execution as an alternative
|
|
8278
8586
|
|
|
8279
|
-
`kici run local` resolves the same local secret files entirely on your machine and honors the fixture `secrets: { ... }` mapping to pick which local context backs each name (see [`kici run local`](https://docs.kici.dev/user/cli-reference/#kici-run-local)). Because the values never leave your machine, it's a good fit when you want to exercise secret-dependent steps without involving the orchestrator at all.
|
|
8587
|
+
`kici run <event> --local` resolves the same local secret files entirely on your machine and honors the fixture `secrets: { ... }` mapping to pick which local context backs each name (see [`kici run <event> --local`](https://docs.kici.dev/user/cli-reference/#kici-run-event---local)). Because the values never leave your machine, it's a good fit when you want to exercise secret-dependent steps without involving the orchestrator at all.
|
|
8280
8588
|
|
|
8281
8589
|
### Discovering available contexts
|
|
8282
8590
|
|
|
@@ -8491,7 +8799,7 @@ job('deploy', {
|
|
|
8491
8799
|
});
|
|
8492
8800
|
```
|
|
8493
8801
|
|
|
8494
|
-
`approval: true` holds the element until **any** org member who can act on approvals signs off — anyone with the `
|
|
8802
|
+
`approval: true` holds the element until **any** org member who can act on approvals signs off — anyone with the `contexts:write` or `ci_trust:write` permission. Use it when you want a manual gate without restricting who may release it.
|
|
8495
8803
|
|
|
8496
8804
|
### Approver list (AND)
|
|
8497
8805
|
|
|
@@ -8612,7 +8920,7 @@ A `when: 'drift'` gate on a step without a `check` facet, or at job/workflow sco
|
|
|
8612
8920
|
|
|
8613
8921
|
## Mandatory vs. explicit gates
|
|
8614
8922
|
|
|
8615
|
-
`approval` is the **explicit** gate — a deliberate "pause for a human here" written by the workflow author. It composes with the **mandatory** gate an operator can attach to a protected
|
|
8923
|
+
`approval` is the **explicit** gate — a deliberate "pause for a human here" written by the workflow author. It composes with the **mandatory** gate an operator can attach to a protected context via required reviewers (see [Contexts](https://docs.kici.dev/user/contexts/#required-reviewers)). When both apply to the same job, all clauses from both sources must be satisfied before the job is released. The two funnel into one held-element mechanism, so the dashboard queue and `kici approve` work the same way regardless of which source held the element.
|
|
8616
8924
|
|
|
8617
8925
|
## Approving from the CLI
|
|
8618
8926
|
|
|
@@ -8646,12 +8954,14 @@ kici run remote deploy-prod --approve-all
|
|
|
8646
8954
|
|
|
8647
8955
|
`--approve-all` is **run-scoped** — it only auto-approves holds belonging to the run this invocation dispatched; there is no fleet-wide or account-wide auto-approve. Eligibility is still enforced per hold: if you are not eligible for a gate, that gate still blocks. Each auto-approved gate prints its payload before resolving and is recorded distinctly in the audit trail (`held_run.auto_approve`).
|
|
8648
8956
|
|
|
8649
|
-
|
|
8957
|
+
`--approve-all` is honored in non-interactive runs too: with `--json` or `--quiet` (no TTY), the flag still auto-approves each eligible gate as it appears instead of hanging or printing out-of-band instructions. Hold notices are routed to stderr so `--json` stdout stays pure machine-readable output.
|
|
8958
|
+
|
|
8959
|
+
You can also approve from the dashboard approval queue. See [Dashboard](https://docs.kici.dev/user/dashboard/contexts-and-secrets/#approval-queue).
|
|
8650
8960
|
|
|
8651
8961
|
## See also
|
|
8652
8962
|
|
|
8653
8963
|
- [Idempotent steps](https://docs.kici.dev/user/idempotent-steps/) — the check/apply step facet that drift gates build on.
|
|
8654
|
-
- [
|
|
8964
|
+
- [Contexts](https://docs.kici.dev/user/contexts/) — operator-required reviewers on protected contexts.
|
|
8655
8965
|
- [Approval gates (operator guide)](https://docs.kici.dev/operator/approvals/) — teams, the approval queue, expiry, and self-approval.
|
|
8656
8966
|
- [Approval gates (architecture)](https://docs.kici.dev/architecture/approvals/) — the unified hold model and the step-level round-trip.
|
|
8657
8967
|
|
|
@@ -8713,7 +9023,7 @@ group: () => 'deploy';
|
|
|
8713
9023
|
group: (ctx) => `deploy-${ctx.event.targetBranch ?? 'default'}`;
|
|
8714
9024
|
```
|
|
8715
9025
|
|
|
8716
|
-
The workflow-level group function is always evaluated **agent-side** at runtime -- the lock file records only that a group function exists (`hasGroup: true`), not the function itself. The agent loads the workflow source, calls the group function with `{ branch, event }`, and reports the evaluated key back to the orchestrator before step execution begins. This differs from job-level `concurrencyGroup` (see [
|
|
9026
|
+
The workflow-level group function is always evaluated **agent-side** at runtime -- the lock file records only that a group function exists (`hasGroup: true`), not the function itself. The agent loads the workflow source, calls the group function with `{ branch, event }`, and reports the evaluated key back to the orchestrator before step execution begins. This differs from job-level `concurrencyGroup` (see [Contexts](https://docs.kici.dev/user/contexts/#concurrency-groups)), where the compiler performs purity analysis and can inline pure functions for orchestrator-side evaluation.
|
|
8717
9027
|
|
|
8718
9028
|
## cancelInProgress mode
|
|
8719
9029
|
|
|
@@ -8806,7 +9116,7 @@ workflow('deploy', {
|
|
|
8806
9116
|
jobs: [
|
|
8807
9117
|
job('deploy-staging', {
|
|
8808
9118
|
runsOn: 'linux',
|
|
8809
|
-
|
|
9119
|
+
context: 'staging',
|
|
8810
9120
|
steps: [
|
|
8811
9121
|
/* ... */
|
|
8812
9122
|
],
|
|
@@ -8837,284 +9147,62 @@ workflow('migrate', {
|
|
|
8837
9147
|
workflow('deploy', {
|
|
8838
9148
|
concurrency: {
|
|
8839
9149
|
group: (ctx) => {
|
|
8840
|
-
const env = ctx.branch === 'main' ? 'production' : 'staging';
|
|
8841
|
-
return `deploy-${env}`;
|
|
8842
|
-
},
|
|
8843
|
-
cancelInProgress: true,
|
|
8844
|
-
},
|
|
8845
|
-
jobs: [
|
|
8846
|
-
/* ... */
|
|
8847
|
-
],
|
|
8848
|
-
});
|
|
8849
|
-
```
|
|
8850
|
-
|
|
8851
|
-
## Interaction with environment protection
|
|
8852
|
-
|
|
8853
|
-
When a workflow has both `concurrency` and `environment` protection rules:
|
|
8854
|
-
|
|
8855
|
-
1. Environment protection gates (required reviewers, wait timer) apply first
|
|
8856
|
-
2. Concurrency group check happens after protection gates pass
|
|
8857
|
-
3. If the run is queued by concurrency, it keeps its protection approval
|
|
8858
|
-
|
|
8859
|
-
This means a run that passed approval won't need re-approval if it gets queued by concurrency.
|
|
8860
|
-
|
|
8861
|
-
## Cancelling queued runs
|
|
8862
|
-
|
|
8863
|
-
Queued runs can be cancelled before they start executing. The cancel request removes them from the queue immediately -- they don't go through the grace period since no step is running.
|
|
8864
|
-
|
|
8865
|
-
## Job-level concurrency groups
|
|
8866
|
-
|
|
8867
|
-
In addition to workflow-level concurrency, individual jobs can define their own concurrency group via the `concurrencyGroup` property. This controls concurrent execution at the job level rather than the workflow level. See [Environments — concurrency groups](https://docs.kici.dev/user/environments/#concurrency-groups) for details.
|
|
8868
|
-
|
|
8869
|
-
## Local execution
|
|
8870
|
-
|
|
8871
|
-
`kici run local` honors workflow-level `concurrency` per-machine, per-user. The `group` callback is evaluated against the simulated event identically to the remote orchestrator path; `cancelInProgress` carries the same semantics — `true` interrupts the holder via `SIGTERM` (escalating to `SIGKILL` after a grace window) and proceeds with the new run, while `false` queues the new invocation in FIFO order until the holder finishes.
|
|
8872
|
-
|
|
8873
|
-
Coordination is local only. Running the same workflow on two different machines does not serialize across them — that requires the orchestrator. For full cross-host enforcement (queueing across agents, dashboard visibility, `max > 1`), use `kici run remote` against a deployed orchestrator.
|
|
8874
|
-
|
|
8875
|
-
Lock files live under `$XDG_RUNTIME_DIR/kici-local-locks/` on Linux, falling back to `os.tmpdir()/kici-local-locks-<uid>/`. A workflow whose `group` callback throws aborts the run with a clear error rather than running unprotected. See [`kici run local` — Concurrency enforcement](https://docs.kici.dev/user/cli-reference/#concurrency-enforcement) for the `KICI_LOCAL_LOCK_KILL_GRACE_MS` override and the diagnostic output emitted while contending on a busy lock.
|
|
8876
|
-
|
|
8877
|
-
The `kici run local --concurrency <n>` flag is a separate concept — it caps **job-level** parallelism within a single run (how many jobs from one workflow run at once), not cross-run serialization.
|
|
8878
|
-
|
|
8879
|
-
---
|
|
8880
|
-
|
|
8881
|
-
_Source: `packages/sdk/src/types.ts` (WorkflowOptions.concurrency, JobOptions.concurrencyGroup)_
|
|
8882
|
-
|
|
8883
|
-
---
|
|
8884
|
-
|
|
8885
|
-
## Dashboard
|
|
8886
|
-
|
|
8887
|
-
Source: https://docs.kici.dev/user/dashboard/
|
|
8888
|
-
|
|
8889
|
-
The KiCI dashboard is the browser interface for monitoring workflow runs, inspecting jobs and logs, and managing your organization. It signs in via OIDC and talks to KiCI over its API.
|
|
8890
|
-
|
|
8891
|
-
This guide is split across the following pages:
|
|
8892
|
-
|
|
8893
|
-
| Page | Covers |
|
|
8894
|
-
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
8895
|
-
| [Getting started](https://docs.kici.dev/user/dashboard/getting-started/) | Onboarding checklist and your organizations list |
|
|
8896
|
-
| [Navigation and layout](https://docs.kici.dev/user/dashboard/navigation/) | Sidebar, mobile nav, theme, time display, shortcuts, error pages |
|
|
8897
|
-
| [Runs and logs](https://docs.kici.dev/user/dashboard/runs/) | Run list, run detail, the log viewer |
|
|
8898
|
-
| [Settings](https://docs.kici.dev/user/dashboard/settings/) | Members, roles, teams, keys, sources, billing, security, support access |
|
|
8899
|
-
| [Workflows, diagnostics, and orchestrators](https://docs.kici.dev/user/dashboard/workflows-and-diagnostics/) | Registered workflows, infra health, per-cluster views |
|
|
8900
|
-
| [Environments, secrets, and approvals](https://docs.kici.dev/user/dashboard/environments-and-secrets/) | Environments, secret scopes, approval queue |
|
|
8901
|
-
| [Activity and DLQ](https://docs.kici.dev/user/dashboard/activity-and-dlq/) | Forensic activity log and dead-letter queue |
|
|
8902
|
-
| [Account](https://docs.kici.dev/user/dashboard/account/) | Personal account settings |
|
|
8903
|
-
|
|
8904
|
-
---
|
|
8905
|
-
|
|
8906
|
-
## Dynamic values
|
|
8907
|
-
|
|
8908
|
-
Source: https://docs.kici.dev/user/dynamic-values/
|
|
8909
|
-
|
|
8910
|
-
Dynamic values let you compute `environment`, `env`, and `concurrencyGroup` at runtime based on the incoming event. Instead of hardcoding static strings, you pass a function that receives the normalized event envelope and returns the resolved value.
|
|
8911
|
-
|
|
8912
|
-
```typescript
|
|
8913
|
-
job('deploy', {
|
|
8914
|
-
runsOn: ['default'],
|
|
8915
|
-
environment: (event) => event.targetBranch,
|
|
8916
|
-
env: (event) => ({ BRANCH: event.targetBranch }),
|
|
8917
|
-
concurrencyGroup: (event) => `deploy-${event.targetBranch}`,
|
|
8918
|
-
steps: [
|
|
8919
|
-
/* ... */
|
|
8920
|
-
],
|
|
8921
|
-
});
|
|
8922
|
-
```
|
|
8923
|
-
|
|
8924
|
-
```typescript
|
|
8925
|
-
job('deploy', {
|
|
8926
|
-
runsOn: 'default',
|
|
8927
|
-
// One shape everywhere: branch on the normalized event type.
|
|
8928
|
-
environment: (event) => (event.type === 'pull_request' ? 'preview' : 'production'),
|
|
8929
|
-
steps: [
|
|
8930
|
-
/* ... */
|
|
8931
|
-
],
|
|
8932
|
-
});
|
|
8933
|
-
```
|
|
8934
|
-
|
|
8935
|
-
## How it works
|
|
8936
|
-
|
|
8937
|
-
When you define a dynamic value as a function, the compiler analyzes it at compile time to determine whether it is **pure** (can be evaluated without cloning the repo or running an init job).
|
|
8938
|
-
|
|
8939
|
-
### Pure functions (inline evaluation)
|
|
8940
|
-
|
|
8941
|
-
A pure function is one that:
|
|
8942
|
-
|
|
8943
|
-
- Is synchronous (no `async`/`await`)
|
|
8944
|
-
- Only references its parameters and local variables
|
|
8945
|
-
- Does not import or require external modules
|
|
8946
|
-
- Does not access globals like `process`, `fetch`, `console`, `setTimeout`, etc.
|
|
8947
|
-
- Uses only safe built-in constructors: `String`, `Number`, `Boolean`, `Array`, `Object`, `JSON`, `Math`, `parseInt`, `parseFloat`, `isNaN`, `isFinite`, `encodeURIComponent`, `decodeURIComponent`, `encodeURI`, `decodeURI`
|
|
8948
|
-
- Does not use `this`, `new`, `class`, `throw`, `try`/`catch`, `delete`, `var`, `yield`, or mutation operators (`++`, `--`, `+=`, etc.)
|
|
8949
|
-
|
|
8950
|
-
When the compiler detects a pure function, it serializes the function source directly into the lock file as an inline expression. At dispatch time, the orchestrator evaluates the expression in a sandboxed VM context (~0ms overhead) instead of dispatching an init job.
|
|
8951
|
-
|
|
8952
|
-
**Examples of pure functions:**
|
|
8953
|
-
|
|
8954
|
-
```typescript
|
|
8955
|
-
// Simple branch extraction
|
|
8956
|
-
environment: (event) => event.targetBranch;
|
|
8957
|
-
|
|
8958
|
-
// Object literal with string operations
|
|
8959
|
-
env: (event) => ({ BRANCH: event.targetBranch });
|
|
8960
|
-
|
|
8961
|
-
// Concatenation with event data
|
|
8962
|
-
concurrencyGroup: (event) => `deploy-${event.targetBranch}`;
|
|
8963
|
-
|
|
8964
|
-
// Using safe globals
|
|
8965
|
-
env: (event) => ({ UPPER: String(event.targetBranch).toUpperCase() });
|
|
8966
|
-
|
|
8967
|
-
// Local variables are fine
|
|
8968
|
-
environment: (event) => {
|
|
8969
|
-
const parts = event.targetBranch.split('/');
|
|
8970
|
-
return parts[parts.length - 1];
|
|
8971
|
-
};
|
|
8972
|
-
```
|
|
8973
|
-
|
|
8974
|
-
### Impure functions (init-job evaluation)
|
|
8975
|
-
|
|
8976
|
-
If the compiler determines a function is impure, it emits a warning during compilation and falls back to the two-phase init model. This means:
|
|
8977
|
-
|
|
8978
|
-
1. The orchestrator dispatches a special `__init__` job to a builder agent
|
|
8979
|
-
2. The builder agent clones the repository and evaluates the function
|
|
8980
|
-
3. The resolved values are sent back to the orchestrator
|
|
8981
|
-
4. The orchestrator dispatches the real execution job with the resolved values
|
|
8982
|
-
|
|
8983
|
-
This adds approximately 5-10 seconds of overhead for cloning and evaluation.
|
|
8984
|
-
|
|
8985
|
-
**Examples of impure functions (will use init job):**
|
|
8986
|
-
|
|
8987
|
-
```typescript
|
|
8988
|
-
// Async functions cannot be inlined
|
|
8989
|
-
environment: async (event) => await lookupEnv(event.targetBranch);
|
|
8990
|
-
|
|
8991
|
-
// External module references
|
|
8992
|
-
env: (event) => {
|
|
8993
|
-
const config = require('./config');
|
|
8994
|
-
return config.env;
|
|
8995
|
-
};
|
|
8996
|
-
|
|
8997
|
-
// Process/global access
|
|
8998
|
-
environment: (event) => process.env.DEFAULT_ENV || 'staging';
|
|
8999
|
-
|
|
9000
|
-
// Dynamic imports
|
|
9001
|
-
env: async (event) => {
|
|
9002
|
-
const m = await import('./config.js');
|
|
9003
|
-
return m.default;
|
|
9004
|
-
};
|
|
9005
|
-
```
|
|
9006
|
-
|
|
9007
|
-
## Performance comparison
|
|
9008
|
-
|
|
9009
|
-
| Evaluation path | Overhead | When used |
|
|
9010
|
-
| ------------------------------------ | -------- | ------------------------------------------------------------------- |
|
|
9011
|
-
| Static value (string/object literal) | ~0ms | `environment: 'staging'` |
|
|
9012
|
-
| Inline expression (pure function) | ~0ms | `environment: (event) => event.targetBranch` |
|
|
9013
|
-
| Init job (impure function) | ~5-10s | `environment: async (event) => await lookupEnv(event.targetBranch)` |
|
|
9014
|
-
|
|
9015
|
-
## Tips
|
|
9016
|
-
|
|
9017
|
-
- **Write pure functions whenever possible** to avoid the init-job delay. Most environment and env computations only need the event payload data.
|
|
9018
|
-
- **Check compiler warnings** -- the compiler tells you when a function is classified as impure and explains why.
|
|
9019
|
-
- **Runtime errors in inline expressions cause immediate job failure.** There is no fallback to the init-job path. If your pure function throws at runtime (e.g., accessing a property on `undefined`), the job fails immediately.
|
|
9020
|
-
- **The event parameter is the normalized event envelope** — the same shape rules receive as `ctx.event`: `{ type, action, targetBranch, sourceBranch, changedFiles, payload, … }` (see the [event payload reference](https://docs.kici.dev/user/sdk/event-payloads/) for the complete schema). Narrow on `event.type` (`'push'`, `'pull_request'`, `'tag'`, …) to branch per trigger kind. The raw provider webhook body is nested at `event.payload` (for GitHub pushes: `payload.ref`, `payload.after`, `payload.repository`, …).
|
|
9021
|
-
|
|
9022
|
-
---
|
|
9023
|
-
|
|
9024
|
-
## Environment variables
|
|
9025
|
-
|
|
9026
|
-
Source: https://docs.kici.dev/user/env-vars/
|
|
9027
|
-
|
|
9028
|
-
The KiCI CLI reads the following environment variables to customize its behavior. OAuth login (`kici login` without `--token`) defaults `KICI_PLATFORM_URL`, `KICI_OIDC_ISSUER`, and `KICI_OIDC_CLIENT_ID` to the hosted KiCI Platform, so `kici login` works with no configuration. Set them only to target another KiCI environment (e.g. a testing instance) or a custom OIDC provider.
|
|
9029
|
-
|
|
9030
|
-
## Authentication
|
|
9031
|
-
|
|
9032
|
-
| Variable | Description | Default |
|
|
9033
|
-
| --------------------- | -------------------------------------- | -------------------------------------------- |
|
|
9034
|
-
| `KICI_OIDC_ISSUER` | OIDC issuer URL for authentication | `https://auth.kici.dev/realms/kici-internal` |
|
|
9035
|
-
| `KICI_OIDC_CLIENT_ID` | OIDC client ID for the CLI application | `kici-cli` |
|
|
9036
|
-
| `KICI_PLATFORM_URL` | Platform API base URL | `https://api.kici.dev` |
|
|
9037
|
-
| `KICI_CONFIG_DIR` | Override the KiCI config directory | `~/.kici` |
|
|
9038
|
-
|
|
9039
|
-
## Browser behavior
|
|
9040
|
-
|
|
9041
|
-
| Variable | Description | Default |
|
|
9042
|
-
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
9043
|
-
| `KICI_BROWSER_CMD` | Custom browser command for OAuth login. Supports `{url}` placeholder. Set to `none` to suppress browser opening and print the URL to stdout instead. | Uses the system default browser via the `open` package |
|
|
9044
|
-
| `KICI_CALLBACK_PORT` | Fixed port for the OAuth PKCE callback server. Useful when firewall rules require a known port. | Random available port |
|
|
9045
|
-
|
|
9046
|
-
## Development
|
|
9047
|
-
|
|
9048
|
-
| Variable | Description | Default |
|
|
9049
|
-
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
9050
|
-
| `KICI_DEV` | Enable development mode. When `true`, uses prerelease-compatible version ranges (`>=0.0.1-0`) for dev dependencies and skips npm version resolution. | unset |
|
|
9051
|
-
| `KICI_DEBUG` | Enable debug logging. When `true`, prints verbose diagnostics (SDK alias resolution, step-level debug logs, stack traces on errors). Equivalent to the `--debug` CLI flag. | unset |
|
|
9052
|
-
|
|
9053
|
-
## Usage examples
|
|
9054
|
-
|
|
9055
|
-
### CI/CD environment
|
|
9056
|
-
|
|
9057
|
-
Authenticate with a pre-existing API key (no browser needed):
|
|
9058
|
-
|
|
9059
|
-
```bash
|
|
9060
|
-
kici login --token <<< "$KICI_API_KEY"
|
|
9150
|
+
const env = ctx.branch === 'main' ? 'production' : 'staging';
|
|
9151
|
+
return `deploy-${env}`;
|
|
9152
|
+
},
|
|
9153
|
+
cancelInProgress: true,
|
|
9154
|
+
},
|
|
9155
|
+
jobs: [
|
|
9156
|
+
/* ... */
|
|
9157
|
+
],
|
|
9158
|
+
});
|
|
9061
9159
|
```
|
|
9062
9160
|
|
|
9063
|
-
|
|
9161
|
+
## Interaction with context protection
|
|
9064
9162
|
|
|
9065
|
-
|
|
9163
|
+
When a workflow has both `concurrency` and `context` protection rules:
|
|
9066
9164
|
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
export KICI_PLATFORM_URL=https://your-platform.example.com
|
|
9071
|
-
kici login
|
|
9072
|
-
```
|
|
9165
|
+
1. Context protection gates (required reviewers, wait timer) apply first
|
|
9166
|
+
2. Concurrency group check happens after protection gates pass
|
|
9167
|
+
3. If the run is queued by concurrency, it keeps its protection approval
|
|
9073
9168
|
|
|
9074
|
-
|
|
9169
|
+
This means a run that passed approval won't need re-approval if it gets queued by concurrency.
|
|
9075
9170
|
|
|
9076
|
-
|
|
9171
|
+
## Cancelling queued runs
|
|
9077
9172
|
|
|
9078
|
-
|
|
9079
|
-
export KICI_BROWSER_CMD=none
|
|
9080
|
-
kici login
|
|
9081
|
-
```
|
|
9173
|
+
Queued runs can be cancelled before they start executing. The cancel request removes them from the queue immediately -- they don't go through the grace period since no step is running.
|
|
9082
9174
|
|
|
9083
|
-
|
|
9175
|
+
## Job-level concurrency groups
|
|
9084
9176
|
|
|
9085
|
-
|
|
9177
|
+
In addition to workflow-level concurrency, individual jobs can define their own concurrency group via the `concurrencyGroup` property. This controls concurrent execution at the job level rather than the workflow level. See [Contexts — concurrency groups](https://docs.kici.dev/user/contexts/#concurrency-groups) for details.
|
|
9086
9178
|
|
|
9087
|
-
|
|
9179
|
+
## Local execution
|
|
9088
9180
|
|
|
9089
|
-
|
|
9090
|
-
export KICI_CALLBACK_PORT=19876
|
|
9091
|
-
kici login
|
|
9092
|
-
```
|
|
9181
|
+
`kici run <event> --local` honors workflow-level `concurrency` per-machine, per-user. The `group` callback is evaluated against the simulated event identically to the remote orchestrator path; `cancelInProgress` carries the same semantics — `true` interrupts the holder via `SIGTERM` (escalating to `SIGKILL` after a grace window) and proceeds with the new run, while `false` queues the new invocation in FIFO order until the holder finishes.
|
|
9093
9182
|
|
|
9094
|
-
|
|
9183
|
+
Coordination is local only. Running the same workflow on two different machines does not serialize across them — that requires the orchestrator. For full cross-host enforcement (queueing across agents, dashboard visibility, `max > 1`), use `kici run remote` against a deployed orchestrator.
|
|
9095
9184
|
|
|
9096
|
-
|
|
9185
|
+
Lock files live under `$XDG_RUNTIME_DIR/kici-local-locks/` on Linux, falling back to `os.tmpdir()/kici-local-locks-<uid>/`. A workflow whose `group` callback throws aborts the run with a clear error rather than running unprotected. See [`kici run <event> --local` — Concurrency enforcement](https://docs.kici.dev/user/cli-reference/#concurrency-enforcement) for the `KICI_LOCAL_LOCK_KILL_GRACE_MS` override and the diagnostic output emitted while contending on a busy lock.
|
|
9097
9186
|
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
```
|
|
9187
|
+
---
|
|
9188
|
+
|
|
9189
|
+
_Source: `packages/sdk/src/types.ts` (WorkflowOptions.concurrency, JobOptions.concurrencyGroup)_
|
|
9102
9190
|
|
|
9103
9191
|
---
|
|
9104
9192
|
|
|
9105
|
-
##
|
|
9193
|
+
## Contexts
|
|
9106
9194
|
|
|
9107
|
-
Source: https://docs.kici.dev/user/
|
|
9195
|
+
Source: https://docs.kici.dev/user/contexts/
|
|
9108
9196
|
|
|
9109
|
-
<!-- help:
|
|
9197
|
+
<!-- help:contexts-list#overview -->
|
|
9110
9198
|
|
|
9111
|
-
|
|
9199
|
+
Contexts are named deployment targets (like staging or production) that control where your workflow jobs run. Each context can have its own variables, secrets, and protection rules to gate deployments.
|
|
9112
9200
|
|
|
9113
|
-
<!-- /help:
|
|
9201
|
+
<!-- /help:contexts-list -->
|
|
9114
9202
|
|
|
9115
|
-
<!-- help:
|
|
9203
|
+
<!-- help:contexts-protection#protection-rules -->
|
|
9116
9204
|
|
|
9117
|
-
Protection rules control when jobs targeting
|
|
9205
|
+
Protection rules control when jobs targeting a context can execute.
|
|
9118
9206
|
|
|
9119
9207
|
Available rules:
|
|
9120
9208
|
|
|
@@ -9123,24 +9211,24 @@ Available rules:
|
|
|
9123
9211
|
- **Wait timers** — delay execution for a fixed period.
|
|
9124
9212
|
- **Concurrency limits** — prevent collisions between parallel deployments.
|
|
9125
9213
|
|
|
9126
|
-
<!-- /help:
|
|
9214
|
+
<!-- /help:contexts-protection -->
|
|
9127
9215
|
|
|
9128
|
-
|
|
9216
|
+
Contexts represent deployment targets like `staging`, `production`, or `review/PR-*`. Each context can have its own variables, bound secrets, and protection rules that control when and how jobs targeting that context can execute.
|
|
9129
9217
|
|
|
9130
9218
|
## Overview
|
|
9131
9219
|
|
|
9132
|
-
|
|
9220
|
+
A context in KiCI provides:
|
|
9133
9221
|
|
|
9134
9222
|
- **Variables** -- non-secret key-value configuration (e.g., `API_URL`, `CLUSTER_NAME`)
|
|
9135
|
-
- **Scoped secrets** -- encrypted values bound to the
|
|
9223
|
+
- **Scoped secrets** -- encrypted values bound to the context via scope bindings
|
|
9136
9224
|
- **Protection rules** -- branch restrictions, required reviewers, wait timers, and concurrency limits
|
|
9137
9225
|
- **Per-source overrides** -- repositories can override unlocked variables for their own deployments
|
|
9138
9226
|
|
|
9139
9227
|
## SDK API
|
|
9140
9228
|
|
|
9141
|
-
### Job-level
|
|
9229
|
+
### Job-level context property
|
|
9142
9230
|
|
|
9143
|
-
The `
|
|
9231
|
+
The `context` property is set on a job, not a workflow or step:
|
|
9144
9232
|
|
|
9145
9233
|
```typescript
|
|
9146
9234
|
import { workflow, job, step, push } from '@kici-dev/sdk';
|
|
@@ -9150,16 +9238,16 @@ export default workflow('deploy', {
|
|
|
9150
9238
|
jobs: [
|
|
9151
9239
|
job('deploy-staging', {
|
|
9152
9240
|
runsOn: 'default',
|
|
9153
|
-
|
|
9241
|
+
context: 'staging',
|
|
9154
9242
|
steps: [
|
|
9155
9243
|
step('deploy', async (ctx) => {
|
|
9156
|
-
// ctx.
|
|
9157
|
-
console.log(`Deploying to ${ctx.
|
|
9158
|
-
// ctx.secrets provides async get/expose/has methods for
|
|
9244
|
+
// ctx.context is the resolved context name
|
|
9245
|
+
console.log(`Deploying to ${ctx.context}`);
|
|
9246
|
+
// ctx.secrets provides async get/expose/has methods for context-bound secrets
|
|
9159
9247
|
const dbPassword = await ctx.secrets.get('DB_PASSWORD');
|
|
9160
9248
|
// Environment variables are in ctx.env
|
|
9161
9249
|
const apiUrl = ctx.env.API_URL;
|
|
9162
|
-
await ctx.$`deploy --target ${ctx.
|
|
9250
|
+
await ctx.$`deploy --target ${ctx.context}`;
|
|
9163
9251
|
}),
|
|
9164
9252
|
],
|
|
9165
9253
|
}),
|
|
@@ -9167,54 +9255,54 @@ export default workflow('deploy', {
|
|
|
9167
9255
|
});
|
|
9168
9256
|
```
|
|
9169
9257
|
|
|
9170
|
-
### Dynamic
|
|
9258
|
+
### Dynamic contexts
|
|
9171
9259
|
|
|
9172
|
-
The
|
|
9260
|
+
The context name can be a string or a function (sync or async) for dynamic contexts (e.g., per-PR review contexts). The function receives the normalized event envelope, with the raw provider body nested at `event.payload`:
|
|
9173
9261
|
|
|
9174
9262
|
```typescript
|
|
9175
9263
|
job('deploy-review', {
|
|
9176
9264
|
runsOn: 'default',
|
|
9177
|
-
|
|
9265
|
+
context: (event) => `review/PR-${event.payload.pull_request.number}`,
|
|
9178
9266
|
steps: [
|
|
9179
9267
|
step('deploy', async (ctx) => {
|
|
9180
|
-
// ctx.
|
|
9181
|
-
await ctx.$`deploy-preview --env ${ctx.
|
|
9268
|
+
// ctx.context is 'review/PR-123' (resolved at runtime)
|
|
9269
|
+
await ctx.$`deploy-preview --env ${ctx.context}`;
|
|
9182
9270
|
}),
|
|
9183
9271
|
],
|
|
9184
9272
|
});
|
|
9185
9273
|
```
|
|
9186
9274
|
|
|
9187
|
-
A pure function like the one above (see [Dynamic values](https://docs.kici.dev/user/dynamic-values/)) is evaluated inline at dispatch with no init-job overhead. Dynamic
|
|
9275
|
+
A pure function like the one above (see [Dynamic values](https://docs.kici.dev/user/dynamic-values/)) is evaluated inline at dispatch with no init-job overhead. Dynamic contexts that match a glob pattern (e.g., `review/*`) inherit the pattern's configuration, variables, and protection rules.
|
|
9188
9276
|
|
|
9189
|
-
### Multiple
|
|
9277
|
+
### Multiple contexts per job
|
|
9190
9278
|
|
|
9191
|
-
A job can bind more than one
|
|
9279
|
+
A job can bind more than one context with `contexts`, an ordered array. This lets a single job draw secrets and variables from several contexts at once — for example a shared `staging` context plus a `my-testing` context that carries test-only variables:
|
|
9192
9280
|
|
|
9193
9281
|
```typescript
|
|
9194
9282
|
job('deploy', {
|
|
9195
9283
|
runsOn: 'default',
|
|
9196
|
-
|
|
9284
|
+
contexts: ['staging', 'my-testing'],
|
|
9197
9285
|
steps: [
|
|
9198
9286
|
step('deploy', async (ctx) => {
|
|
9199
|
-
// ctx.secrets and ctx.env carry the merged set from both
|
|
9287
|
+
// ctx.secrets and ctx.env carry the merged set from both contexts
|
|
9200
9288
|
const dbUrl = await ctx.secrets.get('DB_URL');
|
|
9201
9289
|
}),
|
|
9202
9290
|
],
|
|
9203
9291
|
});
|
|
9204
9292
|
```
|
|
9205
9293
|
|
|
9206
|
-
- `
|
|
9207
|
-
- Each array entry is a static name or a function of the event, resolved per element exactly like a single dynamic
|
|
9294
|
+
- `context` (singular) and `contexts` (array) are mutually exclusive — setting both is a compile error. `context: 'staging'` is exactly equivalent to `contexts: ['staging']`.
|
|
9295
|
+
- Each array entry is a static name or a function of the event, resolved per element exactly like a single dynamic context.
|
|
9208
9296
|
|
|
9209
|
-
**Merge order — last wins.** All bound
|
|
9297
|
+
**Merge order — last wins.** All bound contexts are resolved on every dispatch (webhook, scheduled, and test runs alike) and merged in array order. When the same secret or variable key is defined in more than one context, the later entry in the array wins. With `contexts: ['staging', 'my-testing']`, a key defined in both resolves to `my-testing`'s value; keys defined in only one are preserved. The longest-scope-path-wins rule still applies _within_ each context.
|
|
9210
9298
|
|
|
9211
|
-
**Protection rules combine all-must-pass.** A job must satisfy **every** bound
|
|
9299
|
+
**Protection rules combine all-must-pass.** A job must satisfy **every** bound context's gates — adding a context can never loosen access. Branch restrictions, trigger-type filters, and repo patterns must pass for all contexts; the minimum trust tier is the most restrictive across them; required reviewers are the union of all contexts' reviewers; the wait timer is the longest; and the hold expiry is the shortest. If a run is gated out, the rejection names which context and which rule rejected it (visible via `kici runs show <run-id>` and the run's rejection reason), so a mutually-exclusive set of rules surfaces as a clear failure rather than a silent perpetual rejection.
|
|
9212
9300
|
|
|
9213
|
-
**Skip-on-test (allow-and-warn).** On a test or local run (`kici run remote`, `kici run local`), a bound
|
|
9301
|
+
**Skip-on-test (allow-and-warn).** On a test or local run (`kici run remote`, `kici run <event> --local`), a bound context never rejects the run. Any bound context that disallows local execution (`allowLocalExecution: false`) — or that is not configured — is **skipped**: its variables and secrets are omitted from the merge and its gates are not evaluated. The run proceeds, and a user-visible warning naming the skipped context(s) is shown both on the `kici run remote` CLI output and on the dashboard run view. This makes the test-only-variables pattern work: with `contexts: ['staging', 'my-testing']` where only `my-testing` allows local execution, a test run resolves just `my-testing`'s variables and warns that `staging` was skipped. If every bound context is skipped, the job runs with no environment variables. This is intentionally different from a fixture `secrets:` mapping, which is fail-closed — see the [testing guide](https://docs.kici.dev/user/testing-guide/).
|
|
9214
9302
|
|
|
9215
|
-
**Unconfigured
|
|
9303
|
+
**Unconfigured contexts contribute nothing at dispatch.** At dispatch time a bound context name with no matching configured context (and no matching glob context) simply adds no variables, secrets, or protection rules — the job still runs, exactly as a single dynamic context resolving to an as-yet-unconfigured name does today.
|
|
9216
9304
|
|
|
9217
|
-
**Registration rejects a provably-unsatisfiable binding.** When a workflow is registered, KiCI statically checks every multi-
|
|
9305
|
+
**Registration rejects a provably-unsatisfiable binding.** When a workflow is registered, KiCI statically checks every multi-context binding: a bound context that does not exist, a disabled one, or two contexts with mutually-exclusive fixed branch / trigger-type / repository restrictions (no value can satisfy both) makes the binding provably unsatisfiable, and the registration is rejected with a precise message naming the job, the contexts, and the rule — for example `unsatisfiable context binding: job 'deploy' binds contexts [staging, my-testing] with mutually exclusive branch restrictions (no value satisfies all bound contexts)`. Bindings whose restrictions use globs are undecidable at registration and fall through to the dispatch-time gate check instead.
|
|
9218
9306
|
|
|
9219
9307
|
### Job-level environment variables
|
|
9220
9308
|
|
|
@@ -9223,7 +9311,7 @@ The `env` property on a job provides static or dynamic environment variables:
|
|
|
9223
9311
|
```typescript
|
|
9224
9312
|
job('deploy', {
|
|
9225
9313
|
runsOn: 'default',
|
|
9226
|
-
|
|
9314
|
+
context: 'production',
|
|
9227
9315
|
env: { DEPLOY_TARGET: 'us-east-1' },
|
|
9228
9316
|
// Or dynamic:
|
|
9229
9317
|
// env: (event) => ({ DEPLOY_SHA: event.payload.after?.slice(0, 7) }),
|
|
@@ -9238,14 +9326,14 @@ job('deploy', {
|
|
|
9238
9326
|
|
|
9239
9327
|
### Concurrency groups
|
|
9240
9328
|
|
|
9241
|
-
Jobs can define their own concurrency groups to control concurrent execution within
|
|
9329
|
+
Jobs can define their own concurrency groups to control concurrent execution within a context. For workflow-level concurrency (which applies to all jobs in a workflow), see [Concurrency groups](https://docs.kici.dev/user/concurrency/).
|
|
9242
9330
|
|
|
9243
|
-
Control concurrent deployments to the same
|
|
9331
|
+
Control concurrent deployments to the same context:
|
|
9244
9332
|
|
|
9245
9333
|
```typescript
|
|
9246
9334
|
job('deploy', {
|
|
9247
9335
|
runsOn: 'default',
|
|
9248
|
-
|
|
9336
|
+
context: 'production',
|
|
9249
9337
|
concurrencyGroup: 'production-api',
|
|
9250
9338
|
// Or dynamic:
|
|
9251
9339
|
// concurrencyGroup: (event) => `review-${event.payload.pull_request.number}`,
|
|
@@ -9255,17 +9343,17 @@ job('deploy', {
|
|
|
9255
9343
|
});
|
|
9256
9344
|
```
|
|
9257
9345
|
|
|
9258
|
-
If no `concurrencyGroup` is specified, the
|
|
9346
|
+
If no `concurrencyGroup` is specified, the context name is used as the default concurrency group. For a job bound to multiple contexts, the default is the **first** bound context's name.
|
|
9259
9347
|
|
|
9260
9348
|
### Step context
|
|
9261
9349
|
|
|
9262
9350
|
Inside a step, the `ctx` object provides:
|
|
9263
9351
|
|
|
9264
|
-
| Property
|
|
9265
|
-
|
|
|
9266
|
-
| `ctx.
|
|
9267
|
-
| `ctx.env`
|
|
9268
|
-
| `ctx.secrets`
|
|
9352
|
+
| Property | Type | Description |
|
|
9353
|
+
| ------------- | ------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
9354
|
+
| `ctx.context` | `string \| undefined` | Resolved context name (undefined for jobs without context) |
|
|
9355
|
+
| `ctx.env` | `Record<string, string \| undefined>` | Environment variables (merged from system, org, source, and job-level `env`) |
|
|
9356
|
+
| `ctx.secrets` | `StepSecretsTyped` | Async accessor for bound secrets (get, expose, has, getMeta, list, mountFile, exposeFile) |
|
|
9269
9357
|
|
|
9270
9358
|
| Method | Returns | Description |
|
|
9271
9359
|
| -------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -9282,25 +9370,25 @@ The full secrets API — including `SecretFileOptions`, log masking, and the can
|
|
|
9282
9370
|
|
|
9283
9371
|
## Environment variable merge precedence
|
|
9284
9372
|
|
|
9285
|
-
When a job targets
|
|
9373
|
+
When a job targets a context, variables are merged in this order (last wins):
|
|
9286
9374
|
|
|
9287
9375
|
1. **Allowed system vars** -- `PATH`, `HOME`, etc. from the agent process
|
|
9288
9376
|
2. **Sandbox defaults** -- `FORCE_COLOR=1`
|
|
9289
9377
|
3. **KICI\_\* system vars** -- orchestrator-generated metadata
|
|
9290
|
-
4. **Org-level
|
|
9378
|
+
4. **Org-level context vars** -- from the dashboard, managed per-context
|
|
9291
9379
|
5. **Source-level overrides** -- per-repository overrides (skips locked vars)
|
|
9292
9380
|
6. **Job env** -- from the `env` property in the SDK
|
|
9293
9381
|
7. **`setEnv()` calls** -- runtime modifications within steps
|
|
9294
9382
|
|
|
9295
|
-
> **Note:** Secrets are NOT part of the environment variable merge. They are delivered to the step context via IPC and accessed through `ctx.secrets`, not through `process.env`. See the [step context](https://docs.kici.dev/user/
|
|
9383
|
+
> **Note:** Secrets are NOT part of the environment variable merge. They are delivered to the step context via IPC and accessed through `ctx.secrets`, not through `process.env`. See the [step context](https://docs.kici.dev/user/contexts/#step-context) section above.
|
|
9296
9384
|
|
|
9297
9385
|
## Protection rules
|
|
9298
9386
|
|
|
9299
|
-
|
|
9387
|
+
Contexts can have protection rules that gate job execution:
|
|
9300
9388
|
|
|
9301
9389
|
### Branch restrictions
|
|
9302
9390
|
|
|
9303
|
-
Limit which branches can deploy to
|
|
9391
|
+
Limit which branches can deploy to a context:
|
|
9304
9392
|
|
|
9305
9393
|
```
|
|
9306
9394
|
Allowed branches: main, release/*
|
|
@@ -9357,7 +9445,7 @@ See the [CI security architecture docs](https://docs.kici.dev/architecture/secur
|
|
|
9357
9445
|
|
|
9358
9446
|
### Security approval queue
|
|
9359
9447
|
|
|
9360
|
-
When a PR is held for security review (unknown contributor, workflow modification, or trust policy violation), it enters the security approval queue. This is separate from
|
|
9448
|
+
When a PR is held for security review (unknown contributor, workflow modification, or trust policy violation), it enters the security approval queue. This is separate from context-level approval queues.
|
|
9361
9449
|
|
|
9362
9450
|
Held runs can be approved:
|
|
9363
9451
|
|
|
@@ -9368,7 +9456,7 @@ Security holds expire after a configurable timeout (default 1 hour).
|
|
|
9368
9456
|
|
|
9369
9457
|
### Concurrency limits
|
|
9370
9458
|
|
|
9371
|
-
Control how many jobs can run simultaneously in
|
|
9459
|
+
Control how many jobs can run simultaneously in a context:
|
|
9372
9460
|
|
|
9373
9461
|
```
|
|
9374
9462
|
Concurrency limit: 1
|
|
@@ -9380,18 +9468,18 @@ Strategy: queue (or cancel-pending)
|
|
|
9380
9468
|
|
|
9381
9469
|
## Dashboard management
|
|
9382
9470
|
|
|
9383
|
-
### Creating
|
|
9471
|
+
### Creating contexts
|
|
9384
9472
|
|
|
9385
|
-
Navigate to **Settings >
|
|
9473
|
+
Navigate to **Settings > Contexts** in the dashboard. Click **New context** to choose the context name and type (Fixed or Glob).
|
|
9386
9474
|
|
|
9387
|
-
- **Fixed** -- applies to jobs that declare exactly this
|
|
9388
|
-
- **Glob** -- applies to any
|
|
9475
|
+
- **Fixed** -- applies to jobs that declare exactly this context name, like `staging` or `production`
|
|
9476
|
+
- **Glob** -- applies to any context name a job declares that matches the pattern, e.g. `review/*` matches a job with `context: 'review/PR-123'`
|
|
9389
9477
|
|
|
9390
|
-
The
|
|
9478
|
+
The contexts list shows each context's type, whether test runs may use it (the `allowLocalExecution` flag -- see the [testing guide](https://docs.kici.dev/user/testing-guide/)), and whether it is enabled.
|
|
9391
9479
|
|
|
9392
|
-
###
|
|
9480
|
+
### Context detail page
|
|
9393
9481
|
|
|
9394
|
-
Each
|
|
9482
|
+
Each context has four tabs:
|
|
9395
9483
|
|
|
9396
9484
|
1. **Variables** -- manage key-value pairs with lock toggles. Locked variables cannot be overridden by source-level overrides. Source overrides are managed in a sub-tab.
|
|
9397
9485
|
|
|
@@ -9399,26 +9487,26 @@ Each environment has four tabs:
|
|
|
9399
9487
|
|
|
9400
9488
|
3. **Protection** -- configure branch restrictions, required reviewers, wait timers, and concurrency limits with enable toggles for each section.
|
|
9401
9489
|
|
|
9402
|
-
4. **History** -- view filtered runs targeting this
|
|
9490
|
+
4. **History** -- view filtered runs targeting this context.
|
|
9403
9491
|
|
|
9404
|
-
### Bound
|
|
9492
|
+
### Bound contexts on runs
|
|
9405
9493
|
|
|
9406
|
-
A job's bound deployment
|
|
9494
|
+
A job's bound deployment contexts are shown as chips on the run detail page (in the job metadata panel) in the order the job declared them, and the distinct set across a run's jobs appears as compact chips on the run list. For a multi-context job the chips read left-to-right in merge order — later contexts override earlier ones on key collisions. A `(dynamic)` chip marks a context whose name is computed at runtime; it resolves to the real name once the run starts. A job that binds a single context shows one chip; a job that binds none shows no chip.
|
|
9407
9495
|
|
|
9408
|
-
If a multi-
|
|
9496
|
+
If a multi-context binding is gated out, the run's failure banner names which context and which rule rejected it (the same all-must-pass detail surfaced by `kici runs show <run-id>`).
|
|
9409
9497
|
|
|
9410
9498
|
### Secrets management
|
|
9411
9499
|
|
|
9412
|
-
Secrets are individual encrypted values organized by scope paths (e.g., `aws/prod`, `databases/postgres`). Scopes are bound to
|
|
9500
|
+
Secrets are individual encrypted values organized by scope paths (e.g., `aws/prod`, `databases/postgres`). Scopes are bound to contexts via bindings:
|
|
9413
9501
|
|
|
9414
|
-
- **Scope-centric view** (Secrets page): tree view of scopes with per-scope
|
|
9415
|
-
- **
|
|
9502
|
+
- **Scope-centric view** (Secrets page): tree view of scopes with per-scope context binding checkboxes
|
|
9503
|
+
- **Context-centric view** (inside context detail): bound scopes, resolved secrets, add binding
|
|
9416
9504
|
|
|
9417
9505
|
When scope paths collide on the same key name, the longer (more specific) path wins.
|
|
9418
9506
|
|
|
9419
9507
|
## Type generation
|
|
9420
9508
|
|
|
9421
|
-
Running `kici types` generates two augmented interfaces: `KnownSecretKeys` (union of all secret keys across all
|
|
9509
|
+
Running `kici types` generates two augmented interfaces: `KnownSecretKeys` (union of all secret keys across all contexts) and `ContextSecrets` (per-context key unions):
|
|
9422
9510
|
|
|
9423
9511
|
```typescript
|
|
9424
9512
|
interface KnownSecretKeys {
|
|
@@ -9426,13 +9514,233 @@ interface KnownSecretKeys {
|
|
|
9426
9514
|
API_KEY: string;
|
|
9427
9515
|
}
|
|
9428
9516
|
|
|
9429
|
-
interface
|
|
9517
|
+
interface ContextSecrets {
|
|
9430
9518
|
production: 'DB_PASSWORD' | 'API_KEY';
|
|
9431
9519
|
staging: 'DB_PASSWORD';
|
|
9432
9520
|
}
|
|
9433
9521
|
```
|
|
9434
9522
|
|
|
9435
|
-
`KnownSecretKeys` narrows `ctx.secrets.get()` and `ctx.secrets.expose()` key parameters to valid key names. `
|
|
9523
|
+
`KnownSecretKeys` narrows `ctx.secrets.get()` and `ctx.secrets.expose()` key parameters to valid key names. `ContextSecrets` maps each context to its available secret key names as a string union. Dynamic contexts fall back to the full `KnownSecretKeys` union.
|
|
9524
|
+
|
|
9525
|
+
---
|
|
9526
|
+
|
|
9527
|
+
## Dashboard
|
|
9528
|
+
|
|
9529
|
+
Source: https://docs.kici.dev/user/dashboard/
|
|
9530
|
+
|
|
9531
|
+
The KiCI dashboard is the browser interface for monitoring workflow runs, inspecting jobs and logs, and managing your organization. It signs in via OIDC and talks to KiCI over its API.
|
|
9532
|
+
|
|
9533
|
+
This guide is split across the following pages:
|
|
9534
|
+
|
|
9535
|
+
| Page | Covers |
|
|
9536
|
+
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
9537
|
+
| [Getting started](https://docs.kici.dev/user/dashboard/getting-started/) | Onboarding checklist and your organizations list |
|
|
9538
|
+
| [Navigation and layout](https://docs.kici.dev/user/dashboard/navigation/) | Sidebar, mobile nav, theme, time display, shortcuts, error pages |
|
|
9539
|
+
| [Runs and logs](https://docs.kici.dev/user/dashboard/runs/) | Run list, run detail, the log viewer |
|
|
9540
|
+
| [Settings](https://docs.kici.dev/user/dashboard/settings/) | Members, roles, teams, keys, sources, billing, security, support access |
|
|
9541
|
+
| [Workflows, diagnostics, and orchestrators](https://docs.kici.dev/user/dashboard/workflows-and-diagnostics/) | Registered workflows, infra health, per-cluster views |
|
|
9542
|
+
| [Contexts, secrets, and approvals](https://docs.kici.dev/user/dashboard/contexts-and-secrets/) | Contexts, secret scopes, approval queue |
|
|
9543
|
+
| [Activity and DLQ](https://docs.kici.dev/user/dashboard/activity-and-dlq/) | Forensic activity log and dead-letter queue |
|
|
9544
|
+
| [Account](https://docs.kici.dev/user/dashboard/account/) | Personal account settings |
|
|
9545
|
+
|
|
9546
|
+
---
|
|
9547
|
+
|
|
9548
|
+
## Dynamic values
|
|
9549
|
+
|
|
9550
|
+
Source: https://docs.kici.dev/user/dynamic-values/
|
|
9551
|
+
|
|
9552
|
+
Dynamic values let you compute `context`, `env`, and `concurrencyGroup` at runtime based on the incoming event. Instead of hardcoding static strings, you pass a function that receives the normalized event envelope and returns the resolved value.
|
|
9553
|
+
|
|
9554
|
+
```typescript
|
|
9555
|
+
job('deploy', {
|
|
9556
|
+
runsOn: ['default'],
|
|
9557
|
+
context: (event) => event.targetBranch,
|
|
9558
|
+
env: (event) => ({ BRANCH: event.targetBranch }),
|
|
9559
|
+
concurrencyGroup: (event) => `deploy-${event.targetBranch}`,
|
|
9560
|
+
steps: [
|
|
9561
|
+
/* ... */
|
|
9562
|
+
],
|
|
9563
|
+
});
|
|
9564
|
+
```
|
|
9565
|
+
|
|
9566
|
+
```typescript
|
|
9567
|
+
job('deploy', {
|
|
9568
|
+
runsOn: 'default',
|
|
9569
|
+
// One shape everywhere: branch on the normalized event type.
|
|
9570
|
+
context: (event) => (event.type === 'pull_request' ? 'preview' : 'production'),
|
|
9571
|
+
steps: [
|
|
9572
|
+
/* ... */
|
|
9573
|
+
],
|
|
9574
|
+
});
|
|
9575
|
+
```
|
|
9576
|
+
|
|
9577
|
+
## How it works
|
|
9578
|
+
|
|
9579
|
+
When you define a dynamic value as a function, the compiler analyzes it at compile time to determine whether it is **pure** (can be evaluated without cloning the repo or running an init job).
|
|
9580
|
+
|
|
9581
|
+
### Pure functions (inline evaluation)
|
|
9582
|
+
|
|
9583
|
+
A pure function is one that:
|
|
9584
|
+
|
|
9585
|
+
- Is synchronous (no `async`/`await`)
|
|
9586
|
+
- Only references its parameters and local variables
|
|
9587
|
+
- Does not import or require external modules
|
|
9588
|
+
- Does not access globals like `process`, `fetch`, `console`, `setTimeout`, etc.
|
|
9589
|
+
- Uses only safe built-in constructors: `String`, `Number`, `Boolean`, `Array`, `Object`, `JSON`, `Math`, `parseInt`, `parseFloat`, `isNaN`, `isFinite`, `encodeURIComponent`, `decodeURIComponent`, `encodeURI`, `decodeURI`
|
|
9590
|
+
- Does not use `this`, `new`, `class`, `throw`, `try`/`catch`, `delete`, `var`, `yield`, or mutation operators (`++`, `--`, `+=`, etc.)
|
|
9591
|
+
|
|
9592
|
+
When the compiler detects a pure function, it serializes the function source directly into the lock file as an inline expression. At dispatch time, the orchestrator evaluates the expression in a sandboxed VM context (~0ms overhead) instead of dispatching an init job.
|
|
9593
|
+
|
|
9594
|
+
**Examples of pure functions:**
|
|
9595
|
+
|
|
9596
|
+
```typescript
|
|
9597
|
+
// Simple branch extraction
|
|
9598
|
+
context: (event) => event.targetBranch;
|
|
9599
|
+
|
|
9600
|
+
// Object literal with string operations
|
|
9601
|
+
env: (event) => ({ BRANCH: event.targetBranch });
|
|
9602
|
+
|
|
9603
|
+
// Concatenation with event data
|
|
9604
|
+
concurrencyGroup: (event) => `deploy-${event.targetBranch}`;
|
|
9605
|
+
|
|
9606
|
+
// Using safe globals
|
|
9607
|
+
env: (event) => ({ UPPER: String(event.targetBranch).toUpperCase() });
|
|
9608
|
+
|
|
9609
|
+
// Local variables are fine
|
|
9610
|
+
context: (event) => {
|
|
9611
|
+
const parts = event.targetBranch.split('/');
|
|
9612
|
+
return parts[parts.length - 1];
|
|
9613
|
+
};
|
|
9614
|
+
```
|
|
9615
|
+
|
|
9616
|
+
### Impure functions (init-job evaluation)
|
|
9617
|
+
|
|
9618
|
+
If the compiler determines a function is impure, it emits a warning during compilation and falls back to the two-phase init model. This means:
|
|
9619
|
+
|
|
9620
|
+
1. The orchestrator dispatches a special `__init__` job to a builder agent
|
|
9621
|
+
2. The builder agent clones the repository and evaluates the function
|
|
9622
|
+
3. The resolved values are sent back to the orchestrator
|
|
9623
|
+
4. The orchestrator dispatches the real execution job with the resolved values
|
|
9624
|
+
|
|
9625
|
+
This adds approximately 5-10 seconds of overhead for cloning and evaluation.
|
|
9626
|
+
|
|
9627
|
+
**Examples of impure functions (will use init job):**
|
|
9628
|
+
|
|
9629
|
+
```typescript
|
|
9630
|
+
// Async functions cannot be inlined
|
|
9631
|
+
context: async (event) => await lookupEnv(event.targetBranch);
|
|
9632
|
+
|
|
9633
|
+
// External module references
|
|
9634
|
+
env: (event) => {
|
|
9635
|
+
const config = require('./config');
|
|
9636
|
+
return config.env;
|
|
9637
|
+
};
|
|
9638
|
+
|
|
9639
|
+
// Process/global access
|
|
9640
|
+
context: (event) => process.env.DEFAULT_ENV || 'staging';
|
|
9641
|
+
|
|
9642
|
+
// Dynamic imports
|
|
9643
|
+
env: async (event) => {
|
|
9644
|
+
const m = await import('./config.js');
|
|
9645
|
+
return m.default;
|
|
9646
|
+
};
|
|
9647
|
+
```
|
|
9648
|
+
|
|
9649
|
+
## Performance comparison
|
|
9650
|
+
|
|
9651
|
+
| Evaluation path | Overhead | When used |
|
|
9652
|
+
| ------------------------------------ | -------- | --------------------------------------------------------------- |
|
|
9653
|
+
| Static value (string/object literal) | ~0ms | `context: 'staging'` |
|
|
9654
|
+
| Inline expression (pure function) | ~0ms | `context: (event) => event.targetBranch` |
|
|
9655
|
+
| Init job (impure function) | ~5-10s | `context: async (event) => await lookupEnv(event.targetBranch)` |
|
|
9656
|
+
|
|
9657
|
+
## Tips
|
|
9658
|
+
|
|
9659
|
+
- **Write pure functions whenever possible** to avoid the init-job delay. Most context and env computations only need the event payload data.
|
|
9660
|
+
- **Check compiler warnings** -- the compiler tells you when a function is classified as impure and explains why.
|
|
9661
|
+
- **Runtime errors in inline expressions cause immediate job failure.** There is no fallback to the init-job path. If your pure function throws at runtime (e.g., accessing a property on `undefined`), the job fails immediately.
|
|
9662
|
+
- **The event parameter is the normalized event envelope** — the same shape rules receive as `ctx.event`: `{ type, action, targetBranch, sourceBranch, changedFiles, payload, … }` (see the [event payload reference](https://docs.kici.dev/user/sdk/event-payloads/) for the complete schema). Narrow on `event.type` (`'push'`, `'pull_request'`, `'tag'`, …) to branch per trigger kind. The raw provider webhook body is nested at `event.payload` (for GitHub pushes: `payload.ref`, `payload.after`, `payload.repository`, …).
|
|
9663
|
+
|
|
9664
|
+
---
|
|
9665
|
+
|
|
9666
|
+
## Environment variables
|
|
9667
|
+
|
|
9668
|
+
Source: https://docs.kici.dev/user/env-vars/
|
|
9669
|
+
|
|
9670
|
+
The KiCI CLI reads the following environment variables to customize its behavior. OAuth login (`kici login` without `--token`) defaults `KICI_PLATFORM_URL`, `KICI_OIDC_ISSUER`, and `KICI_OIDC_CLIENT_ID` to the hosted KiCI Platform, so `kici login` works with no configuration. Set them only to target another KiCI environment (e.g. a testing instance) or a custom OIDC provider.
|
|
9671
|
+
|
|
9672
|
+
## Authentication
|
|
9673
|
+
|
|
9674
|
+
| Variable | Description | Default |
|
|
9675
|
+
| --------------------- | -------------------------------------- | -------------------------------------------- |
|
|
9676
|
+
| `KICI_OIDC_ISSUER` | OIDC issuer URL for authentication | `https://auth.kici.dev/realms/kici-internal` |
|
|
9677
|
+
| `KICI_OIDC_CLIENT_ID` | OIDC client ID for the CLI application | `kici-cli` |
|
|
9678
|
+
| `KICI_PLATFORM_URL` | Platform API base URL | `https://api.kici.dev` |
|
|
9679
|
+
| `KICI_CONFIG_DIR` | Override the KiCI config directory | `~/.kici` |
|
|
9680
|
+
|
|
9681
|
+
## Browser behavior
|
|
9682
|
+
|
|
9683
|
+
| Variable | Description | Default |
|
|
9684
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
9685
|
+
| `KICI_BROWSER_CMD` | Custom browser command for OAuth login. Supports `{url}` placeholder. Set to `none` to suppress browser opening and print the URL to stdout instead. | Uses the system default browser via the `open` package |
|
|
9686
|
+
| `KICI_CALLBACK_PORT` | Fixed port for the OAuth PKCE callback server. Useful when firewall rules require a known port. | Random available port |
|
|
9687
|
+
|
|
9688
|
+
## Development
|
|
9689
|
+
|
|
9690
|
+
| Variable | Description | Default |
|
|
9691
|
+
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
9692
|
+
| `KICI_DEV` | Enable development mode. When `true`, uses prerelease-compatible version ranges (`>=0.0.1-0`) for dev dependencies and skips npm version resolution. | unset |
|
|
9693
|
+
| `KICI_DEBUG` | Enable debug logging. When `true`, prints verbose diagnostics (SDK alias resolution, step-level debug logs, stack traces on errors). Equivalent to the `--debug` CLI flag. | unset |
|
|
9694
|
+
|
|
9695
|
+
## Usage examples
|
|
9696
|
+
|
|
9697
|
+
### CI/CD environment
|
|
9698
|
+
|
|
9699
|
+
Authenticate with a pre-existing API key (no browser needed):
|
|
9700
|
+
|
|
9701
|
+
```bash
|
|
9702
|
+
kici login --token <<< "$KICI_API_KEY"
|
|
9703
|
+
```
|
|
9704
|
+
|
|
9705
|
+
### Targeting another environment or custom OIDC provider
|
|
9706
|
+
|
|
9707
|
+
`kici login` targets the hosted KiCI Platform by default. To point the CLI at another KiCI environment (e.g. a testing instance) or a custom OIDC provider, override the defaults:
|
|
9708
|
+
|
|
9709
|
+
```bash
|
|
9710
|
+
export KICI_OIDC_ISSUER=https://your-idp.example.com
|
|
9711
|
+
export KICI_OIDC_CLIENT_ID=your-client-id
|
|
9712
|
+
export KICI_PLATFORM_URL=https://your-platform.example.com
|
|
9713
|
+
kici login
|
|
9714
|
+
```
|
|
9715
|
+
|
|
9716
|
+
### Headless SSH session
|
|
9717
|
+
|
|
9718
|
+
The CLI auto-detects headless environments and uses the device flow. To force PKCE with URL output instead:
|
|
9719
|
+
|
|
9720
|
+
```bash
|
|
9721
|
+
export KICI_BROWSER_CMD=none
|
|
9722
|
+
kici login
|
|
9723
|
+
```
|
|
9724
|
+
|
|
9725
|
+
This prints the authorization URL to stdout as `KICI_AUTH_URL=<url>`. Open the URL in any browser to complete authentication.
|
|
9726
|
+
|
|
9727
|
+
### Fixed callback port
|
|
9728
|
+
|
|
9729
|
+
When behind a firewall or using port forwarding:
|
|
9730
|
+
|
|
9731
|
+
```bash
|
|
9732
|
+
export KICI_CALLBACK_PORT=19876
|
|
9733
|
+
kici login
|
|
9734
|
+
```
|
|
9735
|
+
|
|
9736
|
+
### Custom config location
|
|
9737
|
+
|
|
9738
|
+
Store the KiCI config in a non-default location:
|
|
9739
|
+
|
|
9740
|
+
```bash
|
|
9741
|
+
export KICI_CONFIG_DIR=/tmp/kici-test
|
|
9742
|
+
kici login
|
|
9743
|
+
```
|
|
9436
9744
|
|
|
9437
9745
|
---
|
|
9438
9746
|
|
|
@@ -10027,21 +10335,19 @@ guaranteed side-effect-free.
|
|
|
10027
10335
|
|
|
10028
10336
|
## Running in check mode
|
|
10029
10337
|
|
|
10030
|
-
`--check` and `--fail-on-drift`
|
|
10338
|
+
`--check` and `--fail-on-drift` control drift reporting on `kici run remote`:
|
|
10031
10339
|
|
|
10032
10340
|
```bash
|
|
10033
10341
|
# Apply (default): converge the workflow.
|
|
10034
|
-
kici run local
|
|
10342
|
+
kici run push --local
|
|
10035
10343
|
kici run remote my-fixture
|
|
10036
10344
|
|
|
10037
10345
|
# Check: report drift, change nothing. Always exits 0.
|
|
10038
|
-
kici run local push --check
|
|
10039
10346
|
kici run remote my-fixture --check
|
|
10040
10347
|
|
|
10041
|
-
# Check + fail on drift:
|
|
10042
|
-
#
|
|
10043
|
-
|
|
10044
|
-
kici run local push --check --fail-on-drift
|
|
10348
|
+
# Check + fail on drift: fail the run when any step reports drift. Use this as a
|
|
10349
|
+
# CI gate ("fail the build if prod has drifted").
|
|
10350
|
+
kici run remote my-fixture --check --fail-on-drift
|
|
10045
10351
|
```
|
|
10046
10352
|
|
|
10047
10353
|
`--fail-on-drift` only modifies check mode — passing it without `--check` is an
|
|
@@ -10080,7 +10386,7 @@ The two channels (Option A and Option C) compose. If you declare both, the agent
|
|
|
10080
10386
|
|
|
10081
10387
|
## Option A — `registries:` block
|
|
10082
10388
|
|
|
10083
|
-
Declare the registry in your workflow file and point its `tokenSecret` at a scoped secret using the qualified `<
|
|
10389
|
+
Declare the registry in your workflow file and point its `tokenSecret` at a scoped secret using the qualified `<context>:<secret-name>` syntax. The orchestrator resolves the token at dispatch time and the agent applies it for one `npm install` only.
|
|
10084
10390
|
|
|
10085
10391
|
```typescript
|
|
10086
10392
|
import { workflow, job, step, push } from '@kici-dev/sdk';
|
|
@@ -10097,7 +10403,7 @@ export default workflow('build', {
|
|
|
10097
10403
|
jobs: [
|
|
10098
10404
|
job('build', {
|
|
10099
10405
|
runsOn: 'default',
|
|
10100
|
-
|
|
10406
|
+
context: 'production',
|
|
10101
10407
|
steps: [
|
|
10102
10408
|
step('install-and-build', async (ctx) => {
|
|
10103
10409
|
// .kici/package.json can now reference @my-org/* packages
|
|
@@ -10113,7 +10419,7 @@ Per-field rules:
|
|
|
10113
10419
|
|
|
10114
10420
|
- **`url`** — Must be HTTPS. HTTP is permitted only for `localhost` / `127.0.0.0/8` / `::1` / `*.local` hosts, or when an operator has flipped the org-level `allow_http_npm_registries` toggle (see [`kici-admin org-settings allow-http-npm`](https://docs.kici.dev/operator/kici-admin-cli#allow-http-npm--permit-non-https-private-npm-registries)).
|
|
10115
10421
|
- **`scope`** — Optional. When present, the registry serves only that scope (`@my-org`). When absent, this entry becomes the **default** registry — at most one entry may omit `scope`.
|
|
10116
|
-
- **`tokenSecret`** — Mandatory `<
|
|
10422
|
+
- **`tokenSecret`** — Mandatory `<context>:<secret-name>`. The orchestrator looks up the secret in the named context via the per-context secret resolver. The bare name **must not** contain a colon.
|
|
10117
10423
|
- **`alwaysAuth`** — Defaults to `true`. Forces npm to send the token on every request (even GETs), which is what most managed-registry providers require.
|
|
10118
10424
|
|
|
10119
10425
|
### How tokens reach `npm install`
|
|
@@ -10143,14 +10449,14 @@ export default workflow('build', {
|
|
|
10143
10449
|
jobs: [
|
|
10144
10450
|
job('build', {
|
|
10145
10451
|
runsOn: 'default',
|
|
10146
|
-
|
|
10452
|
+
context: 'production',
|
|
10147
10453
|
steps: [step('build', async (ctx) => ctx.$`npm run build`)],
|
|
10148
10454
|
}),
|
|
10149
10455
|
],
|
|
10150
10456
|
});
|
|
10151
10457
|
```
|
|
10152
10458
|
|
|
10153
|
-
The orchestrator resolves `MY_NPM_TOKEN` from the `production`
|
|
10459
|
+
The orchestrator resolves `MY_NPM_TOKEN` from the `production` context's secret store and seeds it as `MY_NPM_TOKEN` (bare name) in the install subprocess. Your committed `.npmrc` reads it through `${MY_NPM_TOKEN}`.
|
|
10154
10460
|
|
|
10155
10461
|
This path is the right answer when:
|
|
10156
10462
|
|
|
@@ -10172,7 +10478,7 @@ export default workflow('build', {
|
|
|
10172
10478
|
jobs: [
|
|
10173
10479
|
job('mint-codeartifact-token', {
|
|
10174
10480
|
runsOn: 'default',
|
|
10175
|
-
|
|
10481
|
+
context: 'production',
|
|
10176
10482
|
steps: [
|
|
10177
10483
|
step('mint', async (ctx) => {
|
|
10178
10484
|
const awsKey = await ctx.secrets.get('AWS_ACCESS_KEY_ID');
|
|
@@ -10197,7 +10503,7 @@ export default workflow('build', {
|
|
|
10197
10503
|
}),
|
|
10198
10504
|
job('build', {
|
|
10199
10505
|
runsOn: 'default',
|
|
10200
|
-
|
|
10506
|
+
context: 'production',
|
|
10201
10507
|
needs: ['mint-codeartifact-token'],
|
|
10202
10508
|
steps: [step('build', async (ctx) => ctx.$`npm run build`)],
|
|
10203
10509
|
}),
|
|
@@ -10221,7 +10527,7 @@ registries: [
|
|
|
10221
10527
|
],
|
|
10222
10528
|
```
|
|
10223
10529
|
|
|
10224
|
-
Mint the token from a fine-grained PAT with `read:packages` scope, store it as a scoped secret in the `production`
|
|
10530
|
+
Mint the token from a fine-grained PAT with `read:packages` scope, store it as a scoped secret in the `production` context.
|
|
10225
10531
|
|
|
10226
10532
|
### GitLab Packages
|
|
10227
10533
|
|
|
@@ -10276,8 +10582,8 @@ registries: [
|
|
|
10276
10582
|
|
|
10277
10583
|
## Security model
|
|
10278
10584
|
|
|
10279
|
-
- **Per-
|
|
10280
|
-
- **Untrusted contributors get no tokens.** When a fork PR is dispatched and the contributor-trust resolution returns anything other than `trusted`, the orchestrator strips both `npmRegistries` and `installEnvSecrets` out of the dispatch. The install runs without auth and fails naturally on the first private dep — fork PRs cannot ever observe a registry token, even if a misconfigured
|
|
10585
|
+
- **Per-context scoping.** Every `tokenSecret` and `installEnv` entry is qualified with a context name. The orchestrator runs the same protection-rule pipeline (branch / trust / concurrency / reviewer / wait-timer) against each named context **before** resolving any secret, so a workflow that wants a `production` token from a feature branch is rejected exactly like a job that tries to deploy to `production` from a feature branch. A reviewer-gated install context **pauses** the whole workflow dispatch as a workflow-scoped held run instead of resolving the token — see [Reviewer-gated installs](https://docs.kici.dev/user/private-registries/#reviewer-gated-installs) below.
|
|
10586
|
+
- **Untrusted contributors get no tokens.** When a fork PR is dispatched and the contributor-trust resolution returns anything other than `trusted`, the orchestrator strips both `npmRegistries` and `installEnvSecrets` out of the dispatch. The install runs without auth and fails naturally on the first private dep — fork PRs cannot ever observe a registry token, even if a misconfigured context lacks an explicit `requiredTrustTier`.
|
|
10281
10587
|
- **Lifecycle scripts disabled.** Whenever a private registry is in scope, the agent runs the install with `--ignore-scripts` (npm or pnpm alike). A malicious `preinstall` / `postinstall` hook in committed `package.json` cannot read the synthesized token env vars, even though they exist in the install subprocess. For a pnpm workspace, the agent builds your in-repo dependency closure as a separate step **after** the install's auth is torn down, so build scripts never see the tokens either.
|
|
10282
10588
|
- **Stderr is redacted.** If the install fails, the agent masks every token literal out of the surfaced stderr / stdout chunks before logging.
|
|
10283
10589
|
- **Job-scoped env-var names.** The synthesized auth env var is `KICI_NPM_TOKEN_<jobIdShort>_<i>` where `jobIdShort` is the first 8 chars of the dispatched job id. The name is unguessable from outside the install subprocess and not reused across jobs.
|
|
@@ -10285,12 +10591,12 @@ registries: [
|
|
|
10285
10591
|
|
|
10286
10592
|
## Reviewer-gated installs
|
|
10287
10593
|
|
|
10288
|
-
When the named install
|
|
10594
|
+
When the named install context carries a protection rule that holds — a required reviewer (`hold`) or a wait timer (`wait`) — the install gate **pauses the whole workflow dispatch** instead of rejecting it. The run is created in the `held` state, no jobs are queued, and a workflow-scoped row appears on the held-runs page with a `Workflow` scope badge.
|
|
10289
10595
|
|
|
10290
10596
|
- **Reviewer hold:** the run waits for an approver. On approval the dispatch resumes from the install gate, resolves the token, and dispatches its jobs as a normal run. On rejection the run transitions to `cancelled` — no jobs ever run.
|
|
10291
10597
|
- **Wait timer:** the run waits out the timer and resumes automatically when it elapses.
|
|
10292
10598
|
|
|
10293
|
-
A `reject` protection outcome (for example a disabled
|
|
10599
|
+
A `reject` protection outcome (for example a disabled context or a branch the context forbids) still fails the dispatch loudly with a clear reason, exactly as before — the orchestrator never dispatches a run with an unresolved install token.
|
|
10294
10600
|
|
|
10295
10601
|
## Limitations
|
|
10296
10602
|
|
|
@@ -10301,19 +10607,19 @@ A `reject` protection outcome (for example a disabled environment or a branch th
|
|
|
10301
10607
|
|
|
10302
10608
|
The orchestrator exposes Prometheus counters and a histogram under the `kici_orch_install_secrets_*` prefix on its `/metrics` endpoint. They populate the **Install secrets resolution** Grafana dashboard and let operators graph install-secrets activity without digging through Loki.
|
|
10303
10609
|
|
|
10304
|
-
| Metric | Type | Labels | What it tells you
|
|
10305
|
-
| ------------------------------------------------------------- | --------- | ------------------------------ |
|
|
10306
|
-
| `kici_orch_install_secrets_decisions_total` | Counter | `decision`, `reason` | Pass / reject / hold volume. `decision=hold` (reason `held`) counts dispatches paused at a reviewer-gated install
|
|
10307
|
-
| `kici_orch_install_secrets_npm_registry_used_total` | Counter | `channel`, `provider`, `scope` | Per-channel + per-scope usage. `channel=registries` is Option A, `channel=install_env` is Option C. `scope=default` marks a no-scope default registry; `scope=-` marks Option C entries.
|
|
10308
|
-
| `kici_orch_install_secrets_contributor_stripped_total` | Counter | `trust_tier` | Number of dispatches where registry tokens were stripped because the contributor tier wasn't `trusted` (fork PRs from unknown / known contributors). Expected to be 0 in single-tenant orgs.
|
|
10309
|
-
| `kici_orch_install_secrets_token_resolution_duration_seconds` | Histogram | `environment` | Latency of per-environment secret resolution. Pathological tails (>500ms) usually mean a Vault timeout or a slow Postgres replica.
|
|
10610
|
+
| Metric | Type | Labels | What it tells you |
|
|
10611
|
+
| ------------------------------------------------------------- | --------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10612
|
+
| `kici_orch_install_secrets_decisions_total` | Counter | `decision`, `reason` | Pass / reject / hold volume. `decision=hold` (reason `held`) counts dispatches paused at a reviewer-gated install context. Reject reasons enumerate the failure mode: `malformed_ref`, `invalid_url_scheme`, `env_not_found`, `protection_rule_block`, `missing_token`, `missing_install_env`, etc. |
|
|
10613
|
+
| `kici_orch_install_secrets_npm_registry_used_total` | Counter | `channel`, `provider`, `scope` | Per-channel + per-scope usage. `channel=registries` is Option A, `channel=install_env` is Option C. `scope=default` marks a no-scope default registry; `scope=-` marks Option C entries. |
|
|
10614
|
+
| `kici_orch_install_secrets_contributor_stripped_total` | Counter | `trust_tier` | Number of dispatches where registry tokens were stripped because the contributor tier wasn't `trusted` (fork PRs from unknown / known contributors). Expected to be 0 in single-tenant orgs. |
|
|
10615
|
+
| `kici_orch_install_secrets_token_resolution_duration_seconds` | Histogram | `environment` | Latency of per-environment secret resolution. Pathological tails (>500ms) usually mean a Vault timeout or a slow Postgres replica. |
|
|
10310
10616
|
|
|
10311
10617
|
The dashboard JSON lives at `infra/terraform/modules/grafana/dashboards/install-secrets.json`; if you maintain your own monitoring stack, you can import it directly.
|
|
10312
10618
|
|
|
10313
10619
|
## See also
|
|
10314
10620
|
|
|
10315
|
-
- [Secrets](https://docs.kici.dev/user/secrets/) — how to seed the `<
|
|
10316
|
-
- [
|
|
10621
|
+
- [Secrets](https://docs.kici.dev/user/secrets/) — how to seed the `<context>:<secret-name>` values referenced by `tokenSecret` / `installEnv`.
|
|
10622
|
+
- [Contexts](https://docs.kici.dev/user/contexts/) — protection rules (`branch_restrictions`, `requires_review`, `minimum_trust`) that the install gate inherits.
|
|
10317
10623
|
- [Operator: `kici-admin org-settings`](https://docs.kici.dev/operator/kici-admin-cli#org-settings----org-level-security-policy) — the `allow_http_npm_registries` toggle and other org-scoped knobs.
|
|
10318
10624
|
|
|
10319
10625
|
---
|
|
@@ -10582,11 +10888,11 @@ KiCI provides an explicit secrets API that gives workflow steps controlled acces
|
|
|
10582
10888
|
|
|
10583
10889
|
## Overview
|
|
10584
10890
|
|
|
10585
|
-
Secrets are managed per-
|
|
10891
|
+
Secrets are managed per-context in the orchestrator (see [operator docs](https://docs.kici.dev/operator/orchestrator/configuration) for setup). When a job runs with a `context` binding, the agent receives the secret keys available for that context but does **not** inject their values into the step's process environment. Instead, steps access secrets through the `ctx.secrets` API.
|
|
10586
10892
|
|
|
10587
10893
|
This design prevents accidental secret leakage through child processes, log output, or error messages. Only secrets you explicitly request are loaded into memory.
|
|
10588
10894
|
|
|
10589
|
-
A job can bind several
|
|
10895
|
+
A job can bind several contexts with `contexts: ['staging', 'my-testing']`; the secret keys from all bound contexts are merged in array order, with a later context's value winning on a key collision. See [Multiple contexts per job](https://docs.kici.dev/user/contexts/#multiple-contexts-per-job).
|
|
10590
10896
|
|
|
10591
10897
|
## Where secret values come from
|
|
10592
10898
|
|
|
@@ -10654,7 +10960,7 @@ export default workflow('deploy', {
|
|
|
10654
10960
|
jobs: [
|
|
10655
10961
|
job('deploy', {
|
|
10656
10962
|
runsOn: 'default',
|
|
10657
|
-
|
|
10963
|
+
context: 'production',
|
|
10658
10964
|
steps: [
|
|
10659
10965
|
step('deploy', async (ctx) => {
|
|
10660
10966
|
const token = await ctx.secrets.get('DEPLOY_TOKEN');
|
|
@@ -10778,7 +11084,7 @@ export default workflow('deploy', {
|
|
|
10778
11084
|
jobs: [
|
|
10779
11085
|
job('decrypt-and-deploy', {
|
|
10780
11086
|
runsOn: 'default',
|
|
10781
|
-
|
|
11087
|
+
context: 'production',
|
|
10782
11088
|
steps: [
|
|
10783
11089
|
step('decrypt', async (ctx) => {
|
|
10784
11090
|
const ageKeys = ctx.secrets.list().filter((k) => k.startsWith('AGE_KEY_'));
|
|
@@ -10810,7 +11116,7 @@ export default workflow('deploy', {
|
|
|
10810
11116
|
jobs: [
|
|
10811
11117
|
job('decrypt-and-deploy', {
|
|
10812
11118
|
runsOn: 'default',
|
|
10813
|
-
|
|
11119
|
+
context: 'production',
|
|
10814
11120
|
steps: [
|
|
10815
11121
|
step('decrypt-to-env', async (ctx) => {
|
|
10816
11122
|
await ctx.secrets.exposeFile('SOPS_AGE_KEY_FILE', {
|
|
@@ -10889,7 +11195,9 @@ The **GitHub App** is KiCI's flagship source. A single App:
|
|
|
10889
11195
|
|
|
10890
11196
|
1. receives `push`, `pull_request`, and related events from every repo it's installed on,
|
|
10891
11197
|
2. clones repos with a short-lived installation token (no deploy key to manage),
|
|
10892
|
-
3. posts workflow / job / step Check runs back to the
|
|
11198
|
+
3. posts workflow / job / step Check runs back to the commit — visible on
|
|
11199
|
+
the commit view for a plain `push` and on the **Checks** tab of any pull
|
|
11200
|
+
request that contains it (see
|
|
10893
11201
|
[GitHub checks architecture](https://docs.kici.dev/architecture/webhooks/github-checks/)).
|
|
10894
11202
|
|
|
10895
11203
|
You don't need an App for every scenario — if you only care about `push`
|
|
@@ -11226,6 +11534,13 @@ driven by the orchestrator's reporting module; no workflow
|
|
|
11226
11534
|
configuration is required beyond installing the App with the
|
|
11227
11535
|
`checks: write` permission.
|
|
11228
11536
|
|
|
11537
|
+
Check runs are keyed to the head commit SHA, so they surface whether or
|
|
11538
|
+
not a pull request exists: after a `push` you see the pass/fail directly
|
|
11539
|
+
on the commit (a red ✗ / green ✓ next to the SHA in GitHub's commit list
|
|
11540
|
+
and on the commit page), and the same checks roll up into the **Checks**
|
|
11541
|
+
tab of any pull request that later includes the commit. A failing run is
|
|
11542
|
+
therefore visible in GitHub itself without opening the KiCI dashboard.
|
|
11543
|
+
|
|
11229
11544
|
For architecture details see
|
|
11230
11545
|
[GitHub checks architecture](https://docs.kici.dev/architecture/webhooks/github-checks/).
|
|
11231
11546
|
|
|
@@ -12162,7 +12477,7 @@ The working-tree overlay tarball uploads **directly** from the developer machine
|
|
|
12162
12477
|
|
|
12163
12478
|
The run is dispatched to the developer's active organization (selected with `kici org use`, or overridden per-run). The orchestrator anchors its bound organization with a system-managed **remote source** (routing key `remote:<orgId>`) that it auto-provisions — no manual webhook source is required, so a zero-source org is immediately routable for remote runs. The Platform forces the run's routing key to `remote:<orgId>` server-side; the developer never sets a routing key. When an org has more than one connected orchestrator cluster, the CLI selects the target cluster explicitly (or relies on the per-org default), and a single connected cluster is auto-selected.
|
|
12164
12479
|
|
|
12165
|
-
Remote runs are offered by the Platform; an orchestrator with no Platform connection cannot serve them. Executing workflow steps on the developer machine with no orchestrator is the separate `kici run local` path.
|
|
12480
|
+
Remote runs are offered by the Platform; an orchestrator with no Platform connection cannot serve them. Executing workflow steps on the developer machine with no orchestrator is the separate `kici run <event> --local` path.
|
|
12166
12481
|
|
|
12167
12482
|
## Source and dependency caching flow
|
|
12168
12483
|
|
|
@@ -12833,7 +13148,7 @@ The compiler processes the workflow definition:
|
|
|
12833
13148
|
|
|
12834
13149
|
### Execution time (local test runner)
|
|
12835
13150
|
|
|
12836
|
-
When `kici run local` runs a workflow:
|
|
13151
|
+
When `kici run <event> --local` runs a workflow:
|
|
12837
13152
|
|
|
12838
13153
|
1. **SDK module resolution:** The runner resolves `setStepOutputsMap` / `setJobOutputsMap` from the same `@kici-dev/sdk` module instance that the workflow uses (ensures the proxy reads from the same map)
|
|
12839
13154
|
2. **Map injection:** Fresh `OutputsMap` and `StepRefMap` are created and injected via `setStepOutputsMap()` / `setStepRefMap()` before each job
|