@kici-dev/compiler 0.1.27 → 0.3.0

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.
Files changed (153) hide show
  1. package/dist/auth/headless-detect.d.ts +14 -5
  2. package/dist/auth/headless-detect.js +50 -9
  3. package/dist/cli.js +120 -11
  4. package/dist/commands/compile.js +28 -4
  5. package/dist/commands/diagnostics.js +14 -2
  6. package/dist/commands/doctor.d.ts +64 -0
  7. package/dist/commands/doctor.js +413 -0
  8. package/dist/commands/endpoints.js +6 -0
  9. package/dist/commands/fixture.js +13 -0
  10. package/dist/commands/hook.js +3 -2
  11. package/dist/commands/index.d.ts +8 -0
  12. package/dist/commands/index.js +5 -1
  13. package/dist/commands/init-host-os.d.ts +34 -0
  14. package/dist/commands/init-host-os.js +44 -0
  15. package/dist/commands/init.d.ts +4 -0
  16. package/dist/commands/init.js +159 -36
  17. package/dist/commands/local.d.ts +28 -2
  18. package/dist/commands/local.js +74 -5
  19. package/dist/commands/login.js +1 -1
  20. package/dist/commands/notifications.d.ts +61 -0
  21. package/dist/commands/notifications.js +274 -0
  22. package/dist/commands/preview.js +8 -1
  23. package/dist/commands/run-routed.js +10 -1
  24. package/dist/commands/run.js +41 -12
  25. package/dist/commands/runs/artifacts/download.d.ts +24 -0
  26. package/dist/commands/runs/artifacts/download.js +154 -0
  27. package/dist/commands/runs/artifacts/list.d.ts +5 -0
  28. package/dist/commands/runs/artifacts/list.js +47 -0
  29. package/dist/commands/runs/cancel.js +2 -2
  30. package/dist/commands/runs/list.js +8 -2
  31. package/dist/commands/verify-attestation.d.ts +3 -1
  32. package/dist/commands/verify-attestation.js +18 -7
  33. package/dist/errors/formatter.d.ts +14 -1
  34. package/dist/errors/formatter.js +13 -3
  35. package/dist/errors/index.d.ts +2 -1
  36. package/dist/errors/index.js +3 -2
  37. package/dist/errors/source-location.d.ts +20 -0
  38. package/dist/errors/source-location.js +45 -0
  39. package/dist/execution/executor.js +25 -5
  40. package/dist/fixtures/defaults/index.js +2 -1
  41. package/dist/llm-context/llms-architecture.txt +51 -22
  42. package/dist/llm-context/llms-cli.txt +2461 -1582
  43. package/dist/llm-context/llms-features.txt +178 -106
  44. package/dist/llm-context/llms-full.txt +6127 -4426
  45. package/dist/llm-context/llms-getting-started.txt +306 -42
  46. package/dist/llm-context/llms-patterns.txt +13 -7
  47. package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
  48. package/dist/llm-context/llms-sdk.txt +591 -2152
  49. package/dist/llm-context/llms.txt +30 -16
  50. package/dist/local-plane/orchestrator-process.d.ts +12 -7
  51. package/dist/local-plane/orchestrator-process.js +28 -14
  52. package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
  53. package/dist/local-plane/os-mismatch-hint.js +34 -0
  54. package/dist/local-plane/plane-liveness.d.ts +68 -0
  55. package/dist/local-plane/plane-liveness.js +145 -0
  56. package/dist/local-plane/plane-manager.d.ts +60 -18
  57. package/dist/local-plane/plane-manager.js +210 -70
  58. package/dist/local-plane/plane-trigger.d.ts +13 -4
  59. package/dist/local-plane/plane-trigger.js +27 -14
  60. package/dist/local-plane/platform-attach.js +1 -5
  61. package/dist/local-plane/port-holder.d.ts +78 -0
  62. package/dist/local-plane/port-holder.js +227 -0
  63. package/dist/local-plane/postgres.d.ts +15 -3
  64. package/dist/local-plane/postgres.js +34 -12
  65. package/dist/local-plane/run-follow.d.ts +20 -0
  66. package/dist/local-plane/run-follow.js +51 -4
  67. package/dist/local-plane/scaler-config.d.ts +28 -14
  68. package/dist/local-plane/scaler-config.js +59 -41
  69. package/dist/local-plane/source-provider.js +4 -10
  70. package/dist/lockfile/generator.d.ts +14 -1
  71. package/dist/lockfile/generator.js +99 -33
  72. package/dist/lockfile/index.d.ts +3 -1
  73. package/dist/lockfile/index.js +3 -2
  74. package/dist/lockfile/purity-diagnostics.d.ts +31 -0
  75. package/dist/lockfile/purity-diagnostics.js +52 -0
  76. package/dist/postinstall.js +2 -1
  77. package/dist/remote/artifact-extract.d.ts +8 -0
  78. package/dist/remote/artifact-extract.js +58 -0
  79. package/dist/remote/config.d.ts +21 -3
  80. package/dist/remote/config.js +24 -5
  81. package/dist/remote/dashboard-client.d.ts +39 -2
  82. package/dist/remote/dashboard-client.js +47 -4
  83. package/dist/remote/fs-case.d.ts +21 -0
  84. package/dist/remote/fs-case.js +45 -0
  85. package/dist/remote/history.d.ts +9 -3
  86. package/dist/remote/history.js +79 -10
  87. package/dist/remote/local-repo-identity.d.ts +1 -1
  88. package/dist/remote/local-repo-identity.js +2 -1
  89. package/dist/remote/notifications-client.d.ts +149 -0
  90. package/dist/remote/notifications-client.js +103 -0
  91. package/dist/remote/oauth.d.ts +13 -0
  92. package/dist/remote/oauth.js +31 -5
  93. package/dist/remote/output/summary.js +76 -14
  94. package/dist/remote/render.js +30 -9
  95. package/dist/remote/uploader.js +5 -4
  96. package/dist/templates/agents-md.d.ts +1 -1
  97. package/dist/templates/agents-md.js +6 -6
  98. package/dist/templates/index.d.ts +1 -1
  99. package/dist/templates/index.js +2 -2
  100. package/dist/templates/package-json.d.ts +15 -0
  101. package/dist/templates/package-json.js +26 -5
  102. package/dist/test-runner/dry-run.d.ts +2 -1
  103. package/dist/test-runner/dry-run.js +18 -1
  104. package/dist/test-runner/event-types.d.ts +2 -0
  105. package/dist/test-runner/event-types.js +3 -0
  106. package/dist/test-runner/job-executor.d.ts +1 -0
  107. package/dist/test-runner/job-executor.js +81 -43
  108. package/dist/test-runner/output-formatter.d.ts +5 -2
  109. package/dist/test-runner/output-formatter.js +6 -4
  110. package/dist/test-runner/payload-builder.d.ts +7 -1
  111. package/dist/test-runner/payload-builder.js +11 -2
  112. package/dist/test-runner/rule-evaluator.d.ts +7 -3
  113. package/dist/test-runner/rule-evaluator.js +13 -12
  114. package/dist/test-runner/step-context.d.ts +23 -5
  115. package/dist/test-runner/step-context.js +28 -118
  116. package/dist/types.d.ts +21 -2
  117. package/dist/types.js +4 -2
  118. package/dist/validation/index.d.ts +2 -0
  119. package/dist/validation/index.js +2 -1
  120. package/dist/validation/typecheck.d.ts +28 -0
  121. package/dist/validation/typecheck.js +110 -0
  122. package/dist/validation/validator.d.ts +9 -4
  123. package/dist/validation/validator.js +38 -44
  124. package/package.json +12 -15
  125. package/sbom.spdx.json +1322 -1964
  126. package/dist/assets/api-TJJVHrjC.json +0 -118
  127. package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
  128. package/dist/assets/package-BpQF9kR8.json +0 -74
  129. package/dist/assets/package-Ceo2h27X.json +0 -89
  130. package/dist/assets/source_context-D0atuL28.json +0 -20
  131. package/dist/assets/type-BFqO8SCZ.json +0 -202
  132. package/dist/commands/cancel.d.ts +0 -22
  133. package/dist/commands/detect-package-manager.d.ts +0 -42
  134. package/dist/commands/held-run-resolve.d.ts +0 -50
  135. package/dist/commands/status.d.ts +0 -34
  136. package/dist/commands/test.d.ts +0 -88
  137. package/dist/errors/codes.d.ts +0 -25
  138. package/dist/local-executor/dag-scheduler.d.ts +0 -44
  139. package/dist/local-executor/index.d.ts +0 -23
  140. package/dist/local-executor/job-runner.d.ts +0 -47
  141. package/dist/local-executor/materializer.d.ts +0 -44
  142. package/dist/local-executor/output-streamer.d.ts +0 -31
  143. package/dist/local-executor/payload-generator.d.ts +0 -16
  144. package/dist/local-executor/picker.d.ts +0 -33
  145. package/dist/local-executor/runs-on-display.d.ts +0 -9
  146. package/dist/local-executor/secret-loader.d.ts +0 -18
  147. package/dist/local-executor/to-event-payload.d.ts +0 -16
  148. package/dist/local-executor/types.d.ts +0 -93
  149. package/dist/local-executor/workflow-lock.d.ts +0 -82
  150. package/dist/package-F7UXSDHW.json +0 -74
  151. package/dist/remote/client.d.ts +0 -210
  152. package/dist/remote/observer.d.ts +0 -81
  153. package/dist/test-runner/summary.d.ts +0 -7
@@ -101,13 +101,13 @@ When the run reaches this job, it is held instead of dispatched. The held run ap
101
101
  job('deploy', {
102
102
  runsOn: 'default',
103
103
  approval: true,
104
- steps: [
105
- /* ... */
106
- ],
104
+ steps: [/* ... */],
107
105
  });
108
106
  ```
109
107
 
110
- `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.
108
+ `approval: true` holds the element until **any** org member who can act on approvals signs off — anyone with `contexts:write`, since an `approval` gate always raises a reviewer hold. Use it when you want a manual gate without restricting who may release it.
109
+
110
+ A **security** hold is different: it is raised by the CI trust pipeline (an unknown contributor, a fork PR, a workflow-modifying PR), never by `approval`, and releasing one requires `ci_trust:write`. See [Approval gates (operator guide)](https://docs.kici.dev/operator/approvals/#who-may-approve).
111
111
 
112
112
  ### Approver list (AND)
113
113
 
@@ -135,15 +135,17 @@ approval: {
135
135
  },
136
136
  ```
137
137
 
138
- | Field | Type | Description |
139
- | ----------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
140
- | `when` | `'always' \| 'drift'` | When the gate fires. `'always'` (default) gates before the element; `'drift'` gates a check/apply step only when it finds drift. See [Drift gates](https://docs.kici.dev/user/approvals/#drift-gates-whendrift). |
141
- | `approvers` | `ApproverClause[]` | The AND list of `{ team }` / `{ user }` clauses. An empty list means "any approval-capable member". |
142
- | `reason` | `string` | A human-readable label shown in the dashboard queue and the held-for-approval status check. |
143
- | `timeout` | `number` | Per-gate expiry in **seconds**, overriding the org default. On expiry the element is rejected. |
138
+ | Field | Type | Description |
139
+ | ----------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
140
+ | `when` | `'always' \| 'drift'` | When the gate fires. `'always'` (default) gates before the element; `'drift'` gates a check/apply step only when it finds drift. See [Drift gates](https://docs.kici.dev/user/approvals/#drift-gates-whendrift). |
141
+ | `approvers` | `ApproverClause[]` | The AND list of `{ team }` / `{ user }` clauses. An empty list means "any approval-capable member". |
142
+ | `reason` | `string` | A human-readable label shown in the dashboard queue and the held-for-approval status check. |
143
+ | `timeout` | `number` | Per-gate expiry in **seconds**, overriding the org default. Must be a **positive integer** number of seconds; a non-positive or non-finite value is rejected at compile time. On expiry the element is rejected. |
144
144
 
145
145
  When `timeout` is omitted, the gate uses the org's default approval expiry (set by the operator). On expiry, the held element is rejected and the run fails — see [expiry](https://docs.kici.dev/operator/approvals/#expiry).
146
146
 
147
+ A `timeout` that is zero, negative, or non-finite (for example a computed `minutes * 60` where `minutes` is `0`) fails `kici compile` with a clear author-facing error, so a misconfigured gate can never silently expire the moment it is created. If an orchestrator ever receives such a value from a hand-edited lock file, the run fails fast with an **Approval gate misconfigured** init-failure rather than dispatching ungated.
148
+
147
149
  ## Granularity
148
150
 
149
151
  The same `approval` field is accepted on a workflow, a job, and a step.
@@ -168,9 +170,7 @@ A job-level gate holds just that job; other jobs in the run proceed normally:
168
170
  job('publish', {
169
171
  runsOn: 'default',
170
172
  approval: [{ team: 'leads' }],
171
- steps: [
172
- /* ... */
173
- ],
173
+ steps: [/* ... */],
174
174
  });
175
175
  ```
176
176
 
@@ -241,14 +241,14 @@ kici approve <run-id>
241
241
  # Approve a held job
242
242
  kici approve <run-id> --job deploy-production
243
243
 
244
- # Approve a held step
245
- kici approve <run-id> --job migrate-and-deploy --step apply-migration
244
+ # Approve a held step (--step takes the step's zero-based index within the job)
245
+ kici approve <run-id> --job migrate-and-deploy --step 1
246
246
 
247
247
  # Reject (a reason is required)
248
248
  kici reject <run-id> --job deploy-production --reason "Wrong release branch"
249
249
  ```
250
250
 
251
- You must be eligible for at least one unsatisfied clause — being a member of a named team or being a named user. The orchestrator verifies eligibility against the operator-defined teams, so naming a team in your workflow can never let an ineligible person release the gate. The command reports whether the element was released, how many clauses remain, or that it was rejected. See [`kici approve`](https://docs.kici.dev/user/cli-reference/#kici-approve) for the full command reference.
251
+ You must be eligible for at least one unsatisfied clause — being a member of a named team or being a named user. The orchestrator verifies eligibility against the operator-defined teams, so naming a team in your workflow can never let an ineligible person release the gate. The command reports whether the element was released, how many clauses remain, or that it was rejected. See [`kici approve`](https://docs.kici.dev/user/cli/runs-and-approvals/#kici-approve) for the full command reference.
252
252
 
253
253
  ### Inline approval and `--approve-all` in `kici run remote`
254
254
 
@@ -357,9 +357,7 @@ workflow('deploy', {
357
357
  group: (ctx) => `deploy-${ctx.branch}`,
358
358
  cancelInProgress: true,
359
359
  },
360
- jobs: [
361
- /* ... */
362
- ],
360
+ jobs: [/* ... */],
363
361
  });
364
362
  ```
365
363
 
@@ -383,9 +381,7 @@ workflow('migrate-db', {
383
381
  cancelInProgress: false,
384
382
  max: 1,
385
383
  },
386
- jobs: [
387
- /* ... */
388
- ],
384
+ jobs: [/* ... */],
389
385
  });
390
386
  ```
391
387
 
@@ -403,9 +399,7 @@ workflow('test', {
403
399
  cancelInProgress: false,
404
400
  max: 3,
405
401
  },
406
- jobs: [
407
- /* ... */
408
- ],
402
+ jobs: [/* ... */],
409
403
  });
410
404
  ```
411
405
 
@@ -425,9 +419,7 @@ workflow('deploy', {
425
419
  job('deploy-staging', {
426
420
  runsOn: 'linux',
427
421
  context: 'staging',
428
- steps: [
429
- /* ... */
430
- ],
422
+ steps: [/* ... */],
431
423
  }),
432
424
  ],
433
425
  });
@@ -442,9 +434,7 @@ workflow('migrate', {
442
434
  group: () => 'db-migration',
443
435
  cancelInProgress: false,
444
436
  },
445
- jobs: [
446
- /* ... */
447
- ],
437
+ jobs: [/* ... */],
448
438
  });
449
439
  ```
450
440
 
@@ -460,9 +450,7 @@ workflow('deploy', {
460
450
  },
461
451
  cancelInProgress: true,
462
452
  },
463
- jobs: [
464
- /* ... */
465
- ],
453
+ jobs: [/* ... */],
466
454
  });
467
455
  ```
468
456
 
@@ -486,11 +474,11 @@ In addition to workflow-level concurrency, individual jobs can define their own
486
474
 
487
475
  ## Local execution
488
476
 
489
- `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.
477
+ `kici run <event> --local` is a real routed dispatch: your machine becomes an ephemeral agent behind the local dev plane, whose own orchestrator applies the same concurrency machinery described above. The `group` callback is evaluated agent-side against the simulated event, and `cancelInProgress` carries its usual semantics — `true` supersedes the older run in the group, `false` queues the newer one behind it.
490
478
 
491
- 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.
479
+ Coordination is scoped to that plane. The plane's state (including its database) lives under `~/.kici/local/`, so enforcement is per-machine and per-user: running the same workflow on two different machines does not serialize across them. For cross-host enforcement (queueing across agents, dashboard visibility), use `kici run remote` against a deployed orchestrator.
492
480
 
493
- 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.
481
+ See [`kici run <event> --local`](https://docs.kici.dev/user/cli/runs-and-approvals/#kici-run-event---local) for the rest of the local-run behavior, and [the local dev plane](https://docs.kici.dev/operator/orchestrator/local-dev-plane/) for the plane's state directory and lifecycle.
494
482
 
495
483
  ---
496
484
 
@@ -645,9 +633,7 @@ job('deploy', {
645
633
  concurrencyGroup: 'production-api',
646
634
  // Or dynamic:
647
635
  // concurrencyGroup: (event) => `review-${event.payload.pull_request.number}`,
648
- steps: [
649
- /* ... */
650
- ],
636
+ steps: [/* ... */],
651
637
  });
652
638
  ```
653
639
 
@@ -712,7 +698,7 @@ Require manual approval before a job can proceed:
712
698
  Required reviewers: alice, bob
713
699
  ```
714
700
 
715
- When reviewers are required, the job enters a "held" state. Reviewers can approve or reject via the dashboard, the [`kici approve`](https://docs.kici.dev/user/cli-reference/#kici-approve) command, or the API. Held runs expire after a configurable timeout.
701
+ When reviewers are required, the job enters a "held" state. Reviewers can approve or reject via the dashboard, the [`kici approve`](https://docs.kici.dev/user/cli/runs-and-approvals/#kici-approve) command, or the API. Held runs expire after a configurable timeout.
716
702
 
717
703
  This operator-set rule is the **mandatory** form of an approval gate. Workflow authors can also declare gates in code with `approval` at step, job, or workflow level — see [Approval gates](https://docs.kici.dev/user/approvals/). Both forms use the same held-element mechanism and the same queue.
718
704
 
@@ -753,14 +739,16 @@ See the [CI security architecture docs](https://docs.kici.dev/architecture/secur
753
739
 
754
740
  ### Security approval queue
755
741
 
756
- 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.
742
+ When a PR is held for security review — the org trust policy held it (a non-trusted contributor modified `.kici/` files, the PR came from a fork, or the contributor could not be resolved to a known identity), or a `minimumTrust` gate blocked the contributor — it enters the security approval queue. This is separate from the context approval queue: a security hold asks "is it safe to run this contributor's code at all?", while a context approval hold asks "should this job be promoted?". The two never cross — releasing a security hold needs `ci_trust:write` or higher, releasing a context approval hold needs `contexts:write` plus eligibility for one of the gate's clauses. See [Approval holds vs security holds](https://docs.kici.dev/architecture/approvals/#approval-holds-vs-security-holds) for the full comparison.
757
743
 
758
744
  Held runs can be approved:
759
745
 
760
746
  - Via the **dashboard** in Settings > CI trust > Approval queue
761
747
  - Via a PR comment: `/kici approve` (commenter must have `ci_trust:write+`)
762
748
 
763
- Security holds expire after a configurable timeout (default 1 hour).
749
+ A hold raised by the org trust policy covers the whole PR and uses the org's approval expiry (default 72 hours). A `minimumTrust` hold is raised by a context rather than by the org policy, so it uses that context's own hold expiry (default one hour).
750
+
751
+ While the org trust policy is holding a pull request, your organization's global workflows do not run for it. Approving the hold releases that pull request's own workflows; it does not retroactively run the organization's global workflows for the event.
764
752
 
765
753
  ### Concurrency limits
766
754
 
@@ -771,6 +759,8 @@ Concurrency limit: 1
771
759
  Strategy: queue (or cancel-pending)
772
760
  ```
773
761
 
762
+ The concurrency limit is a positive integer; leave it unset for unlimited concurrency.
763
+
774
764
  - **queue** -- new jobs wait in a FIFO queue (with configurable timeout, default 1 hour)
775
765
  - **cancel-pending** -- pending (queued) jobs are cancelled when the limit is reached
776
766
 
@@ -793,7 +783,7 @@ Each context has four tabs:
793
783
 
794
784
  2. **Secrets** -- view bound secret scopes and their resolved secret count. Add bindings by specifying scope glob patterns (e.g., `aws/prod/**`).
795
785
 
796
- 3. **Protection** -- configure branch restrictions, required reviewers, wait timers, and concurrency limits with enable toggles for each section.
786
+ 3. **Protection** -- configure branch restrictions, required reviewers, wait timers, and concurrency limits with enable toggles for each section. Turning a section's toggle off and saving clears that rule on the context, so the gate stops applying to new runs. Emptying the hold expiry field clears it too, and held runs fall back to the default one-hour hold window.
797
787
 
798
788
  4. **History** -- view filtered runs targeting this context.
799
789
 
@@ -840,16 +830,17 @@ The KiCI dashboard is the browser interface for monitoring workflow runs, inspec
840
830
 
841
831
  This guide is split across the following pages:
842
832
 
843
- | Page | Covers |
844
- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
845
- | [Getting started](https://docs.kici.dev/user/dashboard/getting-started/) | Onboarding checklist and your organizations list |
846
- | [Navigation and layout](https://docs.kici.dev/user/dashboard/navigation/) | Sidebar, mobile nav, theme, time display, shortcuts, error pages |
847
- | [Runs and logs](https://docs.kici.dev/user/dashboard/runs/) | Run list, run detail, the log viewer |
848
- | [Settings](https://docs.kici.dev/user/dashboard/settings/) | Members, roles, teams, keys, sources, billing, security, support access |
849
- | [Workflows, diagnostics, and orchestrators](https://docs.kici.dev/user/dashboard/workflows-and-diagnostics/) | Registered workflows, infra health, per-cluster views |
850
- | [Contexts, secrets, and approvals](https://docs.kici.dev/user/dashboard/contexts-and-secrets/) | Contexts, secret scopes, approval queue |
851
- | [Activity and DLQ](https://docs.kici.dev/user/dashboard/activity-and-dlq/) | Forensic activity log and dead-letter queue |
852
- | [Account](https://docs.kici.dev/user/dashboard/account/) | Personal account settings |
833
+ | Page | Covers |
834
+ | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
835
+ | [Getting started](https://docs.kici.dev/user/dashboard/getting-started/) | Onboarding checklist and your organizations list |
836
+ | [Navigation and layout](https://docs.kici.dev/user/dashboard/navigation/) | Sidebar, mobile nav, theme, time display, shortcuts, error pages |
837
+ | [Runs and logs](https://docs.kici.dev/user/dashboard/runs/) | Run list, run detail, the log viewer |
838
+ | [Settings](https://docs.kici.dev/user/dashboard/settings/) | Members, roles, teams, keys, sources, billing, security, support access |
839
+ | [Workflows, diagnostics, and orchestrators](https://docs.kici.dev/user/dashboard/workflows-and-diagnostics/) | Registered workflows, infra health, per-cluster views |
840
+ | [Contexts, secrets, and approvals](https://docs.kici.dev/user/dashboard/contexts-and-secrets/) | Contexts, secret scopes, approval queue |
841
+ | [Activity and DLQ](https://docs.kici.dev/user/dashboard/activity-and-dlq/) | Forensic activity log and dead-letter queue |
842
+ | [Notifications](https://docs.kici.dev/user/dashboard/notifications/) | Personal run notifications and org-wide channels, subscriptions, delivery log |
843
+ | [Account](https://docs.kici.dev/user/dashboard/account/) | Personal account settings |
853
844
 
854
845
  ---
855
846
 
@@ -865,9 +856,7 @@ job('deploy', {
865
856
  context: (event) => event.targetBranch,
866
857
  env: (event) => ({ BRANCH: event.targetBranch }),
867
858
  concurrencyGroup: (event) => `deploy-${event.targetBranch}`,
868
- steps: [
869
- /* ... */
870
- ],
859
+ steps: [/* ... */],
871
860
  });
872
861
  ```
873
862
 
@@ -876,9 +865,7 @@ job('deploy', {
876
865
  runsOn: 'default',
877
866
  // One shape everywhere: branch on the normalized event type.
878
867
  context: (event) => (event.type === 'pull_request' ? 'preview' : 'production'),
879
- steps: [
880
- /* ... */
881
- ],
868
+ steps: [/* ... */],
882
869
  });
883
870
  ```
884
871
 
@@ -923,7 +910,7 @@ context: (event) => {
923
910
 
924
911
  ### Impure functions (init-job evaluation)
925
912
 
926
- 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:
913
+ If the compiler determines a function is impure, it prints a `warning [W101]` naming the affected field (`context`, `env`, or `concurrencyGroup`), the reason the function was judged impure, and the ~5-10 second init-job cost — and compilation still succeeds. The function falls back to the two-phase init model. This means:
927
914
 
928
915
  1. The orchestrator dispatches a special `__init__` job to a builder agent
929
916
  2. The builder agent clones the repository and evaluates the function
@@ -932,6 +919,8 @@ If the compiler determines a function is impure, it emits a warning during compi
932
919
 
933
920
  This adds approximately 5-10 seconds of overhead for cloning and evaluation.
934
921
 
922
+ `kici preview` lists the injected `__init__` job under each affected job, so you can spot the init-job cost before the first run.
923
+
935
924
  **Examples of impure functions (will use init job):**
936
925
 
937
926
  ```typescript
@@ -965,8 +954,9 @@ env: async (event) => {
965
954
  ## Tips
966
955
 
967
956
  - **Write pure functions whenever possible** to avoid the init-job delay. Most context and env computations only need the event payload data.
968
- - **Check compiler warnings** -- the compiler tells you when a function is classified as impure and explains why.
957
+ - **Check compiler warnings** -- the compiler prints a `warning [W101]` when a function is classified as impure, naming the reason and the ~5-10s init-job cost. Run `kici preview` to see the injected `__init__` job listed under each affected job before your first run.
969
958
  - **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.
959
+ - **See [how your workflow code executes](https://docs.kici.dev/user/execution-model/)** for the full picture of where pure vs. impure functions run relative to rules, hooks, and step bodies.
970
960
  - **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`, …).
971
961
 
972
962
  ---
@@ -988,10 +978,10 @@ The KiCI CLI reads the following environment variables to customize its behavior
988
978
 
989
979
  ## Browser behavior
990
980
 
991
- | Variable | Description | Default |
992
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
993
- | `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 |
994
- | `KICI_CALLBACK_PORT` | Fixed port for the OAuth PKCE callback server. Useful when firewall rules require a known port. | Random available port |
981
+ | Variable | Description | Default |
982
+ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
983
+ | `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 |
984
+ | `KICI_CALLBACK_PORT` | Fixed port for the OAuth PKCE callback server. Useful when firewall rules require a known port. | Random available port |
995
985
 
996
986
  ## Development
997
987
 
@@ -1000,6 +990,35 @@ The KiCI CLI reads the following environment variables to customize its behavior
1000
990
  | `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 |
1001
991
  | `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 |
1002
992
 
993
+ ## Local dev plane
994
+
995
+ Read by the [local dev plane](https://docs.kici.dev/user/cli/authoring-and-local/#kici-local) that `kici run <event> --local` dispatches through.
996
+
997
+ | Variable | Description | Default |
998
+ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
999
+ | `KICI_LOCAL_ORCH_PORT` | Port the plane orchestrator listens on (HTTP + WebSocket). Change it when another process already holds the default. | `4319` |
1000
+ | `KICI_LOCAL_PG_PORT` | Port the plane's PostgreSQL listens on. | `45432` |
1001
+ | `KICI_LOCAL_PG_MODE` | Set to `podman` to force the container PostgreSQL fallback instead of the embedded binary. | Embedded PostgreSQL |
1002
+ | `KICI_LOCAL_ACCEPTANCE_TIMEOUT_MS` | How long a local run waits for an agent to claim its first job before failing fast. Raise it on a slow host; the run still fails quickly when no scaler label set matches `runsOn`. | `120000` (2 minutes) |
1003
+
1004
+ ## CI detection
1005
+
1006
+ The CLI also reads the conventional CI markers your CI provider sets. They are not KiCI variables — KiCI only consumes them.
1007
+
1008
+ | Variable | Description | Default |
1009
+ | ---------------- | -------------------------------------------- | ------- |
1010
+ | `CI` | Generic CI marker. Set by most CI providers. | unset |
1011
+ | `GITHUB_ACTIONS` | Set to `true` by GitHub Actions. | unset |
1012
+ | `GITLAB_CI` | Set to `true` by GitLab CI/CD. | unset |
1013
+
1014
+ ### How `CI` is interpreted
1015
+
1016
+ `kici` treats the environment as CI when `CI`, `GITHUB_ACTIONS`, or `GITLAB_CI` is set to any value other than an explicit opt-out. `0` and `false` are the opt-outs, compared case-insensitively, so `CI=0`, `CI=false`, and `CI=False` all mean "not CI". Surrounding whitespace is ignored, and a value that is empty or only whitespace (`CI=`) is treated as unset.
1017
+
1018
+ A vendor marker outranks the generic opt-out: `CI=false GITHUB_ACTIONS=true` is still CI, because an explicit vendor marker names a real runner rather than a preference.
1019
+
1020
+ This affects which login flow `kici login` chooses (browser vs device) and whether interactive commands such as `kici init` prompt.
1021
+
1003
1022
  ## Usage examples
1004
1023
 
1005
1024
  ### CI/CD environment
@@ -1007,7 +1026,7 @@ The KiCI CLI reads the following environment variables to customize its behavior
1007
1026
  Authenticate with a pre-existing API key (no browser needed):
1008
1027
 
1009
1028
  ```bash
1010
- kici login --token <<< "$KICI_API_KEY"
1029
+ kici login --token "$KICI_API_KEY"
1011
1030
  ```
1012
1031
 
1013
1032
  ### Targeting another environment or custom OIDC provider
@@ -1383,11 +1402,11 @@ export const deployComplete = defineEvent(
1383
1402
  );
1384
1403
  ```
1385
1404
 
1386
- Then emit using the definition's name:
1405
+ Then emit using the definition — the payload is checked against the schema:
1387
1406
 
1388
1407
  ```typescript
1389
1408
  step('emit', async (ctx) => {
1390
- await ctx.emit(deployComplete.name, {
1409
+ await ctx.emit(deployComplete, {
1391
1410
  env: 'prod',
1392
1411
  version: '1.2.3',
1393
1412
  services: ['api', 'web'],
@@ -1442,7 +1461,7 @@ If you've only ever used per-repo workflows so far, start with the mental model
1442
1461
  | Workflow repo | The repo whose `.kici/workflows/*.ts` file **declares** the global workflow. Holds the steps. Also known as the _authoring_ repo. |
1443
1462
  | Source repo | The repo that **emits** the event (push / PR / tag / ...) that causes the global workflow to fire. The agent checks out this repo as the working copy. |
1444
1463
  | Global | A workflow whose trigger carries one or more `repos:` glob patterns. The presence of `repos:` is what classifies a workflow as global. |
1445
- | Authoring axis | Policy that answers "which repos may **author** global workflows?" Controlled by the allow-list in the dashboard's _Workflow authors_ setting. |
1464
+ | Authoring axis | Policy that answers "which repos may **author** global workflows?" Controlled by the allow-list in the dashboard's _Allowed author repos_ setting. |
1446
1465
  | Source axis | Policy that answers "which **source** repos' events are allowed to trigger global workflows?" Controlled by the deny-list in _Blocked source repos_. |
1447
1466
 
1448
1467
  The two axes are independent. A global workflow fires only if it passes **both** — its authoring repo is allowed AND the source repo is not denied.
@@ -1497,7 +1516,7 @@ Global workflows are **opt-in per org**. In a fresh org, `repos:`-bearing workfl
1497
1516
 
1498
1517
  | Setting | What it controls | Typical use |
1499
1518
  | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
1500
- | Workflow authors | Restricts which repos can **author** (register) global workflows. Globs matched against the authoring repo identifier. When OFF, any repo in the org may author globals. | Lock authoring to `myorg/ci-*` so random product repos can't ship org-wide automation. |
1519
+ | Allowed author repos | Restricts which repos can **author** (register) global workflows. Globs matched against the authoring repo identifier. When OFF, any repo in the org may author globals. | Lock authoring to `myorg/ci-*` so random product repos can't ship org-wide automation. |
1501
1520
  | Blocked source repos | Blocks dispatch for events emitted from these **source** repos, regardless of authoring. Globs matched against the event source repo identifier. When OFF, events from any repo may trigger globals. | Protect against fork spam — e.g. `!myorg/*` via `myorg/fork-*`. |
1502
1521
  | Elevated access | Authoring repos listed here get **read access to source-repo secrets** during execution. Globs matched against the authoring repo identifier. | A `myorg/ci-deploy` repo that needs to read a source repo's `NPM_TOKEN` to publish releases. |
1503
1522
 
@@ -1513,7 +1532,7 @@ The page is a two-state editor — changes are local until you click **Save chan
1513
1532
 
1514
1533
  A global workflow fires only if:
1515
1534
 
1516
- 1. **The authoring repo is allowed.** If _Workflow authors_ is ON, the workflow's authoring repo must match at least one allow-list glob. If OFF, any repo may author. Enforced at two points:
1535
+ 1. **The authoring repo is allowed.** If _Allowed author repos_ is ON, the workflow's authoring repo must match at least one allow-list glob. If OFF, any repo may author. Enforced at two points:
1517
1536
  - At registration time (extraction from the lock file — non-matching globals are dropped with a warning).
1518
1537
  - At dispatch time (defense-in-depth — policy changes after registration still take effect).
1519
1538
  2. **The source repo is not denied.** If the event's source repo matches any glob in _Blocked source repos_, the global workflow is skipped. Enforced at dispatch time.
@@ -1615,7 +1634,7 @@ const configureNginx = step('configure-nginx', {
1615
1634
  `summarize` is **required** whenever `check` is declared. `run` and `whenInSync`
1616
1635
  both produce the same output type — one output shape per step, whichever path
1617
1636
  runs. Every other step facet (`cache`, `rules`, `continueOnError`, `timeout`,
1618
- `approval`, `onCancel`, `cleanup`, `outputs`) composes unchanged.
1637
+ `retry`, `approval`, `onCancel`, `cleanup`, `outputs`) composes unchanged.
1619
1638
 
1620
1639
  A plain `step()` without `check` keeps its exact current behavior — the check
1621
1640
  facet is fully optional.
@@ -1736,6 +1755,17 @@ The agent never writes the token bytes to your `.kici/.npmrc`. Each registry tok
1736
1755
 
1737
1756
  After the install completes (success or failure), the agent restores the original `.kici/.npmrc` — your committed file is never permanently modified.
1738
1757
 
1758
+ ### Package managers
1759
+
1760
+ The agent detects the package manager from the cloned repo — npm, pnpm, or yarn (classic and berry are both supported) — and applies the auth overlay the detected manager actually reads:
1761
+
1762
+ | Detected manager | Auth file the agent overlays | Notes |
1763
+ | ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
1764
+ | npm, pnpm, yarn classic | `.kici/.npmrc` | Auth lines carry `${VAR}` references to the job-scoped token env vars. |
1765
+ | yarn berry (v2+) | `.kici/.yarnrc.yml` | Berry reads `.yarnrc.yml` instead of `.npmrc`, so the overlay uses berry's own registry/scope/auth keys with the same `${VAR}` indirection. |
1766
+
1767
+ Either file is restored on cleanup, exactly as described above.
1768
+
1739
1769
  ## Option C — committed `.kici/.npmrc` + `installEnv:`
1740
1770
 
1741
1771
  If you'd rather hand-craft the `.npmrc`, commit it under `.kici/.npmrc` with `${VAR}` placeholders, then list each variable in the workflow's `installEnv:` block using the same qualified syntax as `tokenSecret`.
@@ -1891,8 +1921,8 @@ registries: [
1891
1921
  ## Security model
1892
1922
 
1893
1923
  - **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.
1894
- - **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`.
1895
- - **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.
1924
+ - **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 [minimum trust](https://docs.kici.dev/user/contexts/#minimum-trust) rule.
1925
+ - **Lifecycle scripts disabled.** Whenever a private registry is in scope, the agent runs the install with `--ignore-scripts` (npm, pnpm, and yarn classic alike; yarn berry gets the equivalent `enableScripts: false`). 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 or yarn 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.
1896
1926
  - **Stderr is redacted.** If the install fails, the agent masks every token literal out of the surfaced stderr / stdout chunks before logging.
1897
1927
  - **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.
1898
1928
  - **`.npmrc` restored.** Whatever the agent appended for one install is stripped (or the file unlinked) on cleanup, so the workspace is never permanently modified.
@@ -1956,13 +1986,20 @@ An attestation is a self-contained bundle holding three things:
1956
1986
  commit, ref, workflow, run/job identifiers, timestamps).
1957
1987
  - A **[DSSE](https://github.com/secure-systems-lab/dsse) signature** over that
1958
1988
  statement, made with an ephemeral signing key generated for the run.
1959
- - A short-lived **OIDC identity token** issued by the KiCI platform that binds
1960
- the signature to the build identity. The token's identity claims
1961
- (`repository`, `ref`, `sha`, run/job ids) are derived by the platform from the
1962
- run itself — a step cannot forge them.
1989
+ - A short-lived **OIDC identity token** issued by your **orchestrator** that
1990
+ binds the signature to the build identity. The token's identity claims
1991
+ (`repository`, `ref`, `sha`, run/job ids) are derived by the orchestrator from
1992
+ the run itself — a step cannot forge them.
1993
+
1994
+ The orchestrator owns the provenance root of trust: it holds its own long-lived
1995
+ ES256 signing key, mints and signs the identity token **locally** from its own
1996
+ run records, and publishes its own OIDC discovery + public key set (JWKS). Builds
1997
+ therefore produce verifiable provenance with **no dependency on the hosted KiCI
1998
+ platform** — the availability, sovereignty, and air-gap story all follow from
1999
+ this.
1963
2000
 
1964
2001
  Because the bundle carries the identity token and the public signing key, it is
1965
- **offline-verifiable**: a verifier checks it against the platform's published
2002
+ **offline-verifiable**: a verifier checks it against the orchestrator's published
1966
2003
  signing keys with no per-attestation online lookup.
1967
2004
 
1968
2005
  ## Attesting an artifact in a workflow
@@ -2011,8 +2048,11 @@ The identity token is fetched and masked in logs automatically — you never
2011
2048
  handle it. The call returns `{ storageKey, subjectDigest, bundleMediaType }`
2012
2049
  identifying the stored bundle.
2013
2050
 
2014
- `ctx.attestProvenance` is only available inside a running job step. Calling it
2015
- during local execution rejects with a clear error.
2051
+ `ctx.attestProvenance` is only available inside a running job step; calling it
2052
+ outside one rejects with a clear error. `kici run --local` runs are supported:
2053
+ the offline local dev plane signs with a dev identity under the
2054
+ clearly-non-production issuer `kici-local`, and those bundles verify against a
2055
+ trust root exported with `kici local trust-root`.
2016
2056
 
2017
2057
  ### Requesting a raw identity token
2018
2058
 
@@ -2029,11 +2069,11 @@ step('mint', async (ctx) => {
2029
2069
 
2030
2070
  The token is a short-lived (about 10 minutes) signed JWT scoped to the current
2031
2071
  run and job. Its identity claims (`repository`, `ref`, `sha`, `kici_run_id`,
2032
- `kici_job_id`) are derived by the platform from the run context, so a step cannot
2033
- spoof them. The returned token value is automatically masked in step logs, and
2034
- the step never holds platform credentials — the request is relayed through the
2035
- orchestrator, which mints the token on the step's behalf. Like
2036
- `attestProvenance`, it is only available inside a running job step.
2072
+ `kici_job_id`) are derived by the orchestrator from the run context, so a step
2073
+ cannot spoof them. The returned token value is automatically masked in step logs,
2074
+ and the step never holds signing credentials — the orchestrator mints and signs
2075
+ the token on the step's behalf from its own run records. Like `attestProvenance`,
2076
+ it is only available inside a running job step.
2037
2077
 
2038
2078
  ## Verifying an attestation
2039
2079
 
@@ -2049,14 +2089,27 @@ kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-
2049
2089
 
2050
2090
  ### Which trust root do I use?
2051
2091
 
2052
- The trust root is the **KiCI platform's provenance issuer** — the same hosted
2053
- KiCI platform you `kici login` against. KiCI attestations are issued by, and
2054
- verified against, that one issuer; there are no competing "roots" to choose
2055
- between. So the answer to "shouldn't I just use KiCI as the trust root?" is yes
2056
- and that's the **default**: omit `--trust-root` and the verifier checks the
2057
- bundle against the hosted KiCI platform automatically. You only pass
2058
- `--trust-root` to verify against a different environment or, more commonly, an
2059
- offline `{ issuer, jwks }` file for air-gapped checks.
2092
+ The trust root is **your orchestrator's provenance issuer** — the orchestrator
2093
+ you `kici login` against, which owns the provenance signing key and publishes its
2094
+ own JWKS. That is the **default**: omit `--trust-root` and the verifier checks the
2095
+ bundle against your configured orchestrator automatically. There are three ways to
2096
+ verify, and offline is always the primary one:
2097
+
2098
+ 1. **Offline against a JWKS / trust-root file (air-gap)** — export the
2099
+ `{ issuer, jwks }` file once with `kici-admin signing-key export --public` and
2100
+ verify against it with `--trust-root <file>`. No network needed at verify time.
2101
+ 2. **Directly online against your orchestrator** — the default: the verifier
2102
+ resolves your orchestrator's discovery → JWKS. You can also POST a bundle to
2103
+ the orchestrator's native `POST /v1/verify-attestation` endpoint for a verdict
2104
+ against its live keys (fresh rotations / revocations included).
2105
+ 3. **Against the hosted KiCI platform** — bundles produced before your
2106
+ orchestrator owned signing were signed by the hosted platform; those keep
2107
+ verifying forever. When no orchestrator is configured, the default falls back
2108
+ to the hosted platform's issuer so those historical bundles still verify with
2109
+ no flag.
2110
+
2111
+ You pass `--trust-root` to verify against a different environment or, most
2112
+ commonly, an offline `{ issuer, jwks }` file for air-gapped checks.
2060
2113
 
2061
2114
  ### Why you supply it out-of-band
2062
2115
 
@@ -2099,7 +2152,7 @@ when it does not (or on an error such as a missing flag or unreachable trust
2099
2152
  root).
2100
2153
 
2101
2154
  ```bash
2102
- # Default: verify against the hosted KiCI platform (no --trust-root needed):
2155
+ # Default: verify against your configured orchestrator (no --trust-root needed):
2103
2156
  kici verify-attestation ./dist/app.tgz --bundle ./app.tgz.kici.json
2104
2157
 
2105
2158
  # Override the trust root to verify against a specific issuer:
@@ -2113,7 +2166,7 @@ kici verify-attestation ./dist/app.tgz \
2113
2166
  --trust-root ./kici-trust-root.json
2114
2167
  ```
2115
2168
 
2116
- The full flag reference is in the [CLI reference](https://docs.kici.dev/user/cli-reference/#kici-verify-attestation).
2169
+ The full flag reference is in the [CLI reference](https://docs.kici.dev/user/cli/notifications-and-diagnostics/#kici-verify-attestation).
2117
2170
 
2118
2171
  ## Viewing attestations in the dashboard
2119
2172
 
@@ -2155,6 +2208,7 @@ The **Attestations** page lists every build-provenance attestation your organiza
2155
2208
  - **Search** by artifact digest (exact `sha256:…`) or name to trace a specific artifact.
2156
2209
  - **Filter** by verification status, repository, workflow, job, or date.
2157
2210
  - Each row's **status badge** is the verdict KiCI recorded when the attestation was produced (`verified`, `failed`, `unverifiable`, or `pending`).
2211
+ - **Retry** on a `pending` row asks your orchestrator to mint that run's outstanding attestations now; **Retry pending** does the same for every pending run at once.
2158
2212
 
2159
2213
  Open a row for the parsed provenance statement and a live re-verification.
2160
2214
 
@@ -2168,6 +2222,19 @@ the bundle did not pass; `unverifiable` means no verdict could be computed (no
2168
2222
  provenance issuer configured, or its keys could not be read — not a forgery
2169
2223
  signal); `pending` means the verdict has not been computed yet.
2170
2224
 
2225
+ A `pending` row is one still waiting to be minted — the attestation was signed
2226
+ at build time, but attaching its identity token has not completed yet. Those
2227
+ rows carry a **Retry** button that asks your orchestrator to mint that run's
2228
+ outstanding attestations immediately, and the page header offers **Retry
2229
+ pending** to do the same across every pending run. Only one retry runs at a
2230
+ time — the other retry buttons are unavailable until it finishes.
2231
+
2232
+ Retrying is safe to repeat while the mint is only temporarily unavailable: the
2233
+ row stays pending and the next retry tries again. A mint that is definitively
2234
+ rejected — for example the run's records are no longer there to bind the
2235
+ attestation to — is terminal: the row stops being retried, and re-arming it is
2236
+ an operator action (`kici-admin attestations retry --include-rejected`).
2237
+
2171
2238
  Opening a row leads to the **attestation detail page**:
2172
2239
 
2173
2240
  <!-- help:attestation-detail#browsing-attestations-across-runs -->
@@ -2177,13 +2244,14 @@ This page shows the parsed provenance for one attestation.
2177
2244
  - **Builder identity, source, and build type** come from the signed SLSA statement.
2178
2245
  - The **stored badge** is the verdict recorded at build time; **Re-verify** runs the check live in your browser against the current signing keys.
2179
2246
  - **Download** exports the signed bundle for offline verification with `kici verify-attestation`.
2247
+
2180
2248
  <!-- /help:attestation-detail -->
2181
2249
 
2182
2250
  ## See also
2183
2251
 
2184
2252
  - [SDK runtime reference](https://docs.kici.dev/user/sdk/runtime/) — the `ctx.attestProvenance` and
2185
2253
  `ctx.kici.oidc.token` step APIs in full.
2186
- - [CLI reference](https://docs.kici.dev/user/cli-reference/#kici-verify-attestation) — every
2254
+ - [CLI reference](https://docs.kici.dev/user/cli/notifications-and-diagnostics/#kici-verify-attestation) — every
2187
2255
  `kici verify-attestation` flag and exit code.
2188
2256
 
2189
2257
  ---
@@ -2211,7 +2279,7 @@ Secret values are written either through the dashboard or through `kici-admin` r
2211
2279
  A fresh orchestrator starts in **permissive** mode: both surfaces are available.
2212
2280
 
2213
2281
  - **Dashboard:** Settings → Secrets → pick a scope → enter the secret name and value.
2214
- - **CLI:** `kici-admin secret set --scope <scope> <KEY>` against the orchestrator's HTTP admin API.
2282
+ - **CLI:** `kici-admin secret set <orgId> <scope> <KEY>` against the orchestrator's HTTP admin API.
2215
2283
 
2216
2284
  Use whichever fits the workflow — most small teams stay on the dashboard; ops engineers and CI scripts use the CLI.
2217
2285
 
@@ -2219,7 +2287,7 @@ Use whichever fits the workflow — most small teams stay on the dashboard; ops
2219
2287
 
2220
2288
  The orchestrator operator can flip `secrets.set` (and `variables.set`) to **CLI-only** as part of the [dashboard-write policy](https://docs.kici.dev/operator/security/dashboard-write-policy). When that flip is on:
2221
2289
 
2222
- - The dashboard's "Add secret" / "Edit value" controls render with a lock icon. Clicking them shows a tooltip with the exact `kici-admin secret set` invocation needed.
2290
+ - The dashboard's "Add secret" / "Edit value" controls render with a lock icon. Hovering or keyboard-focusing the lock shows a tooltip with the exact `kici-admin secret set` invocation needed. The control itself is inert, so there is nothing to click.
2223
2291
  - The dashboard's secrets page still lists secret **names**, scopes, and bindings — only the value-entry path moves to the CLI.
2224
2292
  - `kici-admin secret set` becomes the single entry point for new and updated secret values.
2225
2293
 
@@ -2227,26 +2295,30 @@ This configuration is common for SOC2-prep and regulated workloads, where the cu
2227
2295
 
2228
2296
  ### CLI input modes
2229
2297
 
2230
- `kici-admin secret set` accepts five input modes pick the one that fits your workflow:
2298
+ `kici-admin secret set` takes the target as three positional arguments — `<orgId> <scope> <key>` — and accepts five input modes; pick the one that fits your workflow:
2231
2299
 
2232
2300
  ```bash
2233
2301
  # Interactive prompt (default when stdin is a TTY). No echo, no shell history.
2234
- kici-admin secret set --scope production DB_PASSWORD --prompt
2302
+ kici-admin secret set my-org production DB_PASSWORD --prompt
2235
2303
 
2236
2304
  # Pipe from another tool (default when stdin is not a TTY).
2237
- pass show prod/db | kici-admin secret set --scope production DB_PASSWORD --from-stdin
2305
+ pass show prod/db | kici-admin secret set my-org production DB_PASSWORD --from-stdin
2238
2306
 
2239
2307
  # Read from a file (handy after `sops -d` to a tmpfile).
2240
- kici-admin secret set --scope production DB_PASSWORD --from-file ./db.pass
2308
+ kici-admin secret set my-org production DB_PASSWORD --from-file ./db.pass
2241
2309
 
2242
2310
  # Read from a named environment variable (CI-friendly).
2243
2311
  KICI_SECRET_VALUE=$(my-secrets-fetcher prod db) \
2244
- kici-admin secret set --scope production DB_PASSWORD --from-env KICI_SECRET_VALUE
2312
+ kici-admin secret set my-org production DB_PASSWORD --from-env KICI_SECRET_VALUE
2245
2313
 
2246
2314
  # Direct argv — discouraged. Prints a stderr warning ("visible in shell history").
2247
- kici-admin secret set --scope production DB_PASSWORD --value "<plaintext>"
2315
+ kici-admin secret set my-org production DB_PASSWORD --value "<plaintext>"
2248
2316
  ```
2249
2317
 
2318
+ When the scope is a deployment context, a flag-based sugar form is also accepted:
2319
+ `kici-admin secret set --org my-org --context production --key DB_PASSWORD --prompt`.
2320
+ The two forms are mutually exclusive — mixing them is refused.
2321
+
2250
2322
  Two cross-cutting flags help every mode:
2251
2323
 
2252
2324
  - `--confirm-fingerprint <hex>` — pre-compute SHA-256 of the value and pass it. The CLI rejects the call if the value's fingerprint doesn't match. Catches paste corruption.