Using Dalo in CI
Dalo's JSON output and exit codes are intended for automation. A pipeline can check that a skill repository still resolves, audits, and links cleanly before a change reaches anyone's agent.
Useful checks:
dalo status --check --jsonreports resolution and fails when the state needs review, including malformed or unsafe portable agent packages.dalo doctor --check --jsonreports health and fails on error findings.dalo sync --check --jsonrenders the sync result and fails when materialization is blocked or incomplete.dalo source refresh <catalog> --checkchecks catalog drift read-only and fails for changed, moved, or removed selected skills.
Passive release checks are disabled automatically when the conventional CI
environment variable is set. DALO_OFFLINE=1 or DALO_UPDATE_CHECK=never can
also disable them explicitly in other managed environments.
Example GitHub Actions job
name: dalo
on:
pull_request:
push:
branches:
- main
jobs:
dalo:
runs-on: ubuntu-latest
env:
DALO_STORE: ${{ runner.temp }}/dalo-store
steps:
- uses: actions/checkout@v7
- name: Install dalo
run: cargo install dalo
- name: Configure a temporary Dalo store
run: |
dalo init
dalo target link generic "$RUNNER_TEMP/dalo-skills"
dalo source add project .
dalo sync
- name: Check dalo status
run: dalo status --check --json > dalo-status.json
- name: Check dalo health
run: dalo doctor --check --json > dalo-doctor.json
The checkout in this example is a local Git source. Replace . with the path
or URL of the skill repository that the workflow should validate. The temporary
store and generic target keep the check isolated from any runner state.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Expected actionable failure, including semantic value validation, failed checks, and security-audit blocks |
| 2 | Usage error from invalid arguments or flags; emitted as plain text even with --json |
| 3 | Unsafe state blocked the operation |
| 4 | Dependency or environment problem |
Treat 1 as a user-actionable configuration or drift problem, 3 as a safety stop that should not be auto-fixed, and 4 as a runner/tooling problem.
Catalog drift
For catalog sources, use the read-only refresh check. --check changes only
the exit status; neither form advances the catalog pin:
dalo source refresh company-catalog --check
The command reports new available skills, selected skill changes, moved or removed selections, and changed requirements without changing the source lock. New unselected skills remain informational; any selected-skill drift exits with code 1 for review.
Pin advancement is deliberately separate from CI checking. Preview the exact transaction without writes, then apply it only in a reviewed maintenance flow:
dalo --dry-run --json source refresh company-catalog --advance
dalo source refresh company-catalog --advance
The advance report contains both lock entries, every drift classification,
the affected materialization plan, and blocking reasons. Never add --advance
to an unattended drift-check job.
How Dalo itself is released
The rest of this page is for maintainers. It documents how a Dalo release is built and published, and you do not need it to run Dalo in your own pipeline.
Release publication
The publish workflow keeps a new GitHub release as a draft while its five target archives, checksums, and Sigstore bundles build and upload. The workflow creates the release tag at draft time so each matrix job can check out the exact release commit. A single final job verifies every expected asset and publishes the release only after the complete matrix succeeds. If a build is failed or cancelled, the incomplete release remains a non-public draft and the preceding public latest release stays available.
GitHub is published before crates.io, npm, or the Homebrew tap dispatch. Each of those downstream channels depends on the final GitHub-release job, so no public installer path advertises an archive before GitHub makes that archive available.
Release candidate rehearsal
The repeatable part of the release rehearsal runs against a clean temporary home, store, and generic agent target. It exercises the documented initialize, target, local-skill, sync, status, doctor, plan, and recovery-summary paths, plus assistant installation, repeat installation, target delivery, and preservation of a user-edited assistant. It prints a transcript for the CI log. This checks CLI behavior; it does not prove that a real agent discovers and invokes the skill.
sh scripts/release-rehearsal.sh
CI runs the same script on its Linux and macOS jobs using the release binary
already built for that runner. When a 1.0.0 candidate is available, set
DALO_REHEARSAL_EXPECTED_VERSION=1.0.0 so the rehearsal also verifies the
candidate version. This does not replace the post-tag distribution smoke test:
the five public channels below still have to be checked from clean machines
after GitHub publishes the release.
Releasing 1.0.0
release-please-config.json sets bump-minor-pre-major: true, so every
feat!: commit below 1.0.0 produces a minor bump, not a major. The first major
is requested explicitly, with a Release-As: footer on a commit that reaches
main:
chore(release): release dalo 1.0.0
Release-As: 1.0.0
The footer is matched case-insensitively on the token Release-As, it must sit
in the commit footer, and it works with any Conventional Commit type — including
types the changelog normally hides, because the changelog generator keeps a
commit that carries the footer. Pull requests are rebase-merged, which preserves
the footer; a squash merge only preserves it when the squash body keeps it.
Other trailers such as Co-Authored-By: may follow it.
Release-please then opens chore(main): release dalo 1.0.0 on
release-please--branches--main--components--dalo, writes the ## [1.0.0]
CHANGELOG heading, and stamps 1.0.0 into Cargo.toml, Cargo.lock,
npm/package.json, both npm/package-lock.json version paths, and the three
annotated slots in site/index.html (softwareVersion plus the two
data-dalo-version spans). Release Please generates the GitHub release notes
and CHANGELOG from Conventional Commits.
Merging that release pull request tags dalo-v1.0.0 and runs publish.yml:
five signed archives and signed amd64/arm64 Debian packages upload with
checksums to a draft release, the draft is published once every asset is
present, and crates.io, npm, and the
sebastian-software/homebrew-tap dispatch follow. The tap bump compares
versions with sort -V, so 1.0.0 supersedes 0.16.0 rather than losing to
it in string order.
Smoke every channel once the release page is public:
brew upgrade dalo && dalo --version
npx getdalo@latest --version
cargo binstall dalo && dalo --version
mise up && dalo --version
curl -fsSL https://dalo.sh/install.sh | sh && dalo --version
Then check the upgrade path itself from a 0.16 install: run any command under a
TTY with DALO_UPDATE_CHECK unset and CI unset, and confirm the notice reads
update available: dalo v1.0.0 (installed v0.16.0 via <channel>) with one v
per version and the upgrade command that matches the channel it was installed
from.
Final 1.0 acceptance
Keep evidence on #841 for the exact candidate commit and the published tag. Closed implementation issues do not stand in for these checks:
- All required CI jobs on the candidate are green, including the separate release-build performance guard and the assistant CLI rehearsal.
- On a clean macOS or Linux account, an actual Codex or Claude Code session follows the installation guide, discovers the Dalo skill after delivery, and invokes it. Record agent version, platform, commands, and results. Also check the missing/outdated skill offer, refusal, and preservation of custom content.
- Old draft releases have been removed without deleting published releases or their Git tags. The 1.0 release contains the generated notes and all signed assets.
- After publication, fresh installation and upgrade work through the documented
channels, including the Nix flake at
dalo-v1.0.0. Record the version anddoctorresult per platform and channel; the CLI rehearsal alone cannot establish distribution availability.
Source: docs/ci.md