Getting Started
cikit is a lightweight CI helper framework for building local development and CI workflows from reusable Python components.
The cikit console command combines commands from installed command-provider
packages with optional project-local commands. Local commands can extend the
installed command set or override individual provider commands.
Installation
Install cikit with pip:
pip install cikit
or add it as a development dependency with uv:
uv add --dev cikit
The package provides the cikit console command.
Command Setup
A project can obtain commands in two ways:
install a reusable command-provider package
define project-local commands in a root-level
ci_commandspackage
Both approaches can be combined.
Installed Provider
A command provider registers a Python package through the cikit.commands
entry-point group. Once that package is installed, its commands are discovered
automatically.
For example, a project may keep cikit and a shared provider in its development dependencies:
[dependency-groups]
dev = [
"cikit",
"company-ci-commands",
]
No local ci_commands package is required when all needed commands come from
installed providers.
Project-Local Commands
Create a root-level ci_commands package when the project needs its own
commands, orchestration, or overrides:
project/
|-- ci_commands/
| |-- __init__.py
| `-- check.py
|-- src/
|-- tests/
`-- pyproject.toml
The package name ci_commands is fixed. Public modules inside it are
discovered automatically.
A local command with the same COMMAND_NAME as an installed provider command
overrides that provider command.
First Project Command
Every command module declares a logical command name and provides a
register() function.
A minimal command can look like this:
import argparse
from cikit import CiSection
from cikit.ci import run_ci_script
COMMAND_NAME = "check"
def run(env, status, _args: argparse.Namespace):
with CiSection("Checking project", status=status):
print(f"Project: {env['PROJECT_NAME']}")
def command(args: argparse.Namespace) -> int:
return run_ci_script(
COMMAND_NAME,
lambda env, status: run(env, status, args),
args=args,
)
def register(subparsers: argparse._SubParsersAction):
parser = subparsers.add_parser(COMMAND_NAME, help="Run project checks.")
parser.set_defaults(func=command)
With this module stored as:
ci_commands/check.py
the command is available as:
uv run cikit check
Use:
uv run cikit --help
to list the effective commands from installed providers and the current project.
For the complete discovery rules, provider-package structure, conflict handling, and recommended command module structure, see CI Commands.
Global Options
The cikit command provides global options before the selected command.
Verbose logging can be enabled with:
uv run cikit --verbose check
The logical run name can be overridden with:
uv run cikit --name custom-check check
The logical run name is used by cikit data and artifact metadata.
Reusable Workflows
Commands normally orchestrate reusable cikit macros instead of implementing tool integration themselves.
For example, a command set may provide commands for:
linting
tests
coverage
CMake or PlatformIO builds
report generation
Sphinx documentation
Reusable commands can live in an installed command provider. Project-specific
policy and orchestration can remain in local ci_commands.
The cikit repository itself uses commands such as:
init
ruff
pylint
test
coverage
sphinx
all
These names are examples of one workflow and are not built-in commands that every cikit installation receives automatically.
Local Workflow
Projects may optionally provide an orchestration command such as:
uv run cikit all
Such a command can combine existing provider and local commands into one local workflow.
The orchestration strategy, step order, and command arguments remain project-specific.
See Local Pipeline for the recommended approach.
Output
The standard cikit environment uses:
PUBLIC_DIR=${PROJECT_ROOT}/public
CIKIT_DATA_DIR=${PUBLIC_DIR}/cikit_data
Registered artifacts are stored below PUBLIC_DIR according to their
artifact type.
Projects should use the cikit artifact API rather than constructing artifact paths directly.
For details, see:
Coverage Example
If a project collects coverage data across several test runs, the test commands can write intermediate data into a shared directory such as:
build/coverage
A coverage command can then process that directory.
For a project using the same command interface as the cikit repository, this would look like:
uv run cikit --name unittests test tests/unittests --coverage-dir build/coverage
uv run cikit --name systemtests test tests/systemtests --coverage-dir build/coverage
uv run cikit coverage build/coverage
The availability and arguments of these commands depend on the installed command providers and optional local overrides.
Documentation
Projects can integrate generated cikit reports and artifacts into Sphinx.
A project using a corresponding command implementation can build documentation with a command such as:
uv run cikit sphinx docs
The command normally wraps the reusable cikit.macros.sphinx functionality.
See:
CI Providers
The same commands can be used locally and in supported CI environments.
cikit currently provides CI-provider integration for:
GitLab CI
Azure DevOps
local Git execution
CI providers are separate from command providers. CI-provider detection and metadata are exposed through the common cikit environment regardless of where a command implementation was discovered.
For provider-specific setup, see:
Next Steps
After the first command is working, the following guides provide the next level of detail:
CI Commands – command providers, local commands, discovery, overrides, status handling, and reusable macros
Local Pipeline – orchestration of multiple commands
Builds – CMake, PlatformIO, build artifacts, and reports
Timeline Charts – historical metrics and timeline charts
Sphinx Documentation Build – generated documentation and artifact integration
GitLab CI Integration – GitLab-specific integration
Azure DevOps Integration – Azure-DevOps-specific integration