@kici-dev/compiler 0.1.23 → 0.1.25
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/auth/headless-detect.js +1 -1
- package/dist/cli-banner.js +1 -1
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +71 -10
- package/dist/commands/approve.js +2 -2
- package/dist/commands/check-mode.js +1 -1
- package/dist/commands/compile.js +1 -1
- package/dist/commands/diagnostics.js +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/drain-worker.js +1 -1
- package/dist/commands/endpoints.js +1 -1
- package/dist/commands/fixture.js +2 -2
- package/dist/commands/held-run-client.d.ts +1 -1
- package/dist/commands/held-run-client.js +1 -1
- package/dist/commands/hook.js +1 -1
- package/dist/commands/index.d.ts +5 -3
- package/dist/commands/index.js +5 -4
- package/dist/commands/init.js +3 -3
- package/dist/commands/login.js +1 -1
- package/dist/commands/logout.js +1 -1
- package/dist/commands/orchestrators.js +1 -1
- package/dist/commands/org.js +1 -1
- package/dist/commands/pat.d.ts +27 -0
- package/dist/commands/pat.js +76 -0
- package/dist/commands/preview.d.ts +88 -0
- package/dist/commands/{test.js → preview.js} +16 -15
- package/dist/commands/reject.js +2 -2
- package/dist/commands/run-hold-watch.d.ts +10 -1
- package/dist/commands/run-hold-watch.js +13 -12
- package/dist/commands/run.d.ts +20 -1
- package/dist/commands/run.js +62 -12
- package/dist/commands/runs/cancel.js +1 -1
- package/dist/commands/runs/list.js +1 -1
- package/dist/commands/runs/logs.js +1 -1
- package/dist/commands/runs/rerun.js +1 -1
- package/dist/commands/runs/show.js +1 -1
- package/dist/commands/secrets-list.js +1 -1
- package/dist/commands/types.js +1 -1
- package/dist/commands/verify-attestation.d.ts +4 -1
- package/dist/commands/verify-attestation.js +34 -12
- package/dist/commands/watch.js +1 -1
- package/dist/commands/workflows.js +1 -1
- package/dist/errors/capability-gap.js +1 -1
- package/dist/errors/formatter.js +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/execution/executor.d.ts +5 -6
- package/dist/execution/executor.js +6 -7
- package/dist/execution/index.js +1 -1
- package/dist/execution/sdk-alias.d.ts +4 -14
- package/dist/execution/sdk-alias.js +6 -45
- package/dist/execution/ts-loader.js +1 -1
- package/dist/fixtures/compiler.js +1 -1
- package/dist/fixtures/defaults/index.js +1 -1
- package/dist/fixtures/describe-event.d.ts +0 -4
- package/dist/fixtures/describe-event.js +35 -5
- package/dist/fixtures/picker.js +1 -1
- package/dist/format.js +1 -1
- package/dist/generators/secrets-dts.js +3 -1
- package/dist/hooks/detector.js +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/installer.js +1 -1
- package/dist/hooks/templates.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/llm-context/llms-architecture.txt +4 -4
- package/dist/llm-context/llms-cli.txt +346 -33
- package/dist/llm-context/llms-features.txt +128 -21
- package/dist/llm-context/llms-full.txt +610 -71
- package/dist/llm-context/llms-getting-started.txt +7 -7
- package/dist/llm-context/llms-sdk.txt +125 -6
- package/dist/llm-context/llms.txt +7 -5
- package/dist/local-executor/dag-scheduler.js +1 -1
- package/dist/local-executor/index.js +3 -2
- package/dist/local-executor/job-runner.js +4 -4
- package/dist/local-executor/materializer.js +1 -1
- package/dist/local-executor/output-streamer.js +1 -1
- package/dist/local-executor/payload-generator.js +1 -1
- package/dist/local-executor/picker.js +1 -1
- package/dist/local-executor/runs-on-display.js +1 -1
- package/dist/local-executor/secret-loader.js +1 -1
- package/dist/local-executor/to-event-payload.js +1 -1
- package/dist/local-executor/types.js +1 -1
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/lockfile/generator.d.ts +10 -2
- package/dist/lockfile/generator.js +107 -53
- package/dist/lockfile/hash-files.js +1 -1
- package/dist/lockfile/hasher.js +1 -1
- package/dist/lockfile/index.js +1 -1
- package/dist/lockfile/purity-analyzer.js +3 -3
- package/dist/postinstall.js +1 -1
- package/dist/provenance-trust-root.js +1 -1
- package/dist/remote/config.js +1 -1
- package/dist/remote/dashboard-client.js +1 -1
- package/dist/remote/encryption.js +1 -1
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/history.js +2 -2
- package/dist/remote/local-repo-identity.d.ts +32 -0
- package/dist/remote/local-repo-identity.js +74 -0
- package/dist/remote/oauth.js +1 -1
- package/dist/remote/oidc-discovery.js +1 -1
- package/dist/remote/output/json.js +1 -1
- package/dist/remote/output/junit.js +1 -1
- package/dist/remote/output/streaming.js +1 -1
- package/dist/remote/output/summary.js +1 -1
- package/dist/remote/platform-client.d.ts +2 -0
- package/dist/remote/platform-client.js +1 -1
- package/dist/remote/prod-defaults.d.ts +9 -1
- package/dist/remote/prod-defaults.js +11 -3
- package/dist/remote/render.js +1 -1
- package/dist/remote/secret-upload.js +1 -1
- package/dist/remote/uploader.js +4 -4
- package/dist/{chunk-BTugEXQM.js → rolldown-runtime-ClRpJifh.js} +0 -1
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +3 -3
- package/dist/templates/index.js +1 -1
- package/dist/templates/package-json.js +2 -2
- package/dist/templates/tsconfig-json.js +1 -1
- package/dist/templates/workflows/hello-world.js +1 -1
- package/dist/templates/workflows/pr-checks.js +1 -1
- package/dist/test-runner/dry-run.js +1 -1
- package/dist/test-runner/event-types.js +1 -1
- package/dist/test-runner/git-detector.js +1 -1
- package/dist/test-runner/index.js +1 -1
- package/dist/test-runner/job-executor.js +1 -1
- package/dist/test-runner/output-formatter.js +1 -1
- package/dist/test-runner/payload-builder.js +1 -1
- package/dist/test-runner/rule-evaluator.js +1 -1
- package/dist/test-runner/secrets-file.js +1 -1
- package/dist/test-runner/step-context.d.ts +1 -1
- package/dist/test-runner/step-context.js +3 -2
- package/dist/types.d.ts +33 -6
- package/dist/types.js +6 -2
- package/dist/validation/index.js +1 -1
- package/dist/validation/validator.js +1 -1
- package/package.json +4 -7
- package/sbom.spdx.json +35 -35
- package/dist/commands/held-run-resolve.js +0 -53
|
@@ -26,7 +26,7 @@ Why the lock file must stay in sync with workflow source, how to commit both tog
|
|
|
26
26
|
|
|
27
27
|
### [CLI reference](https://docs.kici.dev/user/cli-reference/)
|
|
28
28
|
|
|
29
|
-
All CLI commands provided by `@kici-dev/compiler`: `kici compile` (with watch mode and check mode), `kici run` (local and remote execution), `kici
|
|
29
|
+
All CLI commands provided by `@kici-dev/compiler`: `kici compile` (with watch mode and check mode), `kici run` (local and remote execution), `kici preview` (event simulation with dry-run, filtering, debug output, and custom payloads), `kici login`/`logout`/`org` (authentication and org management), `kici diagnostics` (infrastructure tree) and `kici runs` (`list`/`show`/`logs`/`rerun`/`cancel` — run management), `kici secrets` (secret listing), `kici types` (type generation), `kici fixture` (generate test payloads), `kici init` (interactive project scaffolding), `kici hook` (pre-commit hook installation), `kici endpoints` (webhook entrypoints), and `kici workflows` (workflow listing). Includes environment variables and exit codes.
|
|
30
30
|
|
|
31
31
|
### [Workflow patterns](https://docs.kici.dev/user/workflow-patterns/)
|
|
32
32
|
|
|
@@ -46,7 +46,7 @@ Configure deployment environments (staging, production, review/\*) with variable
|
|
|
46
46
|
|
|
47
47
|
### [Environment variables](https://docs.kici.dev/user/env-vars/)
|
|
48
48
|
|
|
49
|
-
Reference for all `KICI_*` environment variables supported by the CLI. Covers authentication overrides (OIDC issuer, client ID, project ID), browser behavior (custom browser command, fixed callback port), development mode, and usage examples for CI/CD,
|
|
49
|
+
Reference for all `KICI_*` environment variables supported by the CLI. Covers authentication overrides (OIDC issuer, client ID, project ID), browser behavior (custom browser command, fixed callback port), development mode, and usage examples for CI/CD, alternate environments, and headless setups.
|
|
50
50
|
|
|
51
51
|
### [CLI authentication](https://docs.kici.dev/user/cli-auth/)
|
|
52
52
|
|
|
@@ -249,10 +249,10 @@ The lock file (`kici.lock.json`) is a JSON representation of your workflow that
|
|
|
249
249
|
|
|
250
250
|
## Preview trigger matching
|
|
251
251
|
|
|
252
|
-
Use `kici
|
|
252
|
+
Use `kici preview` to preview which workflows match a trigger event (dry-run, no execution):
|
|
253
253
|
|
|
254
254
|
```bash
|
|
255
|
-
npx kici
|
|
255
|
+
npx kici preview pr:open
|
|
256
256
|
```
|
|
257
257
|
|
|
258
258
|
Expected output (simplified):
|
|
@@ -418,14 +418,14 @@ Or add the flag to your root `package.json`:
|
|
|
418
418
|
|
|
419
419
|
## Authoring KiCI workflows with LLM coding agents
|
|
420
420
|
|
|
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
|
|
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.
|
|
422
422
|
|
|
423
423
|
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
424
|
|
|
425
425
|
- where the SDK type declarations live (`node_modules/@kici-dev/sdk/dist/index.d.ts`)
|
|
426
426
|
- the five canonical authoring patterns with runnable examples
|
|
427
427
|
- 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
|
|
428
|
+
- the local commands the agent should drive (`kici compile --check`, `kici preview`, `kici run local`, `kici docs llm`)
|
|
429
429
|
|
|
430
430
|
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
431
|
|
|
@@ -516,7 +516,7 @@ If you're not sure, pick Docker / Podman.
|
|
|
516
516
|
|
|
517
517
|
## Looking for the laptop-only path?
|
|
518
518
|
|
|
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
|
|
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.
|
|
520
520
|
|
|
521
521
|
---
|
|
522
522
|
|
|
@@ -2650,7 +2650,7 @@ const deploy = job('deploy', {
|
|
|
2650
2650
|
|
|
2651
2651
|
**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
2652
|
|
|
2653
|
-
Cross-job output chaining works in both local
|
|
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.
|
|
2654
2654
|
|
|
2655
2655
|
### Job dependencies (`needs`)
|
|
2656
2656
|
|
|
@@ -3316,6 +3316,88 @@ The caller never has to branch on outcome — `result.result` is always a `Bucke
|
|
|
3316
3316
|
|
|
3317
3317
|
---
|
|
3318
3318
|
|
|
3319
|
+
## SDK reference: parallel
|
|
3320
|
+
|
|
3321
|
+
Source: https://docs.kici.dev/user/sdk/parallel/
|
|
3322
|
+
|
|
3323
|
+
`parallel([...steps], opts?)` runs a group of independent steps **concurrently**
|
|
3324
|
+
within one job, behind a join barrier: execution continues past the group only
|
|
3325
|
+
once every child has settled. Each child is its own observable step — it gets its
|
|
3326
|
+
own logs, status, timing, and retry — instead of being hidden inside one step's
|
|
3327
|
+
`Promise.all`.
|
|
3328
|
+
|
|
3329
|
+
```ts
|
|
3330
|
+
import { workflow, job, step, parallel, push } from '@kici-dev/sdk';
|
|
3331
|
+
|
|
3332
|
+
export default workflow('ci', {
|
|
3333
|
+
on: push(),
|
|
3334
|
+
jobs: [
|
|
3335
|
+
job('checks', {
|
|
3336
|
+
runsOn: 'kici:os:linux',
|
|
3337
|
+
steps: [
|
|
3338
|
+
checkout,
|
|
3339
|
+
// lint, typecheck, and the unit tests have no ordering between them,
|
|
3340
|
+
// so they run together — the job's wall-clock is the slowest child,
|
|
3341
|
+
// not the sum of all three.
|
|
3342
|
+
parallel([lint, typecheck, unitTests], { failFast: true }),
|
|
3343
|
+
deploy,
|
|
3344
|
+
],
|
|
3345
|
+
}),
|
|
3346
|
+
],
|
|
3347
|
+
});
|
|
3348
|
+
```
|
|
3349
|
+
|
|
3350
|
+
`parallel(...)` returns a `ParallelGroup` that sits in the ordinary flat
|
|
3351
|
+
`steps: [...]` array — there is no new `job` field. A group's children are
|
|
3352
|
+
**sequential steps only**; groups cannot be nested.
|
|
3353
|
+
|
|
3354
|
+
## Options
|
|
3355
|
+
|
|
3356
|
+
`parallel(steps, opts?)` accepts:
|
|
3357
|
+
|
|
3358
|
+
- **`failFast?: boolean`** — default `true`. When a child fails, the in-flight
|
|
3359
|
+
siblings are cancelled immediately and the job fails. With `failFast: false`
|
|
3360
|
+
every child runs to completion first, then the job fails if any child failed.
|
|
3361
|
+
- **`maxParallel?: number`** — default unlimited. Caps how many children run at
|
|
3362
|
+
once; children waiting for a slot report a `pending` status until they launch.
|
|
3363
|
+
- **`name?: string`** — a label for the group's dashboard band.
|
|
3364
|
+
|
|
3365
|
+
A child marked `continueOnError: true` never trips fail-fast and never fails the
|
|
3366
|
+
job — it still shows a `failed` status badge, but the group treats it as
|
|
3367
|
+
non-fatal.
|
|
3368
|
+
|
|
3369
|
+
## Statuses
|
|
3370
|
+
|
|
3371
|
+
Parallel steps introduce two step statuses:
|
|
3372
|
+
|
|
3373
|
+
- **`pending`** — a child queued behind `maxParallel`, not yet launched.
|
|
3374
|
+
- **`cancelled`** — a sibling aborted by fail-fast. A cancelled step is **not** a
|
|
3375
|
+
failure: only the child that actually failed fails the job; the cancelled
|
|
3376
|
+
siblings render in gray (distinct from the red failing step) on the dashboard.
|
|
3377
|
+
|
|
3378
|
+
Children may also complete **out of order** — the fastest child finishes first
|
|
3379
|
+
regardless of array position. A later sequential step can read a parallel child's
|
|
3380
|
+
`.result` after the barrier; children within a group cannot read each other's
|
|
3381
|
+
results (there is no ordering inside the group).
|
|
3382
|
+
|
|
3383
|
+
## Scope: nests inside job-level fan-out
|
|
3384
|
+
|
|
3385
|
+
`parallel()`'s `failFast` / `maxParallel` are **step-group** scopes — they govern
|
|
3386
|
+
only the steps inside the group. They are a different layer from the **job-level**
|
|
3387
|
+
`failFast` / `maxParallel` on a matrix / `runsOnAll` fan-out, which govern how a
|
|
3388
|
+
job's child _jobs_ spread across the matrix or host roster. A `parallel()` group
|
|
3389
|
+
inside a fan-out job nests its concurrency inside each fan-out child.
|
|
3390
|
+
|
|
3391
|
+
## Local vs remote execution
|
|
3392
|
+
|
|
3393
|
+
Run remotely (the orchestrator + agent), parallel children execute concurrently
|
|
3394
|
+
and each surfaces as its own dashboard step. `kici run local` executes the same
|
|
3395
|
+
children in array order in its single-process model — the results are identical,
|
|
3396
|
+
only the wall-clock and the live fail-fast cancellation differ. Use a remote run
|
|
3397
|
+
to observe the concurrent timeline.
|
|
3398
|
+
|
|
3399
|
+
---
|
|
3400
|
+
|
|
3319
3401
|
## SDK reference: rules, matrix, dynamic jobs
|
|
3320
3402
|
|
|
3321
3403
|
Source: https://docs.kici.dev/user/sdk/rules-matrix-dynamic/
|
|
@@ -4214,7 +4296,7 @@ interface StepContext<TInputs = Record<string, unknown>> {
|
|
|
4214
4296
|
rawPayload?: Record<string, unknown>;
|
|
4215
4297
|
/** Which git provider triggered this workflow (e.g. 'github', 'gitlab') */
|
|
4216
4298
|
provider?: string;
|
|
4217
|
-
/** Whether this execution was triggered by `kici
|
|
4299
|
+
/** Whether this execution was triggered by `kici run remote` (developer-initiated remote run) */
|
|
4218
4300
|
isTestRun: boolean;
|
|
4219
4301
|
/** The resolved deployment environment name for this job (undefined without environment) */
|
|
4220
4302
|
environment?: string;
|
|
@@ -4611,7 +4693,7 @@ Tools that require a file path on disk (sops `SOPS_AGE_KEY_FILE`, kubectl `KUBEC
|
|
|
4611
4693
|
|
|
4612
4694
|
### Local test mode secrets
|
|
4613
4695
|
|
|
4614
|
-
When running `kici
|
|
4696
|
+
When running `kici preview`, you can provide secrets locally without an orchestrator.
|
|
4615
4697
|
|
|
4616
4698
|
#### .kici/.secrets file
|
|
4617
4699
|
|
|
@@ -4639,10 +4721,10 @@ Override or supplement file-based secrets with CLI flags:
|
|
|
4639
4721
|
|
|
4640
4722
|
```bash
|
|
4641
4723
|
# Inject flat secrets (repeatable)
|
|
4642
|
-
kici
|
|
4724
|
+
kici preview push --secret DEPLOY_TOKEN=my-token --secret API_KEY=my-key
|
|
4643
4725
|
|
|
4644
4726
|
# Inject context-scoped secrets (repeatable)
|
|
4645
|
-
kici
|
|
4727
|
+
kici preview push --context production.DB_PASSWORD=prod-secret --context npm-publish.NPM_TOKEN=abc123
|
|
4646
4728
|
```
|
|
4647
4729
|
|
|
4648
4730
|
**Precedence:** CLI flags override `.kici/.secrets` file values. Context secrets are auto-flattened into `ctx.secrets` using the same merge logic as production (last context wins).
|
|
@@ -5197,6 +5279,7 @@ interface ScheduleConfigInput {
|
|
|
5197
5279
|
cron: string; // Required: cron expression (5-field)
|
|
5198
5280
|
timezone?: string; // Timezone for cron evaluation (default: 'UTC')
|
|
5199
5281
|
description?: string; // Human-readable description of the schedule
|
|
5282
|
+
inputs?: DispatchInputsMap; // Optional: defaults-only typed inputs (see below)
|
|
5200
5283
|
}
|
|
5201
5284
|
```
|
|
5202
5285
|
|
|
@@ -5207,6 +5290,41 @@ schedule({ cron: '0 9 * * 1', timezone: 'America/New_York' }); // Monday 9am ET
|
|
|
5207
5290
|
schedule({ cron: '*/15 * * * *', description: 'health check every 15 min' });
|
|
5208
5291
|
```
|
|
5209
5292
|
|
|
5293
|
+
#### Schedule inputs (defaults-only)
|
|
5294
|
+
|
|
5295
|
+
A `schedule()` trigger may declare typed `inputs`. A cron or dashboard
|
|
5296
|
+
"run now" fire carries **no operator-supplied values**, so each input resolves
|
|
5297
|
+
from its declared **default** and is exposed to steps and rules as
|
|
5298
|
+
`ctx.dispatchInputs` — the same surface as [typed dispatch inputs](https://docs.kici.dev/user/sdk/triggers/#typed-dispatch-inputs).
|
|
5299
|
+
|
|
5300
|
+
Because there is no operator to supply a value, every schedule input must
|
|
5301
|
+
declare a `.default()` **or** be `.optional()`. An input that is neither is
|
|
5302
|
+
rejected at `kici compile` time.
|
|
5303
|
+
|
|
5304
|
+
```typescript
|
|
5305
|
+
import { workflow, job, schedule, z } from '@kici-dev/sdk';
|
|
5306
|
+
|
|
5307
|
+
export default workflow('nightly', {
|
|
5308
|
+
on: schedule({
|
|
5309
|
+
cron: '0 3 * * *',
|
|
5310
|
+
inputs: { mode: z.enum(['full', 'quick']).default('full') },
|
|
5311
|
+
}),
|
|
5312
|
+
jobs: [
|
|
5313
|
+
job('build', {
|
|
5314
|
+
runsOn: 'default',
|
|
5315
|
+
run: async (ctx) => {
|
|
5316
|
+
ctx.log(`mode = ${ctx.dispatchInputs.mode}`); // "full" on every fire
|
|
5317
|
+
},
|
|
5318
|
+
}),
|
|
5319
|
+
],
|
|
5320
|
+
});
|
|
5321
|
+
```
|
|
5322
|
+
|
|
5323
|
+
You can also share a typed handle via `defineDispatchInputs(...)` and read it
|
|
5324
|
+
back with `.from(ctx)`, exactly as with `dispatch()`. The allowed input types
|
|
5325
|
+
are the same closed subset documented under
|
|
5326
|
+
[typed dispatch inputs](https://docs.kici.dev/user/sdk/triggers/#typed-dispatch-inputs).
|
|
5327
|
+
|
|
5210
5328
|
### lifecycle()
|
|
5211
5329
|
|
|
5212
5330
|
Create a lifecycle trigger for cross-workflow orchestration events. Returns a frozen `LifecycleTriggerConfig`.
|
|
@@ -5535,7 +5653,7 @@ If `check()` throws while polling, the error is logged and polling continues —
|
|
|
5535
5653
|
|
|
5536
5654
|
Source: https://docs.kici.dev/user/sdk-reference/
|
|
5537
5655
|
|
|
5538
|
-
Reference documentation for `@kici-dev/sdk`. The reference is split across
|
|
5656
|
+
Reference documentation for `@kici-dev/sdk`. The reference is split across the per-topic pages below.
|
|
5539
5657
|
|
|
5540
5658
|
| Page | Covers |
|
|
5541
5659
|
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -5547,6 +5665,7 @@ Reference documentation for `@kici-dev/sdk`. The reference is split across five
|
|
|
5547
5665
|
| [Runtime](https://docs.kici.dev/user/sdk/runtime/) | Types index, `StepContext`, secrets, and fixtures. |
|
|
5548
5666
|
| [Idempotent helpers](https://docs.kici.dev/user/sdk/idempotent/) | `idempotent()`, `idempotentStep()`, and the check-mode-aware `checkStep()` — check / apply pattern with typed results on both the skipped and applied branches. |
|
|
5549
5667
|
| [Wait-for helpers](https://docs.kici.dev/user/sdk/wait-for/) | `waitFor()` and `waitForStep()` — poll a condition on an interval, run an optional success action, recover gracefully on timeout. |
|
|
5668
|
+
| [Parallel steps](https://docs.kici.dev/user/sdk/parallel/) | `parallel()` — run independent steps concurrently within one job behind a join barrier, each as its own observable step, with `failFast` and `maxParallel` controls. |
|
|
5550
5669
|
|
|
5551
5670
|
The `@kici-dev/sdk` package re-exports the entire surface from a single entry point. Pick what you need:
|
|
5552
5671
|
|
|
@@ -5569,6 +5688,272 @@ For the complete list of every named export (factory functions, triggers, rules,
|
|
|
5569
5688
|
|
|
5570
5689
|
# CLI and authoring
|
|
5571
5690
|
|
|
5691
|
+
## Drive KiCI from your coding agent
|
|
5692
|
+
|
|
5693
|
+
Source: https://docs.kici.dev/user/ai-agents/
|
|
5694
|
+
|
|
5695
|
+
KiCI ships a hosted **MCP server** so a coding agent (Claude Code, or any MCP
|
|
5696
|
+
client) can drive your CI directly: trigger runs, read a structured result,
|
|
5697
|
+
fetch the failing step's logs, cancel, and re-run — all under an agent identity
|
|
5698
|
+
you control, org-scoped, and audited. There are no per-tool tokens to configure:
|
|
5699
|
+
point the agent at one URL with one credential and it's done.
|
|
5700
|
+
|
|
5701
|
+
The MCP exposes only what you can already do yourself through the `kici` CLI and
|
|
5702
|
+
the dashboard. It is not a new privileged surface — every tool maps to an
|
|
5703
|
+
existing user-facing operation and is gated by the same permissions your role
|
|
5704
|
+
grants.
|
|
5705
|
+
|
|
5706
|
+
## 1. Mint an agent credential
|
|
5707
|
+
|
|
5708
|
+
The MCP accepts an **agent-kind credential** — and only an agent-kind one. It
|
|
5709
|
+
can be either of two kinds:
|
|
5710
|
+
|
|
5711
|
+
- An **agent personal access token (PAT)** that you own — it acts as you, with
|
|
5712
|
+
your provenance. The token is `kici_pat_…`.
|
|
5713
|
+
- An **agent org API key** that belongs to your organization — a
|
|
5714
|
+
provenance-carrying service account, independent of any one person. The key is
|
|
5715
|
+
`kici_sk_…`.
|
|
5716
|
+
|
|
5717
|
+
Both drive the MCP identically. A non-agent token of either kind (a plain user
|
|
5718
|
+
PAT, a plain org API key) is refused at the door.
|
|
5719
|
+
|
|
5720
|
+
**Option A — an agent PAT.** Mint one with the `kici` CLI (log in first with
|
|
5721
|
+
`kici login`):
|
|
5722
|
+
|
|
5723
|
+
```bash
|
|
5724
|
+
kici pat create --agent --name "claude-code"
|
|
5725
|
+
```
|
|
5726
|
+
|
|
5727
|
+
The `--name` value is the **agent label**. It is recorded on every action the
|
|
5728
|
+
agent takes, so your audit log shows exactly which agent did what (and on whose
|
|
5729
|
+
behalf). The token is printed once — save it now; it cannot be retrieved later.
|
|
5730
|
+
|
|
5731
|
+
**Option B — an agent org API key.** Create one from the dashboard's
|
|
5732
|
+
**Settings → API keys** tab: set the key's kind to **Agent** and give it an
|
|
5733
|
+
agent name (the agent label). The same key can also be minted with
|
|
5734
|
+
`kici-platform-admin user api-key create --org <id> --agent --agent-label <label>`.
|
|
5735
|
+
Reach for an org agent key when the agent should act as a shared service account
|
|
5736
|
+
rather than as a single user — for example, a long-lived CI bot that outlives any
|
|
5737
|
+
individual's membership.
|
|
5738
|
+
|
|
5739
|
+
Whichever you pick, the credential carries provenance, not extra authority. Its
|
|
5740
|
+
effective permissions are the matrix it was minted with, and that matrix can
|
|
5741
|
+
never exceed the permissions of the person who created it — so you can scope an
|
|
5742
|
+
agent credential **below** your own access (for example, read-only) and the agent
|
|
5743
|
+
is held to that smaller set. Powerful operator capabilities (secret rotation,
|
|
5744
|
+
agent and peer management, draining) are intentionally **not** exposed here. See
|
|
5745
|
+
[the agent safety model](https://docs.kici.dev/user/ai-agents/#6-the-agent-safety-model) for how scoping and
|
|
5746
|
+
confinement work.
|
|
5747
|
+
|
|
5748
|
+
## 2. Point your coding agent at the MCP server
|
|
5749
|
+
|
|
5750
|
+
KiCI's hosted MCP server lives at one fixed URL:
|
|
5751
|
+
|
|
5752
|
+
```
|
|
5753
|
+
https://api.kici.dev/api/v1/mcp
|
|
5754
|
+
```
|
|
5755
|
+
|
|
5756
|
+
Configure your MCP client with that URL and your agent credential (the agent PAT
|
|
5757
|
+
or the agent org key) as a Bearer credential. For Claude Code:
|
|
5758
|
+
|
|
5759
|
+
```bash
|
|
5760
|
+
claude mcp add --transport http kici https://api.kici.dev/api/v1/mcp \
|
|
5761
|
+
--header "Authorization: Bearer <your-agent-credential>"
|
|
5762
|
+
```
|
|
5763
|
+
|
|
5764
|
+
That's the entire setup. The agent can now call the tools below.
|
|
5765
|
+
|
|
5766
|
+
## 3. What the agent can do
|
|
5767
|
+
|
|
5768
|
+
**Read**
|
|
5769
|
+
|
|
5770
|
+
- `list_runs` — recent runs in your organization.
|
|
5771
|
+
- `get_run` — the structured, provenance-tagged result of a run: the typed job
|
|
5772
|
+
graph, per-step statuses and exit codes, durations, and a derived failure
|
|
5773
|
+
category.
|
|
5774
|
+
- `get_step_logs` — the log lines for a specific step.
|
|
5775
|
+
- `list_workflows` — your registered workflows, optionally filtered by
|
|
5776
|
+
`triggerType`, `repo`, or `stale` (only those not triggered within a duration
|
|
5777
|
+
like `30d`).
|
|
5778
|
+
- `list_orgs` — the organizations you belong to. Use it to discover the `orgId`
|
|
5779
|
+
to pass to the other tools when you're a member of more than one.
|
|
5780
|
+
- `list_secrets` — the secret scopes in your organization and the **key names**
|
|
5781
|
+
each holds. Secret values are never returned — only the names.
|
|
5782
|
+
- `list_orchestrators` — the connected orchestrator clusters your runs execute
|
|
5783
|
+
on (cluster name, routing keys, version, scaler backends, health).
|
|
5784
|
+
- `get_diagnostics` — your organization's execution metrics over the last 24
|
|
5785
|
+
hours (run count, success rate, average duration, queued and running jobs)
|
|
5786
|
+
plus per-orchestrator connection health.
|
|
5787
|
+
|
|
5788
|
+
**Drive**
|
|
5789
|
+
|
|
5790
|
+
- `trigger_run` — run a registered workflow ("run now").
|
|
5791
|
+
- `rerun_run` — re-run a completed run.
|
|
5792
|
+
- `cancel_run` — cancel an in-progress run.
|
|
5793
|
+
- `approve_run` — approve a held approval gate for a run (name the run, plus
|
|
5794
|
+
`job`/`step` to disambiguate when it has multiple holds).
|
|
5795
|
+
- `reject_run` — reject a held approval gate; a `reason` is required.
|
|
5796
|
+
- `cancel_runs_by_branch` — cancel all in-progress runs on a branch (bounded —
|
|
5797
|
+
up to 100 per call; a `truncated` flag tells the agent to re-invoke).
|
|
5798
|
+
|
|
5799
|
+
The tools cover the same developer operations you can drive yourself with the
|
|
5800
|
+
`kici` CLI. Operations that are purely local to your machine (scaffolding,
|
|
5801
|
+
compiling, running a workflow locally) or that mint credentials are
|
|
5802
|
+
intentionally not exposed — the agent works against your deployed CI, not your
|
|
5803
|
+
filesystem.
|
|
5804
|
+
|
|
5805
|
+
If you belong to a single organization, the org is resolved automatically. If
|
|
5806
|
+
you belong to several, pass an `orgId` argument to any tool (use `list_orgs` to
|
|
5807
|
+
find it).
|
|
5808
|
+
|
|
5809
|
+
### Limits and pagination
|
|
5810
|
+
|
|
5811
|
+
The MCP server applies a few bounds so an agent loop can't overwhelm the shared
|
|
5812
|
+
infrastructure. They are agent-visible — your agent gets a clear tool error and
|
|
5813
|
+
should back off or page, never a silent truncation:
|
|
5814
|
+
|
|
5815
|
+
- **Per-token request limits.** Each agent token has its own ceiling, refreshed
|
|
5816
|
+
every minute: **120 reads/minute** (listing and fetching runs, step logs, and
|
|
5817
|
+
workflows) and **20 run actions/minute** (cancel, re-run, trigger, approve,
|
|
5818
|
+
reject, cancel-by-branch). The two
|
|
5819
|
+
budgets are independent. An over-limit call returns a tool error telling the
|
|
5820
|
+
agent which kind of operation was throttled and how many seconds to wait
|
|
5821
|
+
before retrying.
|
|
5822
|
+
- **Paginated step logs.** `get_step_logs` returns log lines in pages. Pass a
|
|
5823
|
+
`limit` to bound a page (capped server-side) and follow the returned
|
|
5824
|
+
`nextCursor` (as `cursor` on the next call) to read more. A large step log is
|
|
5825
|
+
paged, never silently cut off — when `nextCursor` is null you've reached the
|
|
5826
|
+
end.
|
|
5827
|
+
- **Bounded run results.** `get_run` returns the structured run result, which is
|
|
5828
|
+
naturally bounded by workflow size. For a pathologically large run it returns a
|
|
5829
|
+
tool error directing the agent to inspect specific steps with `get_step_logs`
|
|
5830
|
+
instead.
|
|
5831
|
+
|
|
5832
|
+
## 4. Why the structured result is agent-safe
|
|
5833
|
+
|
|
5834
|
+
Every tool returns a machine-first shape designed for an agent to reason over
|
|
5835
|
+
without being misled by repository content. Each field that comes from your repo,
|
|
5836
|
+
a contributor, or a process's output — workflow and job names, refs, error
|
|
5837
|
+
messages, log lines, job outputs — is delivered **fenced** as untrusted data:
|
|
5838
|
+
wrapped in a per-response, randomly-named delimiter (`⟦u:<nonce>⟧…⟦/u:<nonce>⟧`),
|
|
5839
|
+
with the result prefixed by a notice that fenced text is data, never instructions.
|
|
5840
|
+
KiCI-generated values (ids, statuses, exit codes, durations, the derived failure
|
|
5841
|
+
category) are left plain. So an agent can keep user-controlled content out of its
|
|
5842
|
+
instruction channel by treating anything inside a fence as data only. See
|
|
5843
|
+
[Untrusted content and prompt injection](https://docs.kici.dev/user/ai-agents/#7-untrusted-content-and-prompt-injection)
|
|
5844
|
+
for the full model.
|
|
5845
|
+
|
|
5846
|
+
Secret values are never returned — only the names of the secret keys a step
|
|
5847
|
+
accessed.
|
|
5848
|
+
|
|
5849
|
+
## 5. The audit guarantee
|
|
5850
|
+
|
|
5851
|
+
Because the MCP accepts only an agent-kind credential, **every action that flows
|
|
5852
|
+
through it is agent-attributed by construction** — there is no path that produces
|
|
5853
|
+
an untagged, human-looking action. Each read and each drive operation is recorded
|
|
5854
|
+
in your orchestrator's access log under the acting identity plus the agent label,
|
|
5855
|
+
so you always have a complete trail of what your agent did.
|
|
5856
|
+
|
|
5857
|
+
Inspect that trail with `kici-admin access-log list --json` (or
|
|
5858
|
+
`kici-admin access-log show <id>` for one entry). The acting identity depends on
|
|
5859
|
+
which credential you used:
|
|
5860
|
+
|
|
5861
|
+
- An **agent PAT** keeps `actor_type` as `user` and `actor_id` as your own
|
|
5862
|
+
identity — the agent provenance rides in the actor metadata as `agentLabel`
|
|
5863
|
+
(the `--name` you minted the PAT with) and `agentPatId`.
|
|
5864
|
+
- An **agent org key** keeps `actor_type` as `api_key` and `actor_id` as the key
|
|
5865
|
+
— the same `agentLabel` provenance rides in its actor metadata.
|
|
5866
|
+
|
|
5867
|
+
Either way the label is stored in a dedicated `agent_label` column on every such
|
|
5868
|
+
row, so you can filter the access log down to just agent activity:
|
|
5869
|
+
|
|
5870
|
+
```bash
|
|
5871
|
+
# Every action a specific agent took, by its label:
|
|
5872
|
+
kici-admin access-log list --agent-label "claude-code"
|
|
5873
|
+
|
|
5874
|
+
# Every agent-attributed action, across all agents:
|
|
5875
|
+
kici-admin access-log list --agent-only
|
|
5876
|
+
```
|
|
5877
|
+
|
|
5878
|
+
In the dashboard, agent-driven activity is visually distinguished: the
|
|
5879
|
+
[Activity](https://docs.kici.dev/user/dashboard/activity-and-dlq/#activity) log renders an **agent badge**
|
|
5880
|
+
on every agent-attributed row, and a run's **Triggered by** shows the same badge
|
|
5881
|
+
when an agent triggered or cancelled it — so an agent's footprint is obvious at a
|
|
5882
|
+
glance, not buried in metadata.
|
|
5883
|
+
|
|
5884
|
+
## 6. The agent safety model
|
|
5885
|
+
|
|
5886
|
+
KiCI treats a coding agent as a **least-privilege principal with its own token**,
|
|
5887
|
+
not as an unscoped extension of you. Three properties make the agent
|
|
5888
|
+
"confined and audited by construction":
|
|
5889
|
+
|
|
5890
|
+
**Least-privilege, capped at the creator.** An agent token is scoped when you
|
|
5891
|
+
mint it. Leave the scope open and it inherits your role; narrow it and the agent
|
|
5892
|
+
is held to that smaller set — its effective permissions are always the
|
|
5893
|
+
**minimum** of your role and the token's scope. A token can never grant more than
|
|
5894
|
+
you hold, so an agent cannot escalate beyond its creator.
|
|
5895
|
+
|
|
5896
|
+
**Fail-closed denial, on every surface the token is used.** The scope is enforced
|
|
5897
|
+
wherever the token acts — the MCP tools the agent drives **and** any direct API
|
|
5898
|
+
call made with the raw token. When the agent attempts something outside its
|
|
5899
|
+
scope (driving a run with a read-only token, reading members it wasn't granted),
|
|
5900
|
+
the action is **refused fail-closed**: it does not run, nothing is changed, and a
|
|
5901
|
+
clear "insufficient permission" error comes back. There is no fallback path that
|
|
5902
|
+
quietly lets a denied action through.
|
|
5903
|
+
|
|
5904
|
+
**Every decision is audited — allowed and denied alike.** Allowed actions are
|
|
5905
|
+
recorded in your access log under your identity plus the agent label, exactly as
|
|
5906
|
+
described in [the audit guarantee](https://docs.kici.dev/user/ai-agents/#5-the-audit-guarantee). **Denials are audited
|
|
5907
|
+
too:** each refused action lands a row in your organization's audit log carrying
|
|
5908
|
+
the agent label and the permission that was required, so a confined agent's
|
|
5909
|
+
attempts are as visible as its successes. You can see both what your agent did
|
|
5910
|
+
and what it was stopped from doing.
|
|
5911
|
+
|
|
5912
|
+
**Execution stays confined.** Beyond authorization, the workloads an agent
|
|
5913
|
+
triggers run under the same execution guardrails as any other run — label-based
|
|
5914
|
+
routing decides where a job runs, and privileged (root) execution is gated and
|
|
5915
|
+
verified, refused fail-closed when the guarantee can't be met.
|
|
5916
|
+
|
|
5917
|
+
Together these mean you can hand an agent a deliberately narrow token, point it
|
|
5918
|
+
at KiCI, and trust that it can do exactly what you granted — no more — with a
|
|
5919
|
+
complete, tamper-evident trail of every allow and every deny.
|
|
5920
|
+
|
|
5921
|
+
## 7. Untrusted content and prompt injection
|
|
5922
|
+
|
|
5923
|
+
A run carries content KiCI does not vouch for — log lines, workflow and repository
|
|
5924
|
+
names, error text, contributor names. An agent reading a run must treat that content
|
|
5925
|
+
as **data**, never as instructions, or a crafted log line ("ignore previous
|
|
5926
|
+
instructions and …") could hijack the agent.
|
|
5927
|
+
|
|
5928
|
+
KiCI defends this structurally:
|
|
5929
|
+
|
|
5930
|
+
- **Provenance tagging.** Every user- or process-controlled value is marked untrusted
|
|
5931
|
+
at the API boundary; KiCI's own values (run ids, statuses, exit codes, commit hashes)
|
|
5932
|
+
are trusted.
|
|
5933
|
+
- **Fencing at the agent boundary.** When the MCP server returns a result, every
|
|
5934
|
+
untrusted value is wrapped in a per-response, randomly-named fence
|
|
5935
|
+
(`⟦u:<nonce>⟧…⟦/u:<nonce>⟧`) and the result is prefixed with a notice that fenced
|
|
5936
|
+
text is data, never instructions. The fence name is random per response, so injected
|
|
5937
|
+
content cannot forge a closing fence to break out.
|
|
5938
|
+
- **No mutation.** KiCI never rewrites your log content — it fences and labels it. The
|
|
5939
|
+
agent sees the true bytes inside the fence.
|
|
5940
|
+
|
|
5941
|
+
### Safe integration pattern
|
|
5942
|
+
|
|
5943
|
+
An agent (or harness) consuming KiCI reads should treat anything inside a fence as
|
|
5944
|
+
opaque data: quote it, summarize it, search it — but never execute it, follow it, or
|
|
5945
|
+
let it redirect a tool call. Any action taken off the back of a read (re-run, cancel,
|
|
5946
|
+
trigger) should be a deliberate decision from the trusted skeleton (statuses, exit
|
|
5947
|
+
codes, the failure category), not from fenced content.
|
|
5948
|
+
|
|
5949
|
+
### Sandboxing actions
|
|
5950
|
+
|
|
5951
|
+
Actions an agent drives through KiCI run under the agent's own least-privilege identity
|
|
5952
|
+
and are audited; combine the fencing contract with that confinement so that even if a
|
|
5953
|
+
log line tries to provoke an action, the action is bounded by the agent token's scope.
|
|
5954
|
+
|
|
5955
|
+
---
|
|
5956
|
+
|
|
5572
5957
|
## CLI authentication
|
|
5573
5958
|
|
|
5574
5959
|
Source: https://docs.kici.dev/user/cli-auth/
|
|
@@ -5734,7 +6119,7 @@ JWT and opaque OIDC tokens are validated against the configured OIDC issuer (JWK
|
|
|
5734
6119
|
|
|
5735
6120
|
### Permissions
|
|
5736
6121
|
|
|
5737
|
-
Tokens authenticate; RBAC authorizes. Every org-scoped route runs `orgContextMiddleware` (verifies you are a member of the target org) followed by `requirePermission(resource, level)`. The
|
|
6122
|
+
Tokens authenticate; RBAC authorizes. Every org-scoped route runs `orgContextMiddleware` (verifies you are a member of the target org) followed by `requirePermission(resource, level)`. The 18 resources and 5 levels are documented in [RBAC](https://docs.kici.dev/architecture/security/rbac/#permission-model). User API keys carry their own permission matrix bounded above by the creator's effective permissions; PATs inherit the user's role permissions (or are capped further by their `scopes` field).
|
|
5738
6123
|
|
|
5739
6124
|
### Configurable surfaces
|
|
5740
6125
|
|
|
@@ -5851,7 +6236,7 @@ Run commands with `npx kici` or add scripts to your `package.json`:
|
|
|
5851
6236
|
{
|
|
5852
6237
|
"scripts": {
|
|
5853
6238
|
"kici:compile": "kici compile",
|
|
5854
|
-
"kici:
|
|
6239
|
+
"kici:preview": "kici preview"
|
|
5855
6240
|
}
|
|
5856
6241
|
}
|
|
5857
6242
|
```
|
|
@@ -5946,6 +6331,8 @@ kici run local [event] [options]
|
|
|
5946
6331
|
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
5947
6332
|
| `--in-place` | `false` | Run against the real working directory instead of an isolated tmp checkout (see "Execution isolation" below) |
|
|
5948
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`) |
|
|
5949
6336
|
|
|
5950
6337
|
**Interactive workflow selection (`--pick` / `-p`):**
|
|
5951
6338
|
|
|
@@ -6087,6 +6474,12 @@ kici run remote [fixture] [options]
|
|
|
6087
6474
|
| `--target-allow-empty` | `false` | A `--target` that narrows a `runsOnAll` job to zero hosts skips it instead of failing |
|
|
6088
6475
|
| `--debug` | `false` | Verbose internals |
|
|
6089
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
|
+
`--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.
|
|
6090
6483
|
|
|
6091
6484
|
**Examples:**
|
|
6092
6485
|
|
|
@@ -6252,12 +6645,12 @@ kici orchestrators use us-east
|
|
|
6252
6645
|
kici orchestrators use us-east --org xyz789ghi012
|
|
6253
6646
|
```
|
|
6254
6647
|
|
|
6255
|
-
### kici
|
|
6648
|
+
### kici preview
|
|
6256
6649
|
|
|
6257
6650
|
Preview which workflows match a trigger event (dry-run, no execution). Useful for verifying trigger configurations during development.
|
|
6258
6651
|
|
|
6259
6652
|
```bash
|
|
6260
|
-
kici
|
|
6653
|
+
kici preview [event] [options]
|
|
6261
6654
|
```
|
|
6262
6655
|
|
|
6263
6656
|
**Arguments:**
|
|
@@ -6284,19 +6677,19 @@ kici test [event] [options]
|
|
|
6284
6677
|
|
|
6285
6678
|
```bash
|
|
6286
6679
|
# Preview which workflows match a push event
|
|
6287
|
-
kici
|
|
6680
|
+
kici preview push
|
|
6288
6681
|
|
|
6289
6682
|
# Preview PR trigger matching
|
|
6290
|
-
kici
|
|
6683
|
+
kici preview pr:open
|
|
6291
6684
|
|
|
6292
6685
|
# Preview with branch override
|
|
6293
|
-
kici
|
|
6686
|
+
kici preview push --branch develop
|
|
6294
6687
|
|
|
6295
6688
|
# Filter to specific workflow
|
|
6296
|
-
kici
|
|
6689
|
+
kici preview push --workflow ci
|
|
6297
6690
|
|
|
6298
6691
|
# Simulate changed files for path-filtered triggers
|
|
6299
|
-
kici
|
|
6692
|
+
kici preview push --files src/index.ts --files README.md
|
|
6300
6693
|
```
|
|
6301
6694
|
|
|
6302
6695
|
**Exit codes:**
|
|
@@ -6306,7 +6699,7 @@ kici test push --files src/index.ts --files README.md
|
|
|
6306
6699
|
| 0 | Preview completed (including zero matches) |
|
|
6307
6700
|
| 1 | Error |
|
|
6308
6701
|
|
|
6309
|
-
**Migration from old `
|
|
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 local <event>`.
|
|
6310
6703
|
|
|
6311
6704
|
### kici login
|
|
6312
6705
|
|
|
@@ -6316,7 +6709,7 @@ By default, `kici login` opens your browser for OIDC authentication using PKCE.
|
|
|
6316
6709
|
|
|
6317
6710
|
After OAuth, the CLI exchanges the OIDC token for a personal access token (PAT) stored in the config directory (`~/.kici/config` by default, overridable with `KICI_CONFIG_DIR`).
|
|
6318
6711
|
|
|
6319
|
-
`kici login` targets the hosted KiCI Platform by default. To authenticate against another environment (a
|
|
6712
|
+
`kici login` targets the hosted KiCI Platform by default. To authenticate against another KiCI environment (staging, or a testing OIDC provider, for example), pass `--platform-endpoint` / `--oidc-issuer` or set `KICI_PLATFORM_URL` / `KICI_OIDC_ISSUER`. Login persists the platform endpoint and OIDC issuer it authenticated against alongside the PAT, so a saved PAT always matches its endpoint. Because the config describes one environment at a time, **switching the endpoint resets the active organization and default clusters** — re-run `kici org use <name>` after switching environments.
|
|
6320
6713
|
|
|
6321
6714
|
```bash
|
|
6322
6715
|
kici login [options]
|
|
@@ -6336,9 +6729,9 @@ kici login [options]
|
|
|
6336
6729
|
|
|
6337
6730
|
| Variable | Default | Description |
|
|
6338
6731
|
| --------------------- | -------------------------------------------- | ---------------------------------------------------------------------- |
|
|
6339
|
-
| `KICI_PLATFORM_URL` | `https://api.kici.dev` | Platform API base URL (override
|
|
6340
|
-
| `KICI_OIDC_ISSUER` | `https://auth.kici.dev/realms/kici-internal` | OIDC issuer URL (override
|
|
6341
|
-
| `KICI_OIDC_CLIENT_ID` | `kici-cli` | OIDC client ID (override
|
|
6732
|
+
| `KICI_PLATFORM_URL` | `https://api.kici.dev` | Platform API base URL (override to target another KiCI environment) |
|
|
6733
|
+
| `KICI_OIDC_ISSUER` | `https://auth.kici.dev/realms/kici-internal` | OIDC issuer URL (override to target another KiCI environment) |
|
|
6734
|
+
| `KICI_OIDC_CLIENT_ID` | `kici-cli` | OIDC client ID (override to target another KiCI environment) |
|
|
6342
6735
|
| `KICI_BROWSER_CMD` | uses `open` package | Custom browser command with `{url}` placeholder, or `none` to suppress |
|
|
6343
6736
|
| `KICI_CALLBACK_PORT` | random | Fixed port for OAuth PKCE callback server |
|
|
6344
6737
|
| `KICI_CONFIG_DIR` | `~/.kici` | Override config directory |
|
|
@@ -6355,7 +6748,7 @@ kici login --device
|
|
|
6355
6748
|
# Legacy API key login
|
|
6356
6749
|
kici login --token kici_sk_abc123...
|
|
6357
6750
|
|
|
6358
|
-
# Log in against a
|
|
6751
|
+
# Log in against another KiCI environment (e.g. a testing instance)
|
|
6359
6752
|
kici login --platform-endpoint https://platform.example.com \
|
|
6360
6753
|
--oidc-issuer https://auth.example.com/realms/kici-internal
|
|
6361
6754
|
|
|
@@ -6444,7 +6837,7 @@ kici org current
|
|
|
6444
6837
|
### kici diagnostics
|
|
6445
6838
|
|
|
6446
6839
|
Show the orchestrators, scalers, and agents serving your organization — the
|
|
6447
|
-
terminal equivalent of the dashboard
|
|
6840
|
+
terminal equivalent of the dashboard Infrastructure page. Reads the same
|
|
6448
6841
|
org-scoped data the dashboard does, so it needs `kici login` and an active org
|
|
6449
6842
|
(`kici org use <name>`).
|
|
6450
6843
|
|
|
@@ -6683,6 +7076,27 @@ Only key names are shown — secret values are never returned over this endpoint
|
|
|
6683
7076
|
|
|
6684
7077
|
**Prerequisites:** authenticate via `kici login` and select an active organization with `kici org use <name>`.
|
|
6685
7078
|
|
|
7079
|
+
### kici pat create
|
|
7080
|
+
|
|
7081
|
+
Mint a personal access token under your own identity. Pass `--agent` to mint an
|
|
7082
|
+
**agent-kind** PAT — the credential a coding agent points the KiCI MCP server at.
|
|
7083
|
+
|
|
7084
|
+
```bash
|
|
7085
|
+
kici pat create --agent --name "claude-code"
|
|
7086
|
+
```
|
|
7087
|
+
|
|
7088
|
+
- `--agent` marks the token as agent-kind. An agent PAT inherits your
|
|
7089
|
+
permissions unchanged (it carries provenance, not extra authority) and is the
|
|
7090
|
+
**only** credential the MCP server accepts.
|
|
7091
|
+
- `--name <label>` sets the token name. For an agent PAT this is the **agent
|
|
7092
|
+
label** recorded on every action the agent takes — required with `--agent`.
|
|
7093
|
+
- `--expires-in-days <n>` overrides the default expiry.
|
|
7094
|
+
|
|
7095
|
+
The token is printed once — save it immediately; it cannot be retrieved later.
|
|
7096
|
+
See [Drive KiCI from your coding agent](https://docs.kici.dev/user/ai-agents/) for the full setup.
|
|
7097
|
+
|
|
7098
|
+
**Prerequisites:** authenticate via `kici login` first.
|
|
7099
|
+
|
|
6686
7100
|
### kici types
|
|
6687
7101
|
|
|
6688
7102
|
Generate TypeScript declaration files from orchestrator environment metadata. The generated `.d.ts` file augments the SDK's `KnownSecretKeys` and `EnvironmentSecrets` interfaces, providing compile-time autocomplete and type checking for secret key names.
|
|
@@ -7000,8 +7414,10 @@ kici admin drain-worker --url http://worker-2.internal:10143
|
|
|
7000
7414
|
|
|
7001
7415
|
Verify a KiCI build-provenance attestation bundle offline. A bundle is the signed package a workflow step produces via `ctx.attestProvenance(...)`: a DSSE-wrapped SLSA in-toto statement, the ephemeral public key that signed it, and the KiCI identity token that anchors the build context. For the end-to-end attest → verify → view journey, see the [build provenance guide](https://docs.kici.dev/user/provenance/). Verification establishes the full chain — the identity token verifies against the trusted issuer's JWKS, the DSSE signature verifies against the bundled key, and the statement's build context must match the token's claims (a mismatch is a hard failure). When an `[artifact]` is given, its SHA-256 digest is also matched against the attestation subject.
|
|
7002
7416
|
|
|
7417
|
+
On success the output prints the **origin org** (the customer's public org id — the authoritative "who built this" the platform vouches for) and a **source marker**. A `kici run remote` attestation is flagged unmistakably: its `repository`/`ref`/`sha` are caller-supplied from a local working-tree overlay, not a triggered VCS commit, so a verifier must treat those coordinates as org-asserted rather than VCS-verified. A normal triggered run carries the ordinary `triggered` source marker. See the [build provenance guide](https://docs.kici.dev/user/provenance/) for the full trust model.
|
|
7418
|
+
|
|
7003
7419
|
```bash
|
|
7004
|
-
kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-file> [options]
|
|
7420
|
+
kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-file>] [options]
|
|
7005
7421
|
```
|
|
7006
7422
|
|
|
7007
7423
|
**Arguments:**
|
|
@@ -7012,14 +7428,14 @@ kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-f
|
|
|
7012
7428
|
|
|
7013
7429
|
**Options:**
|
|
7014
7430
|
|
|
7015
|
-
| Option | Required | Description
|
|
7016
|
-
| ---------------------------- | -------- |
|
|
7017
|
-
| `--bundle <path-or-url>` | yes | Path or `http(s)` URL to the attestation bundle JSON.
|
|
7018
|
-
| `--trust-root <url-or-file>` |
|
|
7019
|
-
| `--audience <aud>` | no | Expected token audience (defaults to the KiCI provenance audience).
|
|
7020
|
-
| `--json` | no | Print the structured verification result as JSON instead of human-readable output.
|
|
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. |
|
|
7021
7437
|
|
|
7022
|
-
**Trust root:** the verifier never trusts the issuer named inside the token
|
|
7438
|
+
**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:
|
|
7023
7439
|
|
|
7024
7440
|
- **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`.
|
|
7025
7441
|
- **Offline — a self-contained trust-root file.** A local JSON file with the issuer and JWKS inlined, so no network access is needed (air-gapped verification):
|
|
@@ -7038,7 +7454,10 @@ kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-f
|
|
|
7038
7454
|
**Examples:**
|
|
7039
7455
|
|
|
7040
7456
|
```bash
|
|
7041
|
-
#
|
|
7457
|
+
# Default: verify against the hosted KiCI platform (no --trust-root needed)
|
|
7458
|
+
kici verify-attestation ./dist/app.tgz --bundle ./app.tgz.kici.json
|
|
7459
|
+
|
|
7460
|
+
# Override: verify a bundle against a specific issuer, digest-checking the artifact
|
|
7042
7461
|
kici verify-attestation ./dist/app.tgz \
|
|
7043
7462
|
--bundle ./app.tgz.kici.json \
|
|
7044
7463
|
--trust-root https://platform.example/issuer
|
|
@@ -7053,12 +7472,23 @@ kici verify-attestation --bundle ./app.tgz.kici.json \
|
|
|
7053
7472
|
--trust-root https://platform.example/issuer --json
|
|
7054
7473
|
```
|
|
7055
7474
|
|
|
7475
|
+
**Attestation origin marker.** On a PASS, the command surfaces when the identity
|
|
7476
|
+
token was minted relative to the build. A normal attestation prints no marker
|
|
7477
|
+
(the token was minted live). A **deferred** attestation prints an `ATTESTATION:
|
|
7478
|
+
deferred` line — the build facts were sealed at build time and the token was
|
|
7479
|
+
minted later, after a transient platform outage, bound to the frozen statement
|
|
7480
|
+
by its hash. An **offline-backfill** attestation prints an `ATTESTATION:
|
|
7481
|
+
offline-backfill` line — the run was ingested while the platform was down, so its
|
|
7482
|
+
run/job rows were backfilled before the token was minted. Both still verify
|
|
7483
|
+
(PASS); the marker discloses the temporal gap, and the organization id remains
|
|
7484
|
+
the authoritative anchor.
|
|
7485
|
+
|
|
7056
7486
|
**Exit codes:**
|
|
7057
7487
|
|
|
7058
|
-
| Code | Meaning
|
|
7059
|
-
| ---- |
|
|
7060
|
-
| 0 | Verified — signature, identity, build context (and digest, if checked) all pass
|
|
7061
|
-
| 1 | Not verified, or an error (missing
|
|
7488
|
+
| Code | Meaning |
|
|
7489
|
+
| ---- | ----------------------------------------------------------------------------------------- |
|
|
7490
|
+
| 0 | Verified — signature, identity, build context (and digest, if checked) all pass |
|
|
7491
|
+
| 1 | Not verified, or an error (missing `--bundle`, unreadable bundle, unreachable trust root) |
|
|
7062
7492
|
|
|
7063
7493
|
## Workflow discovery
|
|
7064
7494
|
|
|
@@ -7100,7 +7530,7 @@ All commands follow a consistent exit code convention:
|
|
|
7100
7530
|
|
|
7101
7531
|
## Debug output
|
|
7102
7532
|
|
|
7103
|
-
Use `--debug` (on `kici run local`, `kici run remote`, `kici
|
|
7533
|
+
Use `--debug` (on `kici run local`, `kici run remote`, `kici preview`) or `--verbose` (on `kici compile`) for detailed output:
|
|
7104
7534
|
|
|
7105
7535
|
```bash
|
|
7106
7536
|
# Shows trigger matching, rule evaluation, decision traces
|
|
@@ -7110,7 +7540,7 @@ kici run local push --debug
|
|
|
7110
7540
|
kici compile --verbose
|
|
7111
7541
|
|
|
7112
7542
|
# Shows trigger matching preview
|
|
7113
|
-
kici
|
|
7543
|
+
kici preview pr:open --debug
|
|
7114
7544
|
```
|
|
7115
7545
|
|
|
7116
7546
|
Set `KICI_DEBUG=true` for additional internal debug output across all commands.
|
|
@@ -7391,7 +7821,7 @@ The lock file (`kici.lock.json`) is a JSON file with the following top-level fie
|
|
|
7391
7821
|
|
|
7392
7822
|
| Field | Description |
|
|
7393
7823
|
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7394
|
-
| `schemaVersion` | Lock file schema version (currently
|
|
7824
|
+
| `schemaVersion` | Lock file schema version (currently 29). Incremented on breaking format changes. |
|
|
7395
7825
|
| `source` | Reference to the source file and export (e.g., `{ file: “.kici/workflows/ci.ts”, export: “#default” }`). |
|
|
7396
7826
|
| `contentHash` | SHA-256 of the serialized lock file content (excluding itself). Changes when any workflow, trigger, or job changes. |
|
|
7397
7827
|
| `lockfileHash` | SHA-256 of the detected package manager's lockfile, used as the dependency cache key. The lockfile is `.kici/package-lock.json` for npm, or the repo-root `pnpm-lock.yaml` / `yarn.lock` for a pnpm/yarn workspace; the hash input is prefixed with the manager name so a manager change is a guaranteed cache miss. Omitted when no lockfile exists. |
|
|
@@ -7514,7 +7944,7 @@ Test your workflows remotely against the full CI pipeline from your local machin
|
|
|
7514
7944
|
- Give test runs test-scoped secrets — your local secret files and `--env` values (uploaded encrypted) plus any environment flagged `allowLocalExecution: true` — while production environments stay unreachable
|
|
7515
7945
|
- Detect test mode in workflow code via `ctx.isTestRun`
|
|
7516
7946
|
|
|
7517
|
-
The command is remote-only -- all execution happens on the orchestrator and agent. For local-only trigger matching previews, use `kici
|
|
7947
|
+
The command is remote-only -- all execution happens on the orchestrator and agent. For local-only trigger matching previews, use `kici preview <event>`.
|
|
7518
7948
|
|
|
7519
7949
|
:::note[Orchestrator prerequisite: cache storage]
|
|
7520
7950
|
`kici run remote` uploads your working-tree overlay to the orchestrator's **cache storage** via a pre-signed URL, and the agent fetches it from there (see [Repo state transfer](https://docs.kici.dev/user/testing-guide/#repo-state-transfer)). The target orchestrator must therefore have cache storage enabled (`KICI_STORAGE_TYPE` = `s3` or `filesystem`).
|
|
@@ -7646,6 +8076,8 @@ This mapping is honored by **both** `kici run local` and `kici run remote`:
|
|
|
7646
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).
|
|
7647
8077
|
- For **`kici run remote`**, each named context maps to an orchestrator **environment**, and the orchestrator resolves that environment's secrets for the run. The target environment must be flagged `allowLocalExecution: true` — mapping a context to a missing or non-test environment rejects the run (see [Secret contexts for testing](https://docs.kici.dev/user/testing-guide/#secret-contexts-for-testing) below).
|
|
7648
8078
|
|
|
8079
|
+
**A fixture `secrets:` mapping is fail-closed; a job's bound `environment:` is not.** The reject above applies only to the fixture `secrets:` mapping — an explicit request for that environment's secrets. A job's own bound `environment:` (`job('deploy', { environment: 'production', … })`) is treated differently on a test run: if it resolves to a non-test or unconfigured environment 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 environment(s), and the dashboard run view shows the same notice. See [Skip-on-test](https://docs.kici.dev/user/environments/#multiple-environments-per-job) in the environments guide.
|
|
8080
|
+
|
|
7649
8081
|
### Async fixtures
|
|
7650
8082
|
|
|
7651
8083
|
For dynamic fixture configuration, export an async function:
|
|
@@ -8593,7 +9025,7 @@ env: async (event) => {
|
|
|
8593
9025
|
|
|
8594
9026
|
Source: https://docs.kici.dev/user/env-vars/
|
|
8595
9027
|
|
|
8596
|
-
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 a
|
|
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.
|
|
8597
9029
|
|
|
8598
9030
|
## Authentication
|
|
8599
9031
|
|
|
@@ -8628,9 +9060,9 @@ Authenticate with a pre-existing API key (no browser needed):
|
|
|
8628
9060
|
kici login --token <<< "$KICI_API_KEY"
|
|
8629
9061
|
```
|
|
8630
9062
|
|
|
8631
|
-
###
|
|
9063
|
+
### Targeting another environment or custom OIDC provider
|
|
8632
9064
|
|
|
8633
|
-
`kici login` targets the hosted KiCI Platform by default. To point the CLI at a
|
|
9065
|
+
`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:
|
|
8634
9066
|
|
|
8635
9067
|
```bash
|
|
8636
9068
|
export KICI_OIDC_ISSUER=https://your-idp.example.com
|
|
@@ -8754,6 +9186,36 @@ job('deploy-review', {
|
|
|
8754
9186
|
|
|
8755
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 environments that match a glob pattern (e.g., `review/*`) inherit the pattern's configuration, variables, and protection rules.
|
|
8756
9188
|
|
|
9189
|
+
### Multiple environments per job
|
|
9190
|
+
|
|
9191
|
+
A job can bind more than one environment with `environments`, an ordered array. This lets a single job draw secrets and variables from several environments at once — for example a shared `staging` environment plus a `my-testing` environment that carries test-only variables:
|
|
9192
|
+
|
|
9193
|
+
```typescript
|
|
9194
|
+
job('deploy', {
|
|
9195
|
+
runsOn: 'default',
|
|
9196
|
+
environments: ['staging', 'my-testing'],
|
|
9197
|
+
steps: [
|
|
9198
|
+
step('deploy', async (ctx) => {
|
|
9199
|
+
// ctx.secrets and ctx.env carry the merged set from both environments
|
|
9200
|
+
const dbUrl = await ctx.secrets.get('DB_URL');
|
|
9201
|
+
}),
|
|
9202
|
+
],
|
|
9203
|
+
});
|
|
9204
|
+
```
|
|
9205
|
+
|
|
9206
|
+
- `environment` (singular) and `environments` (array) are mutually exclusive — setting both is a compile error. `environment: 'staging'` is exactly equivalent to `environments: ['staging']`.
|
|
9207
|
+
- Each array entry is a static name or a function of the event, resolved per element exactly like a single dynamic environment.
|
|
9208
|
+
|
|
9209
|
+
**Merge order — last wins.** All bound environments 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 environment, the later entry in the array wins. With `environments: ['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 environment.
|
|
9210
|
+
|
|
9211
|
+
**Protection rules combine all-must-pass.** A job must satisfy **every** bound environment's gates — adding an environment can never loosen access. Branch restrictions, trigger-type filters, and repo patterns must pass for all environments; the minimum trust tier is the most restrictive across them; required reviewers are the union of all environments' reviewers; the wait timer is the longest; and the hold expiry is the shortest. If a run is gated out, the rejection names which environment 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
|
+
|
|
9213
|
+
**Skip-on-test (allow-and-warn).** On a test or local run (`kici run remote`, `kici run local`), a bound environment never rejects the run. Any bound environment 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 environment(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 `environments: ['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 environment 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
|
+
|
|
9215
|
+
**Unconfigured environments contribute nothing at dispatch.** At dispatch time a bound environment name with no matching configured environment (and no matching glob environment) simply adds no variables, secrets, or protection rules — the job still runs, exactly as a single dynamic environment resolving to an as-yet-unconfigured name does today.
|
|
9216
|
+
|
|
9217
|
+
**Registration rejects a provably-unsatisfiable binding.** When a workflow is registered, KiCI statically checks every multi-environment binding: a bound environment that does not exist, a disabled one, or two environments 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 environments, and the rule — for example `unsatisfiable environment binding: job 'deploy' binds environments [staging, my-testing] with mutually exclusive branch restrictions (no value satisfies all bound environments)`. Bindings whose restrictions use globs are undecidable at registration and fall through to the dispatch-time gate check instead.
|
|
9218
|
+
|
|
8757
9219
|
### Job-level environment variables
|
|
8758
9220
|
|
|
8759
9221
|
The `env` property on a job provides static or dynamic environment variables:
|
|
@@ -8793,25 +9255,30 @@ job('deploy', {
|
|
|
8793
9255
|
});
|
|
8794
9256
|
```
|
|
8795
9257
|
|
|
8796
|
-
If no `concurrencyGroup` is specified, the environment name is used as the default concurrency group.
|
|
9258
|
+
If no `concurrencyGroup` is specified, the environment name is used as the default concurrency group. For a job bound to multiple environments, the default is the **first** bound environment's name.
|
|
8797
9259
|
|
|
8798
9260
|
### Step context
|
|
8799
9261
|
|
|
8800
9262
|
Inside a step, the `ctx` object provides:
|
|
8801
9263
|
|
|
8802
|
-
| Property | Type | Description
|
|
8803
|
-
| ----------------- | ------------------------------------- |
|
|
8804
|
-
| `ctx.environment` | `string \| undefined` | Resolved environment name (undefined for jobs without environment)
|
|
8805
|
-
| `ctx.env` | `Record<string, string \| undefined>` | Environment variables (merged from system, org, source, and job-level `env`)
|
|
8806
|
-
| `ctx.secrets` | `StepSecretsTyped` | Async accessor for bound secrets (get, expose, has, getMeta)
|
|
8807
|
-
|
|
8808
|
-
| Method
|
|
8809
|
-
|
|
|
8810
|
-
| `await ctx.secrets.get(key)`
|
|
8811
|
-
| `await ctx.secrets.expose(key)`
|
|
8812
|
-
| `ctx.secrets.has(key)`
|
|
8813
|
-
| `ctx.secrets.getMeta(key)`
|
|
8814
|
-
| `ctx.
|
|
9264
|
+
| Property | Type | Description |
|
|
9265
|
+
| ----------------- | ------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
9266
|
+
| `ctx.environment` | `string \| undefined` | Resolved environment name (undefined for jobs without environment) |
|
|
9267
|
+
| `ctx.env` | `Record<string, string \| undefined>` | Environment variables (merged from system, org, source, and job-level `env`) |
|
|
9268
|
+
| `ctx.secrets` | `StepSecretsTyped` | Async accessor for bound secrets (get, expose, has, getMeta, list, mountFile, exposeFile) |
|
|
9269
|
+
|
|
9270
|
+
| Method | Returns | Description |
|
|
9271
|
+
| -------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
9272
|
+
| `await ctx.secrets.get(key)` | `string` | Retrieve a secret value. Throws `SecretNotFoundError` if not found. |
|
|
9273
|
+
| `await ctx.secrets.expose(key)` | `void` | Set the secret as an environment variable for this step — visible via `ctx.env` and to child processes (`process.env`). Throws `SecretNotFoundError` if not found. |
|
|
9274
|
+
| `ctx.secrets.has(key)` | `boolean` | Check if a secret key exists. Synchronous, never throws. |
|
|
9275
|
+
| `ctx.secrets.getMeta(key)` | `SecretMeta \| undefined` | Retrieve metadata (value, backend name, scope path) for a resolved secret. Returns `undefined` if not found. |
|
|
9276
|
+
| `ctx.secrets.list()` | `string[]` | Every secret key available to the step, sorted alphabetically. Synchronous, never throws. |
|
|
9277
|
+
| `await ctx.secrets.mountFile(opts)` | `{ path }` | Materialise one or more secrets to a per-step tmpfile (auto-removed at step end). See [Secrets → Mounting secrets as files](https://docs.kici.dev/user/secrets/#mounting-secrets-as-files). |
|
|
9278
|
+
| `await ctx.secrets.exposeFile(envVar, opts)` | `{ path }` | `mountFile` plus `process.env[envVar] = path`; the env var is unset at step end. |
|
|
9279
|
+
| `ctx.setSecretOutput(key, val)` | `void` | Publish an encrypted secret output from this job, consumable by downstream jobs via `needs`. Never logged or stored in plaintext. |
|
|
9280
|
+
|
|
9281
|
+
The full secrets API — including `SecretFileOptions`, log masking, and the canonical `sops` example — is documented in [Secrets](https://docs.kici.dev/user/secrets/).
|
|
8815
9282
|
|
|
8816
9283
|
## Environment variable merge precedence
|
|
8817
9284
|
|
|
@@ -8934,6 +9401,12 @@ Each environment has four tabs:
|
|
|
8934
9401
|
|
|
8935
9402
|
4. **History** -- view filtered runs targeting this environment.
|
|
8936
9403
|
|
|
9404
|
+
### Bound environments on runs
|
|
9405
|
+
|
|
9406
|
+
A job's bound deployment environments 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-environment job the chips read left-to-right in merge order — later environments override earlier ones on key collisions. A `(dynamic)` chip marks an environment whose name is computed at runtime; it resolves to the real name once the run starts. A job that binds a single environment shows one chip; a job that binds none shows no chip.
|
|
9407
|
+
|
|
9408
|
+
If a multi-environment binding is gated out, the run's failure banner names which environment and which rule rejected it (the same all-must-pass detail surfaced by `kici runs show <run-id>`).
|
|
9409
|
+
|
|
8937
9410
|
### Secrets management
|
|
8938
9411
|
|
|
8939
9412
|
Secrets are individual encrypted values organized by scope paths (e.g., `aws/prod`, `databases/postgres`). Scopes are bound to environments via bindings:
|
|
@@ -9957,11 +10430,34 @@ statement's build context must match the token's identity claims (a mismatch is
|
|
|
9957
10430
|
a hard failure).
|
|
9958
10431
|
|
|
9959
10432
|
```bash
|
|
9960
|
-
kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-file>
|
|
10433
|
+
kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-file>]
|
|
9961
10434
|
```
|
|
9962
10435
|
|
|
9963
|
-
|
|
9964
|
-
|
|
10436
|
+
### Which trust root do I use?
|
|
10437
|
+
|
|
10438
|
+
The trust root is the **KiCI platform's provenance issuer** — the same hosted
|
|
10439
|
+
KiCI platform you `kici login` against. KiCI attestations are issued by, and
|
|
10440
|
+
verified against, that one issuer; there are no competing "roots" to choose
|
|
10441
|
+
between. So the answer to "shouldn't I just use KiCI as the trust root?" is yes
|
|
10442
|
+
— and that's the **default**: omit `--trust-root` and the verifier checks the
|
|
10443
|
+
bundle against the hosted KiCI platform automatically. You only pass
|
|
10444
|
+
`--trust-root` to verify against a different environment or, more commonly, an
|
|
10445
|
+
offline `{ issuer, jwks }` file for air-gapped checks.
|
|
10446
|
+
|
|
10447
|
+
### Why you supply it out-of-band
|
|
10448
|
+
|
|
10449
|
+
Given there's a single issuer, why pass it at all instead of letting the
|
|
10450
|
+
verifier read it from the token? Because the issuer named **inside** a token
|
|
10451
|
+
cannot be trusted: a forged bundle could carry a token that names
|
|
10452
|
+
`iss: https://attacker.example` _and_ bundle a key set that "verifies" it,
|
|
10453
|
+
making the whole signature chain circular and self-attesting. The verifier
|
|
10454
|
+
therefore pins to an issuer you supply out-of-band and checks the token against
|
|
10455
|
+
_that_ — the bundle is verified against a key set you trust, not one it shipped
|
|
10456
|
+
with. Naming the trust root is a security requirement, not a multiple-choice
|
|
10457
|
+
question.
|
|
10458
|
+
|
|
10459
|
+
To override the default, supply the trusted issuer via `--trust-root`, in one of
|
|
10460
|
+
two forms:
|
|
9965
10461
|
|
|
9966
10462
|
- **Online — an HTTPS issuer URL.** The verifier fetches
|
|
9967
10463
|
`<url>/.well-known/openid-configuration`, reads its `issuer` and `jwks_uri`,
|
|
@@ -9989,7 +10485,10 @@ when it does not (or on an error such as a missing flag or unreachable trust
|
|
|
9989
10485
|
root).
|
|
9990
10486
|
|
|
9991
10487
|
```bash
|
|
9992
|
-
#
|
|
10488
|
+
# Default: verify against the hosted KiCI platform (no --trust-root needed):
|
|
10489
|
+
kici verify-attestation ./dist/app.tgz --bundle ./app.tgz.kici.json
|
|
10490
|
+
|
|
10491
|
+
# Override the trust root to verify against a specific issuer:
|
|
9993
10492
|
kici verify-attestation ./dist/app.tgz \
|
|
9994
10493
|
--bundle ./app.tgz.kici.json \
|
|
9995
10494
|
--trust-root https://platform.example/issuer
|
|
@@ -10028,6 +10527,44 @@ attestations shows an empty state.
|
|
|
10028
10527
|
|
|
10029
10528
|
<!-- /help:run-attestations -->
|
|
10030
10529
|
|
|
10530
|
+
## Browsing attestations across runs
|
|
10531
|
+
|
|
10532
|
+
The **Attestations** page (in the org sidebar) lists every build-provenance
|
|
10533
|
+
attestation your organization has produced — not just one run's. It is the
|
|
10534
|
+
supply-chain audit surface: look up "who built `sha256:…`?" by digest, or browse
|
|
10535
|
+
and filter every attestation across all runs.
|
|
10536
|
+
|
|
10537
|
+
<!-- help:attestations-list#browsing-attestations-across-runs -->
|
|
10538
|
+
|
|
10539
|
+
The **Attestations** page lists every build-provenance attestation your organization has produced.
|
|
10540
|
+
|
|
10541
|
+
- **Search** by artifact digest (exact `sha256:…`) or name to trace a specific artifact.
|
|
10542
|
+
- **Filter** by verification status, repository, workflow, job, or date.
|
|
10543
|
+
- Each row's **status badge** is the verdict KiCI recorded when the attestation was produced (`verified`, `failed`, `unverifiable`, or `pending`).
|
|
10544
|
+
|
|
10545
|
+
Open a row for the parsed provenance statement and a live re-verification.
|
|
10546
|
+
|
|
10547
|
+
<!-- /help:attestations-list -->
|
|
10548
|
+
|
|
10549
|
+
The status badge here is the **server-side verdict**, computed once when the
|
|
10550
|
+
attestation was recorded (verify-at-ingest) — so the list stays fast at any
|
|
10551
|
+
size. `verified` means the signature, build identity, and build context all
|
|
10552
|
+
checked out against the provenance issuer; `failed` means verification ran and
|
|
10553
|
+
the bundle did not pass; `unverifiable` means no verdict could be computed (no
|
|
10554
|
+
provenance issuer configured, or its keys could not be read — not a forgery
|
|
10555
|
+
signal); `pending` means the verdict has not been computed yet.
|
|
10556
|
+
|
|
10557
|
+
Opening a row leads to the **attestation detail page**:
|
|
10558
|
+
|
|
10559
|
+
<!-- help:attestation-detail#browsing-attestations-across-runs -->
|
|
10560
|
+
|
|
10561
|
+
This page shows the parsed provenance for one attestation.
|
|
10562
|
+
|
|
10563
|
+
- **Builder identity, source, and build type** come from the signed SLSA statement.
|
|
10564
|
+
- The **stored badge** is the verdict recorded at build time; **Re-verify** runs the check live in your browser against the current signing keys.
|
|
10565
|
+
- **Download** exports the signed bundle for offline verification with `kici verify-attestation`.
|
|
10566
|
+
<!-- /help:attestation-detail -->
|
|
10567
|
+
|
|
10031
10568
|
## See also
|
|
10032
10569
|
|
|
10033
10570
|
- [SDK runtime reference](https://docs.kici.dev/user/sdk/runtime/) — the `ctx.attestProvenance` and
|
|
@@ -10049,6 +10586,8 @@ Secrets are managed per-environment in the orchestrator (see [operator docs](htt
|
|
|
10049
10586
|
|
|
10050
10587
|
This design prevents accidental secret leakage through child processes, log output, or error messages. Only secrets you explicitly request are loaded into memory.
|
|
10051
10588
|
|
|
10589
|
+
A job can bind several environments with `environments: ['staging', 'my-testing']`; the secret keys from all bound environments are merged in array order, with a later environment's value winning on a key collision. See [Multiple environments per job](https://docs.kici.dev/user/environments/#multiple-environments-per-job).
|
|
10590
|
+
|
|
10052
10591
|
## Where secret values come from
|
|
10053
10592
|
|
|
10054
10593
|
Secret values are written either through the dashboard or through `kici-admin` running against the orchestrator. The orchestrator operator decides — per organization — which surface accepts secret writes. From the workflow author's perspective, the resolution path at run time is identical either way; the difference is where you (or your ops team) **enter** the value.
|
|
@@ -11520,7 +12059,7 @@ Source: https://docs.kici.dev/architecture/data-flows/
|
|
|
11520
12059
|
|
|
11521
12060
|
This document describes the key data flows through the KiCI architecture: webhook delivery, job execution, developer-initiated remote runs, dependency caching, re-run and cancel, trace ID propagation, internal event routing, and generic webhook ingestion.
|
|
11522
12061
|
|
|
11523
|
-
> **Lock file schema version:** The lock file uses schema version
|
|
12062
|
+
> **Lock file schema version:** The lock file uses schema version 29. The orchestrator rejects any fetched lock whose `schemaVersion` does not exactly match the engine version it was built against, so a stale lock must be recompiled with `kici compile` and pushed again after any SDK upgrade that bumps the schema.
|
|
11524
12063
|
|
|
11525
12064
|
## Webhook delivery flow
|
|
11526
12065
|
|
|
@@ -11726,7 +12265,7 @@ Dep cache misses alone do **not** trigger a build job. Deps are platform-specifi
|
|
|
11726
12265
|
|
|
11727
12266
|
### Cross-source / no-contentHash workflows
|
|
11728
12267
|
|
|
11729
|
-
- **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is
|
|
12268
|
+
- **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is 29.
|
|
11730
12269
|
- **Cross-source / global-workflow dispatch** (a workflow registered against source A fired by a webhook on source B) bypasses both caches. The registration's lock file entry still carries `contentHash`, but the cross-source path always clone-and-installs — the eval temp dir doesn't ship `@kici-dev/sdk`. The execution agent still verifies `contentHash` against the cloned source for drift detection.
|
|
11731
12270
|
|
|
11732
12271
|
### Build deduplication
|
|
@@ -12294,7 +12833,7 @@ The compiler processes the workflow definition:
|
|
|
12294
12833
|
|
|
12295
12834
|
### Execution time (local test runner)
|
|
12296
12835
|
|
|
12297
|
-
When `kici
|
|
12836
|
+
When `kici run local` runs a workflow:
|
|
12298
12837
|
|
|
12299
12838
|
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)
|
|
12300
12839
|
2. **Map injection:** Fresh `OutputsMap` and `StepRefMap` are created and injected via `setStepOutputsMap()` / `setStepRefMap()` before each job
|
|
@@ -12404,7 +12943,7 @@ flowchart LR
|
|
|
12404
12943
|
|
|
12405
12944
|
**Why three tiers?** Trust boundaries. The Platform relay never sees customer code -- it only verifies webhook signatures and forwards payloads. The orchestrator matches triggers against the lock file without cloning repositories. Only the agent, running on customer infrastructure, clones code and executes steps.
|
|
12406
12945
|
|
|
12407
|
-
This model also
|
|
12946
|
+
This model also supports an independent deployment without the hosted Platform: the orchestrator and agent run on customer infrastructure, with the orchestrator receiving webhooks directly from GitHub instead of through the Platform relay.
|
|
12408
12947
|
|
|
12409
12948
|
## Component responsibilities
|
|
12410
12949
|
|