Tasks
LocalCI runs checks that are defined as Mise tasks. A task is eligible when its task name starts with localci:.
LocalCI discovers tasks with:
It then runs each matching task with:
Defining tasks
TOML tasks
Use TOML tasks when a check is short and belongs near the rest of your Mise configuration.
Mise documents this format in TOML tasks.
Nested mise.toml files
TOML tasks also work from nested Mise config roots. Tell Mise which child directories are config roots from the repo-level mise.toml:
Then define LocalCI tasks inside those child configs:
[tasks."localci:test"]
description = "Run Vue unit tests"
run = "pnpm exec vitest --run"
[tasks."localci:build"]
description = "Build documentation"
run = "zensical build --strict"
LocalCI uses Mise's task list, so nested tasks keep their path prefix. In the UI, LocalCI removes the localci: namespace from task labels: a root task like localci:test shows as test, and a nested task like //web:localci:test shows as //web:test.
Mise documents the path syntax in monorepo tasks.
File tasks
Use file tasks when a check is easier to maintain as a script.
Mise documents this format in file tasks.
File tasks in monorepos
File tasks work the same way inside nested config roots. For example, this file:
is exposed by Mise as //web:localci:test, and LocalCI shows it in the UI as //web:test.
Setup tasks
Use a root localci:setup task for dependency installation shared by all checks.
[tasks."localci:setup"]
description = "Install dependencies for LocalCI runs"
run = "mise install"
LocalCI runs localci:setup first when it exists. It is setup for the run, not an ordinary validation check.
Only the root setup task is used. LocalCI ignores setup tasks from nested config roots, such as //web:localci:setup. If you need package-specific setup, use task dependencies.
Task execution environment
Tasks run either in shallow clones of a specific commit, or on your working directory when you pass --no-clone. Runs with --no-clone are marked with an asterisk * in the UI because their state won’t match what’s in git.
Environment variables
Every task receives these environment variables:
| Variable | Meaning |
|---|---|
LOCALCI_TASK_OUTPUT_DIR |
Directory for artifacts from this task attempt. |
LOCALCI_TASK_ARTIFACTS_FILE |
JSON manifest path for named artifact actions from this task attempt. |
LOCALCI_TASK_CACHE_DIR |
Cache directory for this task. |
LOCALCI_CACHE_DIR |
Cache directory shared by LocalCI tasks. |
Write reports and inspectable artifacts under LOCALCI_TASK_OUTPUT_DIR. LocalCI exposes those files in the web and terminal UIs.
Task output
LocalCI captures each task's stdout and stderr into combined.log. For ordinary checks, let the task print normally:
For tasks with multiple outputs, write them under LOCALCI_TASK_OUTPUT_DIR:
mkdir -p "$LOCALCI_TASK_OUTPUT_DIR/coverage"
pytest --cov --cov-report=html:"$LOCALCI_TASK_OUTPUT_DIR/coverage"
If a task has an output people should open from higher-level views, write a manifest to LOCALCI_TASK_ARTIFACTS_FILE. Manifest paths are relative to LOCALCI_TASK_OUTPUT_DIR, and marked artifacts sort before ordinary artifacts:
mkdir -p "$LOCALCI_TASK_OUTPUT_DIR/site"
cp -R site/. "$LOCALCI_TASK_OUTPUT_DIR/site/"
cat >"$LOCALCI_TASK_ARTIFACTS_FILE" <<'JSON'
{
"version": 1,
"artifacts": [
{"name": "docs html", "path": "site/index.html", "action": "open"}
]
}
JSON
Valid actions are open, download, reveal, and view.
Here‘s how you might configure a browser testing tool like Playwright to put its filesystem output in the right place:
import { defineConfig } from '@playwright/test'
export default defineConfig({
outputDir: process.env.LOCALCI_TASK_OUTPUT_DIR
? `${process.env.LOCALCI_TASK_OUTPUT_DIR}/playwright-artifacts`
: 'test-results',
reporter: [
['list'],
[
'html',
{
outputFolder: process.env.LOCALCI_TASK_OUTPUT_DIR
? `${process.env.LOCALCI_TASK_OUTPUT_DIR}/playwright-report`
: 'playwright-report',
open: 'never',
},
],
],
})