@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.
- package/dist/auth/headless-detect.d.ts +14 -5
- package/dist/auth/headless-detect.js +50 -9
- package/dist/cli.js +120 -11
- package/dist/commands/compile.js +28 -4
- package/dist/commands/diagnostics.js +14 -2
- package/dist/commands/doctor.d.ts +64 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/endpoints.js +6 -0
- package/dist/commands/fixture.js +13 -0
- package/dist/commands/hook.js +3 -2
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.js +5 -1
- package/dist/commands/init-host-os.d.ts +34 -0
- package/dist/commands/init-host-os.js +44 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +159 -36
- package/dist/commands/local.d.ts +28 -2
- package/dist/commands/local.js +74 -5
- package/dist/commands/login.js +1 -1
- package/dist/commands/notifications.d.ts +61 -0
- package/dist/commands/notifications.js +274 -0
- package/dist/commands/preview.js +8 -1
- package/dist/commands/run-routed.js +10 -1
- package/dist/commands/run.js +41 -12
- package/dist/commands/runs/artifacts/download.d.ts +24 -0
- package/dist/commands/runs/artifacts/download.js +154 -0
- package/dist/commands/runs/artifacts/list.d.ts +5 -0
- package/dist/commands/runs/artifacts/list.js +47 -0
- package/dist/commands/runs/cancel.js +2 -2
- package/dist/commands/runs/list.js +8 -2
- package/dist/commands/verify-attestation.d.ts +3 -1
- package/dist/commands/verify-attestation.js +18 -7
- package/dist/errors/formatter.d.ts +14 -1
- package/dist/errors/formatter.js +13 -3
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +3 -2
- package/dist/errors/source-location.d.ts +20 -0
- package/dist/errors/source-location.js +45 -0
- package/dist/execution/executor.js +25 -5
- package/dist/fixtures/defaults/index.js +2 -1
- package/dist/llm-context/llms-architecture.txt +51 -22
- package/dist/llm-context/llms-cli.txt +2461 -1582
- package/dist/llm-context/llms-features.txt +178 -106
- package/dist/llm-context/llms-full.txt +6127 -4426
- package/dist/llm-context/llms-getting-started.txt +306 -42
- package/dist/llm-context/llms-patterns.txt +13 -7
- package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
- package/dist/llm-context/llms-sdk.txt +591 -2152
- package/dist/llm-context/llms.txt +30 -16
- package/dist/local-plane/orchestrator-process.d.ts +12 -7
- package/dist/local-plane/orchestrator-process.js +28 -14
- package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
- package/dist/local-plane/os-mismatch-hint.js +34 -0
- package/dist/local-plane/plane-liveness.d.ts +68 -0
- package/dist/local-plane/plane-liveness.js +145 -0
- package/dist/local-plane/plane-manager.d.ts +60 -18
- package/dist/local-plane/plane-manager.js +210 -70
- package/dist/local-plane/plane-trigger.d.ts +13 -4
- package/dist/local-plane/plane-trigger.js +27 -14
- package/dist/local-plane/platform-attach.js +1 -5
- package/dist/local-plane/port-holder.d.ts +78 -0
- package/dist/local-plane/port-holder.js +227 -0
- package/dist/local-plane/postgres.d.ts +15 -3
- package/dist/local-plane/postgres.js +34 -12
- package/dist/local-plane/run-follow.d.ts +20 -0
- package/dist/local-plane/run-follow.js +51 -4
- package/dist/local-plane/scaler-config.d.ts +28 -14
- package/dist/local-plane/scaler-config.js +59 -41
- package/dist/local-plane/source-provider.js +4 -10
- package/dist/lockfile/generator.d.ts +14 -1
- package/dist/lockfile/generator.js +99 -33
- package/dist/lockfile/index.d.ts +3 -1
- package/dist/lockfile/index.js +3 -2
- package/dist/lockfile/purity-diagnostics.d.ts +31 -0
- package/dist/lockfile/purity-diagnostics.js +52 -0
- package/dist/postinstall.js +2 -1
- package/dist/remote/artifact-extract.d.ts +8 -0
- package/dist/remote/artifact-extract.js +58 -0
- package/dist/remote/config.d.ts +21 -3
- package/dist/remote/config.js +24 -5
- package/dist/remote/dashboard-client.d.ts +39 -2
- package/dist/remote/dashboard-client.js +47 -4
- package/dist/remote/fs-case.d.ts +21 -0
- package/dist/remote/fs-case.js +45 -0
- package/dist/remote/history.d.ts +9 -3
- package/dist/remote/history.js +79 -10
- package/dist/remote/local-repo-identity.d.ts +1 -1
- package/dist/remote/local-repo-identity.js +2 -1
- package/dist/remote/notifications-client.d.ts +149 -0
- package/dist/remote/notifications-client.js +103 -0
- package/dist/remote/oauth.d.ts +13 -0
- package/dist/remote/oauth.js +31 -5
- package/dist/remote/output/summary.js +76 -14
- package/dist/remote/render.js +30 -9
- package/dist/remote/uploader.js +5 -4
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +6 -6
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +2 -2
- package/dist/templates/package-json.d.ts +15 -0
- package/dist/templates/package-json.js +26 -5
- package/dist/test-runner/dry-run.d.ts +2 -1
- package/dist/test-runner/dry-run.js +18 -1
- package/dist/test-runner/event-types.d.ts +2 -0
- package/dist/test-runner/event-types.js +3 -0
- package/dist/test-runner/job-executor.d.ts +1 -0
- package/dist/test-runner/job-executor.js +81 -43
- package/dist/test-runner/output-formatter.d.ts +5 -2
- package/dist/test-runner/output-formatter.js +6 -4
- package/dist/test-runner/payload-builder.d.ts +7 -1
- package/dist/test-runner/payload-builder.js +11 -2
- package/dist/test-runner/rule-evaluator.d.ts +7 -3
- package/dist/test-runner/rule-evaluator.js +13 -12
- package/dist/test-runner/step-context.d.ts +23 -5
- package/dist/test-runner/step-context.js +28 -118
- package/dist/types.d.ts +21 -2
- package/dist/types.js +4 -2
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -1
- package/dist/validation/typecheck.d.ts +28 -0
- package/dist/validation/typecheck.js +110 -0
- package/dist/validation/validator.d.ts +9 -4
- package/dist/validation/validator.js +38 -44
- package/package.json +12 -15
- package/sbom.spdx.json +1322 -1964
- package/dist/assets/api-TJJVHrjC.json +0 -118
- package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
- package/dist/assets/package-BpQF9kR8.json +0 -74
- package/dist/assets/package-Ceo2h27X.json +0 -89
- package/dist/assets/source_context-D0atuL28.json +0 -20
- package/dist/assets/type-BFqO8SCZ.json +0 -202
- package/dist/commands/cancel.d.ts +0 -22
- package/dist/commands/detect-package-manager.d.ts +0 -42
- package/dist/commands/held-run-resolve.d.ts +0 -50
- package/dist/commands/status.d.ts +0 -34
- package/dist/commands/test.d.ts +0 -88
- package/dist/errors/codes.d.ts +0 -25
- package/dist/local-executor/dag-scheduler.d.ts +0 -44
- package/dist/local-executor/index.d.ts +0 -23
- package/dist/local-executor/job-runner.d.ts +0 -47
- package/dist/local-executor/materializer.d.ts +0 -44
- package/dist/local-executor/output-streamer.d.ts +0 -31
- package/dist/local-executor/payload-generator.d.ts +0 -16
- package/dist/local-executor/picker.d.ts +0 -33
- package/dist/local-executor/runs-on-display.d.ts +0 -9
- package/dist/local-executor/secret-loader.d.ts +0 -18
- package/dist/local-executor/to-event-payload.d.ts +0 -16
- package/dist/local-executor/types.d.ts +0 -93
- package/dist/local-executor/workflow-lock.d.ts +0 -82
- package/dist/package-F7UXSDHW.json +0 -74
- package/dist/remote/client.d.ts +0 -210
- package/dist/remote/observer.d.ts +0 -81
- package/dist/test-runner/summary.d.ts +0 -7
|
@@ -1,86 +1,151 @@
|
|
|
1
1
|
# KiCI Getting started
|
|
2
2
|
|
|
3
|
-
This bundle covers:
|
|
3
|
+
This bundle covers: Adopt KiCI: why it exists, how workflows execute, migrating from GitHub Actions, installing the SDK, and writing/compiling/testing your first workflow.
|
|
4
4
|
|
|
5
5
|
## User guide
|
|
6
6
|
|
|
7
7
|
Source: https://docs.kici.dev/user/
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
KiCI runs your CI/CD on infrastructure you control -- your own orchestrator and agents clone the code and run every job, while the hosted platform relays webhooks and renders the dashboard without ever seeing your source or secrets. You author workflows in real, typed TypeScript and run them locally before you push, so the pipeline you test on your laptop is the pipeline that runs in production. This section is for the people writing those workflows.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Start here
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
1. **[Green run in ~5 minutes](https://docs.kici.dev/user/quickstart/)** -- stand up an orchestrator and agent (Docker / Podman or bare metal) and watch your first workflow go green.
|
|
14
|
+
2. **[Getting started](https://docs.kici.dev/user/getting-started/)** -- install the SDK and compiler, write your first workflow, compile it to a lock file, and test it locally with simulated events.
|
|
15
|
+
3. **[Why KiCI](https://docs.kici.dev/user/why-kici/)** -- the case for running CI on your own infrastructure with typed TypeScript workflows.
|
|
16
|
+
4. **[GitHub App provider](https://docs.kici.dev/user/providers/github/)** -- connect your first source and route real pull-request and push events.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## What's in the user guide
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
- **Authoring** -- the [SDK reference](https://docs.kici.dev/user/sdk-reference/) covers every factory function, trigger, rule, and matrix option; [workflow patterns](https://docs.kici.dev/user/workflow-patterns/) show monorepo builds, conditional jobs, dynamic matrices, and scheduling; [how your workflow code executes](https://docs.kici.dev/user/execution-model/) maps compile, orchestrator, and agent time.
|
|
21
|
+
- **Running and testing** -- the [CLI reference](https://docs.kici.dev/user/cli-reference/) documents every command; the [testing guide](https://docs.kici.dev/user/testing-guide/) covers `kici run remote`, fixtures, and overlay mode; the [dashboard](https://docs.kici.dev/user/dashboard/) is the web UI for watching runs.
|
|
22
|
+
- **Wiring sources** -- the [GitHub App](https://docs.kici.dev/user/providers/github/) and [universal-git](https://docs.kici.dev/user/providers/universal-git/) providers connect your forge; [global workflows](https://docs.kici.dev/user/global-workflows/) run cross-repo.
|
|
23
|
+
- **Configuration and secrets** -- [contexts](https://docs.kici.dev/user/contexts/), [secrets](https://docs.kici.dev/user/secrets/), [dynamic values](https://docs.kici.dev/user/dynamic-values/), [concurrency groups](https://docs.kici.dev/user/concurrency/), [lifecycle hooks](https://docs.kici.dev/user/hooks/), and [environment variables](https://docs.kici.dev/user/env-vars/).
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
The left sidebar is the full index for the user guide -- every page in curated reading order.
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## How your workflow code executes
|
|
30
|
+
|
|
31
|
+
Source: https://docs.kici.dev/user/execution-model/
|
|
32
|
+
|
|
33
|
+
Your workflow is plain TypeScript, but different parts of it run at three distinct moments, on three different machines. Knowing which part runs where is the difference between a workflow that behaves and one that surprises you. This page is the map.
|
|
34
|
+
|
|
35
|
+
## The three phases
|
|
36
|
+
|
|
37
|
+
| Phase | Where it runs | What runs | When |
|
|
38
|
+
| ---------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
39
|
+
| **Compile** | Your dev machine or CI (`kici compile`) | Load your workflow modules, validate the DAG, assign step IDs, analyze dynamic-value purity, emit `kici.lock.json` | Before anything is pushed |
|
|
40
|
+
| **Orchestrator** | Your orchestrator (no repo clone) | Match triggers against the lock, evaluate **pure** inline dynamic values in a sandboxed JavaScript VM, dispatch jobs | On each incoming event |
|
|
41
|
+
| **Agent** | An ephemeral agent (fresh clone per job) | Load the workflow module, evaluate job and step rules, run step bodies and hooks, run impure dynamic-value init jobs and `dynamicJob` generators (both forms) | After dispatch |
|
|
22
42
|
|
|
23
|
-
|
|
43
|
+
The lock file is the seam. Everything left of it is decided once at compile time and frozen into JSON; everything right of it reads that JSON. See [the lock file and workflow drift](https://docs.kici.dev/user/lock-file-and-drift/) and [the three-tier architecture](https://docs.kici.dev/architecture/overview/) for the wider picture.
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
## Compile time
|
|
26
46
|
|
|
27
|
-
|
|
47
|
+
`kici compile` loads your `.kici/workflows/*.ts`, validates dependencies (no cycles, no missing `needs`), assigns compile-time step IDs (unnamed steps become `step-1`, `step-2`, …), runs purity analysis over every dynamic-value function, and writes `kici.lock.json`.
|
|
28
48
|
|
|
29
|
-
|
|
49
|
+
The compiler runs your module's **top-level code** to build the workflow object — but that execution's side effects and in-memory state do not travel. Only the resulting workflow structure (plus the serialized source of pure dynamic-value functions) lands in the lock. Anything your top-level code computes that isn't part of the returned workflow object simply doesn't exist past this point.
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
See [compile the workflow](https://docs.kici.dev/user/getting-started/#compile-the-workflow) for the command in context.
|
|
32
52
|
|
|
33
|
-
|
|
53
|
+
## What serializes into the lock file
|
|
34
54
|
|
|
35
|
-
|
|
55
|
+
The lock is portable JSON. It carries:
|
|
36
56
|
|
|
37
|
-
|
|
57
|
+
- Workflow and trigger metadata.
|
|
58
|
+
- The job and step DAG, with compile-time step IDs.
|
|
59
|
+
- Static values, verbatim.
|
|
60
|
+
- The **source text** of pure dynamic-value functions, as inline expressions.
|
|
38
61
|
|
|
39
|
-
|
|
62
|
+
It does **not** carry:
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
- Your module's runtime state or module-level variables.
|
|
65
|
+
- Closures over those variables.
|
|
66
|
+
- Live instances of modules you imported.
|
|
67
|
+
- Anything computed at top level that isn't part of the returned workflow object.
|
|
42
68
|
|
|
43
|
-
|
|
69
|
+
The consequence is blunt: if a value isn't in the lock, the orchestrator can't see it — it has no copy of your repository.
|
|
44
70
|
|
|
45
|
-
|
|
71
|
+
## Orchestrator time
|
|
46
72
|
|
|
47
|
-
|
|
73
|
+
On each event the orchestrator matches triggers using only the lock — it never clones your repository. Pure dynamic `context`, `env`, and `concurrencyGroup` functions are evaluated here, as inline expressions in a sandboxed JavaScript VM (~0ms overhead), instead of dispatching a separate job to resolve them.
|
|
48
74
|
|
|
49
|
-
|
|
75
|
+
A runtime error in an inline expression fails the job immediately — there is no automatic fallback to the clone-and-evaluate path. The orchestrator does **not** run `dynamicJob` generator bodies itself: for the event-only (function) form it dispatches a dedicated dynamic-evaluation job to an agent at event time; the generator function then runs agent-side (see below).
|
|
50
76
|
|
|
51
|
-
|
|
77
|
+
See [dynamic values](https://docs.kici.dev/user/dynamic-values/) for the exact rules that make a function pure or impure.
|
|
52
78
|
|
|
53
|
-
|
|
79
|
+
## Agent time
|
|
54
80
|
|
|
55
|
-
|
|
81
|
+
After dispatch, each job runs in its own ephemeral agent sandbox: a shallow clone at the dispatch ref (or a source-tarball extract for non-build jobs), then the workflow module is loaded fresh — TypeScript is transformed on import. On the agent, in order:
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
1. **Job-level rules** are evaluated. By this point the agent has already spawned and the source has already been restored, so a job that its rules skip has **still** paid for that spawn and clone; only its steps are avoided.
|
|
84
|
+
2. **Step-level rules**, then each step's `run()` body and its hooks.
|
|
85
|
+
3. **Impure** dynamic values are resolved here too, via an init job that clones and evaluates the function (~5–10s) before the real job runs.
|
|
86
|
+
4. **`dynamicJob` generators run here — both forms.** The event-only (function) form runs in a dedicated evaluation job dispatched at event time; the result-aware (options) form is deferred until its declared `needs` complete, then run with the upstream outputs frozen as `ctx.needs`.
|
|
58
87
|
|
|
59
|
-
|
|
88
|
+
See [job execution](https://docs.kici.dev/architecture/execution/job-execution/) and [hooks and rules](https://docs.kici.dev/user/hooks/) for the details.
|
|
60
89
|
|
|
61
|
-
|
|
90
|
+
## What re-evaluates where
|
|
62
91
|
|
|
63
|
-
|
|
92
|
+
| Construct | Runs on | When |
|
|
93
|
+
| ---------------------------- | ---------------- | ------------------------------- |
|
|
94
|
+
| Static value | Compile → lock | Never re-evaluated |
|
|
95
|
+
| Pure dynamic value | Orchestrator VM | Per event |
|
|
96
|
+
| Impure dynamic value | Agent init job | Per event |
|
|
97
|
+
| Job-level rules | Agent | After clone |
|
|
98
|
+
| Step-level rules | Agent | Per step |
|
|
99
|
+
| `dynamicJob` (function form) | Agent (eval job) | Dispatched at event time |
|
|
100
|
+
| `dynamicJob` (options form) | Agent | Deferred until `needs` complete |
|
|
101
|
+
| Step / job body + hooks | Agent | Per job |
|
|
64
102
|
|
|
65
|
-
|
|
103
|
+
**Determinism note.** `ctx.event` and `ctx.needs` are frozen snapshots — captured once and replayed unchanged on any re-evaluation. A generator that derives its output from them is stable across re-evaluations; one that reads the wall clock (`Date.now()`) or a random source (`Math.random()`) is not.
|
|
66
104
|
|
|
67
|
-
|
|
105
|
+
## OutputProxy: how outputs flow
|
|
68
106
|
|
|
69
|
-
|
|
107
|
+
`step(...).result` and `job(...).result` return an `OutputProxy` — a lazy proxy that, at the type level, mirrors the shape of the step or job's declared outputs so that reading `result.foo` is type-checked, and at runtime defers each property read to a shared outputs map populated as the run progresses.
|
|
70
108
|
|
|
71
|
-
|
|
109
|
+
```typescript
|
|
110
|
+
import { workflow, job, step, z } from '@kici-dev/sdk';
|
|
111
|
+
|
|
112
|
+
const build = job('build', {
|
|
113
|
+
runsOn: 'default',
|
|
114
|
+
steps: [
|
|
115
|
+
step('compile', {
|
|
116
|
+
outputs: { artifact: z.string() },
|
|
117
|
+
run: async () => ({ artifact: 'app.tar.gz' }),
|
|
118
|
+
}),
|
|
119
|
+
step('publish', {
|
|
120
|
+
// `compile.result.artifact` is typed from the `outputs` schema above.
|
|
121
|
+
run: async ({ steps }) => {
|
|
122
|
+
await Promise.resolve(steps.compile.result.artifact);
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
],
|
|
126
|
+
});
|
|
72
127
|
|
|
73
|
-
|
|
128
|
+
export default workflow('build-and-publish', { jobs: [build] });
|
|
129
|
+
```
|
|
74
130
|
|
|
75
|
-
|
|
131
|
+
Outputs are typed across the job boundary too: reading `jobRef.result.…` or `ctx.jobOutputs(jobRef)` on a **job reference** threads the upstream job's inferred output shape through — from any job, in a step body or a `run:` shorthand — so a typo on an output field or a renamed step is a compile error. Typed `ctx.needs.jobRef.result.…` additionally works in a `run:` shorthand job (where the run function's `ctx` derives from the enclosing job's `needs` tuple). Name your steps and use the options form (`step('name', { run })`) to give a job a typed output shape, and pass references rather than string names — string-form `needs` stay loosely typed. See [output chaining](https://docs.kici.dev/user/sdk/core/#output-chaining) for the authoring rules.
|
|
76
132
|
|
|
77
|
-
|
|
133
|
+
## Common footguns
|
|
78
134
|
|
|
79
|
-
|
|
135
|
+
| Symptom | Why | Fix |
|
|
136
|
+
| ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
137
|
+
| A top-level `let seen = 0` (or a cache filled in job A) is empty in job B | Each job loads the workflow module fresh in its own agent process after its own clone — there is no shared memory between jobs | Pass data through step/job **outputs** (`OutputProxy` / `needs`), not module variables |
|
|
138
|
+
| `context: (event) => event.ref + SUFFIX`, where `SUFFIX` is a module constant, silently falls back to the slower init-job path | Purity analysis only allows the function's own params, locals, and a fixed safe-globals set — a free identifier makes it impure | Inline the constant, or accept the init-job path knowingly. See [pure functions](https://docs.kici.dev/user/dynamic-values/#pure-functions-inline-evaluation) |
|
|
139
|
+
| Fan-out job identities shift between re-evaluations | `ctx.event` / `ctx.needs` are frozen and replayed, but `Date.now()` / `Math.random()` are not | Derive job identity only from the frozen event/needs snapshot |
|
|
140
|
+
| A rule-skipped job still spawned an agent and cloned | Job-level rules evaluate agent-side, after dispatch and clone — not on the orchestrator | This is by design: rules can read true runtime context (`$`, `changedFiles`, `env`). See [step-level rules](https://docs.kici.dev/user/hooks/#step-level-rules) |
|
|
80
141
|
|
|
81
|
-
|
|
142
|
+
## See also
|
|
82
143
|
|
|
83
|
-
|
|
144
|
+
- [Dynamic values](https://docs.kici.dev/user/dynamic-values/)
|
|
145
|
+
- [Hooks and rules](https://docs.kici.dev/user/hooks/)
|
|
146
|
+
- [Lock file and drift](https://docs.kici.dev/user/lock-file-and-drift/)
|
|
147
|
+
- [Job execution (architecture)](https://docs.kici.dev/architecture/execution/job-execution/)
|
|
148
|
+
- [SDK: rules, matrix, dynamic jobs](https://docs.kici.dev/user/sdk/rules-matrix-dynamic/)
|
|
84
149
|
|
|
85
150
|
---
|
|
86
151
|
|
|
@@ -123,6 +188,12 @@ The package manager is detected from your repo's `packageManager` field, lockfil
|
|
|
123
188
|
| `--skip-install` | Create files without installing dependencies |
|
|
124
189
|
| `--package-manager <npm\|pnpm\|yarn>` | Force a package manager for the install step (default: auto) |
|
|
125
190
|
| `--mjs` | JavaScript-only mode (no TypeScript, no deps) |
|
|
191
|
+
| `--workspace` | Integrate `.kici/` into the surrounding workspace |
|
|
192
|
+
| `--standalone` | Force a self-contained `.kici/` even inside a workspace |
|
|
193
|
+
|
|
194
|
+
### Workspace integration
|
|
195
|
+
|
|
196
|
+
If you run `kici init` inside a pnpm, npm, or yarn workspace, it offers to **integrate** `.kici/` into that workspace instead of scaffolding a self-contained folder. In integrate mode there is no `.kici/package.json`: `@kici-dev/sdk` is added to your workspace-root `package.json`, and your workflows can `import` your other workspace packages directly — for example shared build or deploy utilities. Pass `--workspace` to opt in non-interactively, or `--standalone` to keep the self-contained layout. In CI the default is standalone. See the [`kici init` reference](https://docs.kici.dev/user/cli/account-and-org/#kici-init) for details.
|
|
126
197
|
|
|
127
198
|
### MJS mode
|
|
128
199
|
|
|
@@ -177,7 +248,7 @@ Create `.kici/workflows/ci.ts`:
|
|
|
177
248
|
import { workflow, job, step, pr } from '@kici-dev/sdk';
|
|
178
249
|
|
|
179
250
|
const lint = job('lint', {
|
|
180
|
-
runsOn: 'linux',
|
|
251
|
+
runsOn: 'kici:os:linux',
|
|
181
252
|
steps: [
|
|
182
253
|
step('install', async ({ $ }) => {
|
|
183
254
|
await $`pnpm install --frozen-lockfile`;
|
|
@@ -189,7 +260,7 @@ const lint = job('lint', {
|
|
|
189
260
|
});
|
|
190
261
|
|
|
191
262
|
const test = job('test', {
|
|
192
|
-
runsOn: 'linux',
|
|
263
|
+
runsOn: 'kici:os:linux',
|
|
193
264
|
needs: [lint],
|
|
194
265
|
steps: [
|
|
195
266
|
step('install', async ({ $ }) => {
|
|
@@ -213,7 +284,7 @@ This workflow:
|
|
|
213
284
|
- Runs a `lint` job first
|
|
214
285
|
- Runs a `test` job after lint succeeds (`needs: [lint]`)
|
|
215
286
|
|
|
216
|
-
`runsOn` selects which agents may run a job. Every agent self-reports `kici:os:<platform>`, `kici:arch:<cpu>`, and `kici:host:<hostname>`, so `runsOn: 'kici:os:linux'` targets any connected Linux agent with zero configuration
|
|
287
|
+
`runsOn` selects which agents may run a job. Every agent self-reports `kici:os:<platform>`, `kici:arch:<cpu>`, and `kici:host:<hostname>`, so `runsOn: 'kici:os:linux'` targets any connected Linux agent with zero configuration. `kici init` scaffolds workflows targeting your own host's OS label (`kici:os:linux`, `kici:os:macos`, or `kici:os:windows`) so your first local run dispatches on this machine. Use a custom label such as `'linux'` or `'gpu'` (defined in your scaler's `labelSet`) to target a specific pool instead. See the [runsOn forms](https://docs.kici.dev/user/sdk/core/#runson-forms) reference for the full label model.
|
|
217
288
|
|
|
218
289
|
**Single-step shortcut.** If a job only has one step, pass `run` directly to `job()` instead of building a `steps: [step(...)]` array:
|
|
219
290
|
|
|
@@ -285,6 +356,8 @@ npx kici run pr:open --local
|
|
|
285
356
|
|
|
286
357
|
This compiles, matches triggers, and runs all matched jobs on this machine — which joins as an ephemeral agent through the warm local dev plane — with DAG-based parallel scheduling.
|
|
287
358
|
|
|
359
|
+
If a run never appears or a webhook seems ignored, run `kici doctor` — it walks your login, organization, orchestrator connection, and compiled lock file, and tells you the exact command to fix the first broken step.
|
|
360
|
+
|
|
288
361
|
## Workflow dependencies
|
|
289
362
|
|
|
290
363
|
KiCI workflows can use any npm package. Dependencies are declared in `.kici/package.json`, which `kici init` generates automatically.
|
|
@@ -441,6 +514,7 @@ The compiler watches `.kici/workflows/*.ts` and recompiles on every save.
|
|
|
441
514
|
## Next steps
|
|
442
515
|
|
|
443
516
|
- **[5-minute quickstart](https://docs.kici.dev/user/quickstart/)** -- ready to run your workflow on real infrastructure? Stand up an orchestrator + agent (Docker / Podman or bare metal)
|
|
517
|
+
- **[How your workflow code executes](https://docs.kici.dev/user/execution-model/)** -- the mental model: which parts of your workflow run at compile time, on the orchestrator, and on the agent
|
|
444
518
|
- **[SDK reference](https://docs.kici.dev/user/sdk-reference/)** -- complete API for workflows, jobs, steps, triggers, rules, and matrix
|
|
445
519
|
- **[CLI reference](https://docs.kici.dev/user/cli-reference/)** -- all CLI commands with options and examples
|
|
446
520
|
- **[Workflow patterns](https://docs.kici.dev/user/workflow-patterns/)** -- common patterns for real-world CI/CD workflows
|
|
@@ -472,6 +546,158 @@ The lock file approach means the orchestrator stays git-agnostic -- it only need
|
|
|
472
546
|
|
|
473
547
|
---
|
|
474
548
|
|
|
549
|
+
## Migrating from GitHub Actions
|
|
550
|
+
|
|
551
|
+
Source: https://docs.kici.dev/user/migrating-from-github-actions/
|
|
552
|
+
|
|
553
|
+
## Before you start
|
|
554
|
+
|
|
555
|
+
KiCI workflows are real, typed TypeScript in `.kici/workflows/*.ts` instead of YAML in `.github/workflows/*.yml`. The compiler validates them ahead of time, and at run time the agent clones your repository and executes them on your own infrastructure. This guide maps the GitHub Actions concepts you already know to their KiCI equivalents, translates one realistic workflow side-by-side, and lists honestly what has no equivalent yet.
|
|
556
|
+
|
|
557
|
+
Follow [getting started](https://docs.kici.dev/user/getting-started/) for the full setup. The mapping below assumes you have `@kici-dev/sdk` installed.
|
|
558
|
+
|
|
559
|
+
## Concept mapping
|
|
560
|
+
|
|
561
|
+
| GitHub Actions | KiCI | Notes |
|
|
562
|
+
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
563
|
+
| Workflow file `.github/workflows/ci.yml` | TypeScript module `.kici/workflows/ci.ts` that default-exports `workflow('ci', {...})` | Workflows are modules built from `workflow()`, `job()`, and `step()` factories. |
|
|
564
|
+
| `on: pull_request:` | `on: pr({ target: 'main' })` | `pr()` is a trigger factory; `on` takes one trigger or an array of triggers. |
|
|
565
|
+
| `on: push: branches: [main]` | `on: push({ branches: ['main'] })` | `push()` matches by branch pattern. |
|
|
566
|
+
| `on: schedule: - cron:` | `on: schedule({ cron: '0 2 * * *', timezone: 'UTC' })` | `cron` is required; `timezone` defaults to `UTC`. In a cluster only the leader evaluates schedules. |
|
|
567
|
+
| `on: workflow_dispatch: inputs:` | `on: dispatch({ inputs: defineDispatchInputs({...}) })`, read typed via `inputs.from(ctx)` | Dispatch inputs are declared with Zod schemas and read back fully typed. |
|
|
568
|
+
| `jobs:` map keyed by name | `jobs: [job('lint', {...}), job('test', {...})]` | Jobs are an array of `job()` results. |
|
|
569
|
+
| `needs: [build]` (string references) | `needs: [buildJob]` (object references) | You reference the `job()` value directly; the compiler validates the dependency graph for cycles and missing references. |
|
|
570
|
+
| `runs-on: <hosted runner>` | `runsOn: 'kici:os:linux'` or a custom scaler label | Every agent self-reports labels such as `kici:os:linux`, `kici:arch:x64`, and `kici:host:<hostname>`. A GitHub-hosted runner label matches no KiCI agent. |
|
|
571
|
+
| `steps: - run: npm test` | `steps: [step('test', async ({ $ }) => { await $\`npm test\` })]` | The `$` in a step body is a zx shell; a single-step job can use the `run:` function shorthand instead of `steps:`. |
|
|
572
|
+
| `steps: - uses: actions/checkout@v4` | (nothing) | The agent clones the repository automatically before steps run, so there is no explicit checkout step. |
|
|
573
|
+
| `steps: - uses: actions/setup-node@v4` | Provision the toolchain in a step or from the agent image | KiCI has no `uses:`-style setup actions; the toolchain comes from the agent environment or an explicit step. |
|
|
574
|
+
| `${{ secrets.NPM_TOKEN }}` | `await ctx.secrets.get('NPM_TOKEN')`, or `ctx.secrets.expose('NPM_TOKEN')` to place it in the environment | Secrets are never auto-injected into `process.env`; access is always explicit. |
|
|
575
|
+
| `environment: production` (+ protection rules) | `context: 'production'` (or `contexts: ['staging', 'prod']`) | A context carries variables, bound secrets, and protection rules (branch restrictions, required reviewers, wait timers, concurrency limits, minimum trust). |
|
|
576
|
+
| `env:` (job or step level) | `env: { KEY: 'val' }` on a job | Job-level `env` accepts a static object or a `(event) => ({...})` function for dynamic values. |
|
|
577
|
+
| `strategy: matrix: node: [18, 20, 22]` | `matrix: ['18', '20', '22']` or `{ node: [...], os: [...] }` | A single-dimension array exposes `matrix.value`; an object expands all combinations and exposes each dimension by name. A dynamic function form is also supported. |
|
|
578
|
+
| `if: github.ref == 'refs/heads/main'` | Native TypeScript conditionals plus `rule()` / `skip()` and dynamic values | Conditions are real TypeScript branching; dynamic values are pure functions of the normalized event. |
|
|
579
|
+
| `concurrency: group: ...` | `concurrencyGroup: 'production-api'` (static) or a dynamic function | Set at the job level; a workflow-level concurrency group also exists. |
|
|
580
|
+
| `jobs.<id>.outputs` | Structured job and step outputs consumed downstream via `needs`; `ctx.setSecretOutput(key, value)` for encrypted outputs | Outputs pass values between jobs; secret outputs are encrypted. |
|
|
581
|
+
| `- uses: actions/cache@v4` | `cache` field on a job or step (declarative) or `ctx.cache.restore` / `ctx.cache.save` (imperative) | A keyed cache, immutable once written, org- and ref-scoped, backed by the orchestrator's object storage. |
|
|
582
|
+
| Reusable workflows / composite actions / marketplace `uses:` | `@kici-dev/action-*` building blocks or any npm package you `import` | Reusable logic is imported as functions, not referenced by `uses:`. |
|
|
583
|
+
|
|
584
|
+
### Secrets are explicit
|
|
585
|
+
|
|
586
|
+
KiCI never copies secrets into `process.env` for you. A step reads a value with `ctx.secrets.get('KEY')` or injects it into the environment with `ctx.secrets.expose('KEY')`, and can mount a secret as a file with `ctx.secrets.mountFile(...)`. Every access is tracked. See [secrets](https://docs.kici.dev/user/secrets/).
|
|
587
|
+
|
|
588
|
+
### Environments become contexts
|
|
589
|
+
|
|
590
|
+
A GitHub environment maps to a KiCI context bound at the job level with `context:` (or `contexts:` for several). A context carries variables, bound secrets, and protection rules — branch restrictions, required reviewers, wait timers, concurrency limits, and a minimum-trust gate. See [contexts](https://docs.kici.dev/user/contexts/).
|
|
591
|
+
|
|
592
|
+
### `if:` becomes real TypeScript
|
|
593
|
+
|
|
594
|
+
There is no expression mini-language. Conditions are ordinary TypeScript, and values that depend on the event are pure functions of the normalized event object. See [dynamic values](https://docs.kici.dev/user/dynamic-values/).
|
|
595
|
+
|
|
596
|
+
### Matrix
|
|
597
|
+
|
|
598
|
+
A single-dimension matrix is an array (`matrix: ['18', '20', '22']`) and exposes the current value as `matrix.value` in the step context. A multi-dimension matrix is an object and exposes each dimension by name. See [conditionals and matrix patterns](https://docs.kici.dev/user/patterns/conditionals-matrix/).
|
|
599
|
+
|
|
600
|
+
### Caching
|
|
601
|
+
|
|
602
|
+
Declare a `cache` on a job or step, or drive it imperatively with `ctx.cache.restore(spec)` and `ctx.cache.save(spec)`. Cache entries are keyed and immutable once written. See [caching](https://docs.kici.dev/user/sdk/caching/).
|
|
603
|
+
|
|
604
|
+
## A real workflow, translated
|
|
605
|
+
|
|
606
|
+
Here is a pull-request CI workflow that runs tests across a Node version matrix and uploads coverage using a secret.
|
|
607
|
+
|
|
608
|
+
The GitHub Actions version:
|
|
609
|
+
|
|
610
|
+
```yaml
|
|
611
|
+
name: ci
|
|
612
|
+
on:
|
|
613
|
+
pull_request:
|
|
614
|
+
branches: [main]
|
|
615
|
+
jobs:
|
|
616
|
+
test:
|
|
617
|
+
# kici-lint-allow-github-runner: GitHub-hosted runner shown for contrast
|
|
618
|
+
runs-on: ubuntu-latest
|
|
619
|
+
strategy:
|
|
620
|
+
matrix:
|
|
621
|
+
node: ['18', '20', '22']
|
|
622
|
+
steps:
|
|
623
|
+
- uses: actions/checkout@v4
|
|
624
|
+
- uses: actions/setup-node@v4
|
|
625
|
+
with:
|
|
626
|
+
node-version: ${{ matrix.node }}
|
|
627
|
+
- run: npm ci
|
|
628
|
+
- run: npm test
|
|
629
|
+
- run: npx codecov
|
|
630
|
+
env:
|
|
631
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
The KiCI translation:
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
import { workflow, job, step, pr } from '@kici-dev/sdk';
|
|
638
|
+
|
|
639
|
+
const test = job('test', {
|
|
640
|
+
runsOn: 'kici:os:linux',
|
|
641
|
+
matrix: ['18', '20', '22'],
|
|
642
|
+
context: 'ci',
|
|
643
|
+
steps: [
|
|
644
|
+
step('install', async ({ $ }) => {
|
|
645
|
+
// The agent already cloned the repo — no checkout step needed.
|
|
646
|
+
await $`npm ci`;
|
|
647
|
+
}),
|
|
648
|
+
step('test', async ({ $, matrix }) => {
|
|
649
|
+
// matrix.value is the Node version for this cell ('18' | '20' | '22').
|
|
650
|
+
// Select it however your agent provisions toolchains, e.g. a version manager.
|
|
651
|
+
await $`nvm use ${matrix!.value}`;
|
|
652
|
+
await $`npm test`;
|
|
653
|
+
}),
|
|
654
|
+
step('coverage', async (ctx) => {
|
|
655
|
+
await ctx.secrets.expose('CODECOV_TOKEN');
|
|
656
|
+
await ctx.$`npx codecov`;
|
|
657
|
+
}),
|
|
658
|
+
],
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
export default workflow('ci', {
|
|
662
|
+
on: pr({ target: 'main' }),
|
|
663
|
+
jobs: [test],
|
|
664
|
+
});
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
What changed and why:
|
|
668
|
+
|
|
669
|
+
- `on: pull_request` → `on: pr({ target: 'main' })`.
|
|
670
|
+
|
|
671
|
+
<!-- kici-lint-allow-github-runner: contrasts GitHub's ubuntu-latest with the KiCI auto-label -->
|
|
672
|
+
|
|
673
|
+
- `runs-on: ubuntu-latest` → `runsOn: 'kici:os:linux'`, an auto-label every Linux agent reports; a GitHub hosted-runner label would match no agent. See [runsOn forms](https://docs.kici.dev/user/sdk/core/#runson-forms).
|
|
674
|
+
- `actions/checkout` → removed; the agent clones the repository before steps run.
|
|
675
|
+
- `actions/setup-node` with `matrix.node` → `matrix: ['18', '20', '22']`, with the current value available as `matrix.value` in the step context. KiCI has no built-in setup-node, so toolchain selection is a step or agent-image concern. See [conditionals and matrix patterns](https://docs.kici.dev/user/patterns/conditionals-matrix/).
|
|
676
|
+
- `${{ secrets.CODECOV_TOKEN }}` → `ctx.secrets.expose('CODECOV_TOKEN')`, explicit and never auto-injected. See [secrets](https://docs.kici.dev/user/secrets/).
|
|
677
|
+
- `environment` → `context: 'ci'`. See [contexts](https://docs.kici.dev/user/contexts/).
|
|
678
|
+
|
|
679
|
+
The `nvm use` line is illustrative — KiCI does not install a Node version for you; use whatever your agent image or step provides.
|
|
680
|
+
|
|
681
|
+
## What has no equivalent yet
|
|
682
|
+
|
|
683
|
+
**File artifacts between jobs.** KiCI has no first-class store for uploading a build directory as a named artifact and downloading it in a later job or from the run UI. It does have structured job and step outputs (and secret outputs) for passing _values_, and a keyed [cache](https://docs.kici.dev/user/sdk/caching/) for reusing files across runs. For build outputs you need to hand between jobs, use the cache or an external object store.
|
|
684
|
+
|
|
685
|
+
**A community action marketplace.** GitHub Actions has thousands of third-party marketplace actions addressable by `uses: owner/repo@ref`. KiCI's reusable blocks are the published `@kici-dev/action-*` packages plus any npm package you import — there is no marketplace of community-contributed actions.
|
|
686
|
+
|
|
687
|
+
**`uses:`-style step references.** KiCI steps are TypeScript functions, so you call reusable logic as imported library functions rather than referencing a composite or container action. This is a model shift rather than a missing feature, but a drop-in `uses:` translation does not exist.
|
|
688
|
+
|
|
689
|
+
**Provider breadth.** KiCI is GitHub-first. Other git hosts are reachable through the universal-git and local-file providers, but the richest event coverage is for GitHub. See [the GitHub provider](https://docs.kici.dev/user/providers/github/).
|
|
690
|
+
|
|
691
|
+
## Next steps
|
|
692
|
+
|
|
693
|
+
- [Getting started](https://docs.kici.dev/user/getting-started/)
|
|
694
|
+
- [SDK reference — runsOn forms](https://docs.kici.dev/user/sdk/core/#runson-forms)
|
|
695
|
+
- [Conditionals and matrix patterns](https://docs.kici.dev/user/patterns/conditionals-matrix/)
|
|
696
|
+
- [Secrets](https://docs.kici.dev/user/secrets/) and [contexts](https://docs.kici.dev/user/contexts/)
|
|
697
|
+
- [CLI reference](https://docs.kici.dev/user/cli-reference/)
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
475
701
|
## 5-minute quickstart
|
|
476
702
|
|
|
477
703
|
Source: https://docs.kici.dev/user/quickstart/
|
|
@@ -509,3 +735,41 @@ If you're not sure, pick Docker / Podman.
|
|
|
509
735
|
Both quickstarts deploy a real orchestrator + agent. If you only want to write a workflow and dry-run it on your laptop with no infrastructure, [Getting started](https://docs.kici.dev/user/getting-started/) covers `kici preview` and `kici run <event> --local` instead.
|
|
510
736
|
|
|
511
737
|
---
|
|
738
|
+
|
|
739
|
+
## Why KiCI
|
|
740
|
+
|
|
741
|
+
Source: https://docs.kici.dev/user/why-kici/
|
|
742
|
+
|
|
743
|
+
Most CI platforms ask you to hand your source, your secrets, and your build machines to someone else. KiCI is built the other way around: your code runs on infrastructure you control, and you describe the pipeline in real TypeScript you can run before you push. This page is the short argument for that trade -- what it buys you, and what it costs.
|
|
744
|
+
|
|
745
|
+
## Your infrastructure runs the code
|
|
746
|
+
|
|
747
|
+
KiCI is a three-tier relay. The hosted platform is a thin webhook router: it verifies the incoming webhook signature and relays the event to your orchestrator over a WebSocket. Your **orchestrator** decides what to run and dispatches jobs to your **agents**, which clone the repository, execute the steps, and stream logs back. The orchestrator and agents run on machines you own.
|
|
748
|
+
|
|
749
|
+
Because of that split, the hosted platform sees only the envelope, never the payload:
|
|
750
|
+
|
|
751
|
+
- **What it receives:** the webhook event, run metadata (workflow and job names, statuses, timings), aggregate operational metrics, and log lines while you are streaming them to the dashboard.
|
|
752
|
+
- **What it never sees:** your source, your secrets, your artifacts, or your signing material. Those stay on your orchestrator and agents. Log content is relayed only in transit for the live dashboard view -- the platform never stores it.
|
|
753
|
+
|
|
754
|
+
The hosted platform is operated by KiCI; you do not run your own. What you run is the orchestrator and the agents, and that is where every byte of your code and every secret lives. For the field-level breakdown of what does and does not leave your infrastructure, see [Data residency](https://docs.kici.dev/operator/data-residency/), and for the honest security posture of self-hosting the agents, see [Is self-hosting the agents a security risk?](https://docs.kici.dev/operator/security/self-hosting-security/).
|
|
755
|
+
|
|
756
|
+
## Workflows are TypeScript
|
|
757
|
+
|
|
758
|
+
A KiCI workflow is a TypeScript program, not a YAML document. Jobs, steps, triggers, and matrices are typed values you compose with the full language -- loops, conditionals, functions, `async`/`await`, and your editor's autocompletion and type checking. Invalid pipelines fail at compile time, in your editor, instead of failing on the tenth push.
|
|
759
|
+
|
|
760
|
+
The same TypeScript runs everywhere. `kici run --local` executes your workflow on your own machine against a simulated event, and that is the same execution model the agents use in production. Your local run is the production pipeline, so you debug a green run before it ever reaches a source event. This also makes workflows something an AI coding agent can author, type-check, and run before it opens a pull request.
|
|
761
|
+
|
|
762
|
+
## The honest trade
|
|
763
|
+
|
|
764
|
+
Running your own infrastructure is not free. You operate the orchestrator: a Docker / Podman or bare-metal service you stand up (in minutes for the quickstart topology), keep patched, back up, and upgrade. In exchange, you own your data, your egress, and your isolation model -- no third party executes your code or holds your secrets. KiCI is pre-1.0, so pin versions for production. See [Deploying the orchestrator](https://docs.kici.dev/operator/orchestrator/getting-started/) for what running it involves.
|
|
765
|
+
|
|
766
|
+
## Compared to specific tools
|
|
767
|
+
|
|
768
|
+
If you are weighing KiCI against a specific incumbent -- GitHub Actions, GitLab CI, CircleCI, Jenkins, Buildkite, and others -- the point-by-point comparisons live on the marketing site, kept current with sourced references. Start with the [GitHub Actions comparison](https://kici.dev/compare/github-actions), or browse [all comparisons](https://kici.dev/compare).
|
|
769
|
+
|
|
770
|
+
## Next steps
|
|
771
|
+
|
|
772
|
+
- **[Green run in ~5 minutes](https://docs.kici.dev/user/quickstart/)** -- stand up an orchestrator and agent and watch a workflow go green.
|
|
773
|
+
- **[Getting started](https://docs.kici.dev/user/getting-started/)** -- write your first workflow and test it locally.
|
|
774
|
+
|
|
775
|
+
---
|
|
@@ -224,7 +224,7 @@ npx kici compile # regenerate .kici/kici.lock.json
|
|
|
224
224
|
npx kici run dispatch --local
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
`kici run dispatch --local` compiles the workflow, matches triggers against a simulated `dispatch` event, and executes the matched jobs on this machine — which joins as an ephemeral agent through the warm local dev plane — with DAG-based scheduling. No webhook, no GitHub, no deployed orchestrator involved. See [`kici run <event> --local`](https://docs.kici.dev/user/cli-
|
|
227
|
+
`kici run dispatch --local` compiles the workflow, matches triggers against a simulated `dispatch` event, and executes the matched jobs on this machine — which joins as an ephemeral agent through the warm local dev plane — with DAG-based scheduling. No webhook, no GitHub, no deployed orchestrator involved. See [`kici run <event> --local`](https://docs.kici.dev/user/cli/runs-and-approvals/#kici-run-event---local) for options like `--env`, `--in-place`, and `--offline`.
|
|
228
228
|
|
|
229
229
|
### Unfiltered vs typed `dispatch()`
|
|
230
230
|
|
|
@@ -351,7 +351,7 @@ With a single-dimension matrix, the current value is available as `matrix.value`
|
|
|
351
351
|
|
|
352
352
|
### Multi-dimensional matrix
|
|
353
353
|
|
|
354
|
-
Use an object to define multiple dimensions. KiCI expands all combinations (capped at 256):
|
|
354
|
+
Use an object to define multiple dimensions. KiCI expands all combinations (capped at 256, and each combination must be unique — a repeated value fails the job rather than running it twice):
|
|
355
355
|
|
|
356
356
|
```typescript
|
|
357
357
|
const test = job('test', {
|
|
@@ -402,7 +402,9 @@ const test = job('test', {
|
|
|
402
402
|
});
|
|
403
403
|
```
|
|
404
404
|
|
|
405
|
-
Exclude is applied first (removes matching combinations), then include adds additional entries.
|
|
405
|
+
Exclude is applied first (removes matching combinations), then include adds additional entries. An
|
|
406
|
+
include entry's values appear in the child job name ordered by dimension name, whichever order you
|
|
407
|
+
write the keys in — see [Include and exclude](https://docs.kici.dev/user/sdk/rules-matrix-dynamic/#include-and-exclude).
|
|
406
408
|
|
|
407
409
|
### Dynamic matrix
|
|
408
410
|
|
|
@@ -590,9 +592,7 @@ post-restart job until the host completes a reboot cycle, then dispatches it.
|
|
|
590
592
|
import { workflow, job, step, restartHost, waitForHostAlive } from '@kici-dev/sdk';
|
|
591
593
|
|
|
592
594
|
export default workflow('patch-and-verify', {
|
|
593
|
-
on: [
|
|
594
|
-
/* ... */
|
|
595
|
-
],
|
|
595
|
+
on: [/* ... */],
|
|
596
596
|
jobs: [
|
|
597
597
|
// Restart job: apply updates, then reboot. restartHost() MUST be the last step.
|
|
598
598
|
job('patch', {
|
|
@@ -727,6 +727,12 @@ export const postDeploy = workflow('post-deploy', {
|
|
|
727
727
|
|
|
728
728
|
`workflowComplete()` / `jobComplete()` start a **separate** workflow run that reacts to the prior one finishing, gated on its status. They are the right tool when a _different_ workflow should respond. When you instead need to add more jobs to the **same** run based on what a job just produced — fanning out follow-up work from a prior job's outputs — use a result-aware generator (next section), not a completion-event chain.
|
|
729
729
|
|
|
730
|
+
#### Failure notifier (any source → any destination)
|
|
731
|
+
|
|
732
|
+
Because the orchestrator auto-emits `workflow_complete` for **every** run, a single workflow with `on: workflowComplete({ status: ['failed'] })` (no `source` filter) becomes an org-wide failure notifier: every failed workflow, whatever repo or provider triggered it, dispatches this one workflow. The runnable example `examples/workflows/failed-workflow-slack-notifier.ts` builds exactly that — it maps the failed run's repo (`ctx.sourceRepo?.identifier`) through an inline `repo → { channel, tag }` table and posts to Slack with `fetch`, guarding the real POST behind `ctx.isTestRun` so a test run never messages a live channel. Swap the `fetch` body for Discord, Teams, PagerDuty, or a plain HTTP endpoint to change the destination — no external package required.
|
|
733
|
+
|
|
734
|
+
The one failure class this pattern cannot catch is a **dead orchestrator**: a workflow can only run while the orchestrator that would dispatch it is alive, so if the orchestrator itself is gone, nothing dispatches the notifier. Watching for an orchestrator that has stopped reporting is the managed notification plane's job, not a workflow's.
|
|
735
|
+
|
|
730
736
|
### Same-run discovery → fan-out
|
|
731
737
|
|
|
732
738
|
A result-aware [`dynamicJob(group, { needs, generate })`](https://docs.kici.dev/user/sdk/rules-matrix-dynamic/#dynamicjob--result-aware-generation) is deferred until its declared upstreams complete, then runs with their frozen outputs as `ctx.needs` — so a discovery job can emit a list at runtime and the generator fans out one follow-up job per item, all in the same run:
|
|
@@ -1261,7 +1267,7 @@ export const testSuite = workflow('test-suite', {
|
|
|
1261
1267
|
await $`pnpm test`;
|
|
1262
1268
|
}),
|
|
1263
1269
|
step('emit-results', async (ctx) => {
|
|
1264
|
-
await ctx.emit(testsPassedEvent
|
|
1270
|
+
await ctx.emit(testsPassedEvent, {
|
|
1265
1271
|
branch: 'main',
|
|
1266
1272
|
commit: 'abc123',
|
|
1267
1273
|
testCount: 142,
|