A point-by-point look at KiCI — typed-TypeScript pipelines on infrastructure you control — versus GitHub Actions’ YAML workflows on GitHub-hosted or self-hosted runners.
Pipelines are real, typed TypeScript — loops, conditionals, functions, autocomplete
Workflows are authored in YAML, and custom actions are composite (YAML) or JavaScript actions
Source code and secrets
Your source and secrets stay on your own sovereign infrastructure; KiCI’s hosted control plane never receives them
Your source lives on GitHub, and Actions secrets are uploaded to GitHub — which decrypts them to inject into the workflow runtime
Self-hosted execution model
The whole execution environment — orchestrator and agents — is self-hosted and sovereign on your own infrastructure; KiCI operates only the hosted control plane
Self-hosted runners execute jobs on machines you deploy and manage, while the workflow orchestration stays on GitHub
Autoscaling ephemeral agents
A built-in auto-scaler provisions ephemeral agents on demand across Docker/Podman containers, bare-metal processes, and Firecracker microVMs — on your own infrastructure, with no extra controller
Autoscaling self-hosted runners needs a separate Kubernetes controller — Actions Runner Controller (ARC) — or you rely on GitHub’s managed cloud runners
Cost model
The hosted control plane is free with full functionality; paid tiers raise observability and usage limits (retention, members, orchestrators) for scale and experience — they never meter your executions, so the cost never grows with how much CI you run. You provide the execution compute itself.
Self-hosted runner usage is free (you supply and run the machines); GitHub-hosted runner minutes are metered and billed per minute
Development experience
Testing & local dev loop
kici run --local and kici run remote trigger a workflow straight from your current codebase — including unstaged changes — so you get a result without committing or pushing
Workflows run on runners when triggered by a repository event, so iterating means committing the change, pushing it to GitHub, then waiting for a runner to pick up and finish the run before you can see the result — every tweak repeats that round trip
Dynamic job generation
Generate jobs programmatically at runtime — a dynamicJob generator emits job definitions in TypeScript, fanning out one job per item an upstream job discovers (beyond static and dynamic matrices)
Dynamic behavior is matrix-bounded — a job’s matrix can be generated from another job’s JSON output (via fromJSON), expanding one job into combinations
Typed values between steps & jobs
Step and job outputs are declared with Zod schemas, so values passed between jobs are typed and validated — not stringly-typed
Job and step outputs are Unicode strings (up to 1 MB) — structured values must be JSON-encoded and parsed back