Dalo User Reference
This is the user-facing reference for scripting Dalo and for understanding the files Dalo writes. It documents the current CLI and persisted schemas.
For a conversational interface to these operations, use the Dalo assistant skill in your existing agent.
Compatibility
This page describes current behavior. Whether a given command, flag, exit code,
JSON field, persisted file, or environment variable is a stability promise is
answered by Compatibility and stability: commands, exit
codes, --json top-level shapes, persisted schemas, environment variables, and
install channels are stable within a major version; surfaces marked
experimental here may change in any release; human-readable output text,
store-internal layout, and the Rust library API are not covered.
Store Resolution
Dalo chooses the store path in this order:
--store <PATH>DALO_STORE~/.dalo
Relative store paths are resolved against the current working directory. ~ is expanded when used at the start of a path.
Without an explicit CLI or DALO_STORE override, the nearest dalo-project.toml
selects project scope. Discovery walks upward and stops at the Git repository
boundary. Use --global / -g to select ~/.dalo even inside a project, or
--project <directory> to select a project explicitly. These flags conflict
with --store. See Project installations for discovery,
interactive initialization, and the versioned definition.
Environment Variables
| Variable | Purpose |
|---|---|
DALO_STORE |
Override the default store path; --store takes precedence. |
DALO_GIT_TIMEOUT_SECS |
Positive timeout in seconds for every Git subprocess. Invalid or zero values use the built-in defaults. |
DALO_OFFLINE |
Disable passive update checks when set to a truthy value. |
DALO_UPDATE_CHECK |
Set to never to disable passive update checks. |
DALO_ASSISTANT_CHECK |
Set to never to disable automatic bundled assistant preparation and target delivery during setup/sync. Explicit assistant commands still work; an installed bundle remains eligible for ordinary sync. |
DALO_INSTALL_CHANNEL |
Installation context set by a launcher so the update notice recommends the matching upgrade command. |
NO_COLOR |
Disable ANSI color output when set. |
DALO_TARGET |
Installer-only release target override. A non-empty value takes precedence over platform detection; see installer target variables. |
For installation variables, see the README installation section
and the npm launcher README: DALO_VERIFY,
DALO_LINUX_LIBC, DALO_INSTALL_DIR, DALO_VERSION, and DALO_CACHE_DIR.
DALO_TARGET
DALO_TARGET is read only by https://dalo.sh/install.sh; it is not a Dalo
CLI option and does not affect an installed binary. An unset or empty value
uses automatic detection: macOS chooses its aarch64 target, and Linux
chooses x86_64 or aarch64 plus the detected (or
DALO_LINUX_LIBC-overridden) libc. A non-empty value takes precedence and is
used verbatim to form the release archive name. Set it only to a published target:
x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu,
x86_64-unknown-linux-musl, aarch64-unknown-linux-musl, or
aarch64-apple-darwin. The installer does not pre-validate the override;
another value fails when its release archive cannot be fetched.
Global Flags
Global flags can be placed before or after the command.
| Flag | Meaning |
|---|---|
--global, -g |
Select ~/.dalo, bypassing project discovery and DALO_STORE. |
--project <DIR> |
Explicit project scope; see Project installations. |
--store <PATH> |
Use a store other than the resolved default. |
--json |
Emit machine-readable JSON for commands that support structured output. It requires a command; bare dalo --json returns the standard JSON error on stderr. manpage and completions reject this flag with a plain-text usage error because they generate plain text only. |
--dry-run |
Plan supported mutating operations without changing persistent state. migrate skills-sh still clones into temporary directories to verify content. Read-only commands ignore it. |
-h, --help |
Print command help. |
-V, --version |
Print the installed version. |
Update Notices
After a successful interactive command, Dalo checks for a newer GitHub release
at most once per 24 hours. The check uses a one-second network timeout and
never changes the command's exit status. Checks are skipped for --json, CI,
DALO_OFFLINE=1, and DALO_UPDATE_CHECK=never. Offline commands such as
assistant install and plugin validate skip these notices as well.
The check runs beside the command on its own thread. A command that finishes first waits up to 150 milliseconds for the answer, so even a command that takes ten milliseconds prints the notice in the same run. When the release API is slower than that, the command exits without waiting further and the answer is recorded instead, so the next interactive command prints the notice with no network access at all. A check that never reported back leaves a pending record and is retried after five minutes rather than counting as the day's check; the 24-hour interval starts from a check that actually reached the release API.
The result lives in last-check inside ${XDG_CACHE_HOME:-~/.cache}/dalo/update-notices,
a versioned key=value record holding the schema version, whether the check
completed, the version that ran it, and the newer release it found. A record
written by an unrecognized schema or by a different installed version is
ignored, which makes the next command check again. Deleting the directory only
costs one extra check. A fresh install has no record, so its first interactive
command checks immediately instead of staying silent for the first day.
Dalo never modifies its own executable. If the installed version is outdated,
the notice recommends an upgrade command for Homebrew, npm/npx, mise, Cargo, or
the hosted installer. Launchers may set DALO_INSTALL_CHANNEL so the Rust binary
can preserve their installation context. Unknown installation methods receive a
link to the installation guide instead of a guessed command. Each newer version
is announced only once per user cache.
Command Reference
Commands that act on a project declaration have their own sections further
down: dalo install, dalo project add,
dalo project update,
dalo project remove, and
dalo migrate skills-sh. So does
dalo promote.
dalo init
Initialize the store layout, default config, local Git source, lock/state files, and approvals file.
Examples:
dalo init
dalo --store /tmp/dalo-demo init
dalo --json --dry-run init
JSON output shape: InitReport.
dalo assistant status
Inspect the assistant without writing files or using the network. Works before store initialization and compares the installed bundle with the running executable, not the latest release on the internet. Unknown, unreadable, or modified content is reported as blocked, never as missing.
dalo assistant status
dalo --store /tmp/dalo-demo --json assistant status
JSON output shape: AssistantStatusReport. Its state is missing_store,
missing, current, update_available, external, or blocked. It includes
the binary's version, verified installed_version when available, the local
skill_path, an optional reason, discovered external_paths, enabled
undelivered_targets, and an optional next_command. current describes the
local bundle, so check delivery separately. External entries are inspected in
configured/default target folders, agent configuration overrides, the Codex skill folder, and the current
project's .agents, .claude, and .codex skill folders. Their freshness is
not inferred from the name. The report is also the additive assistant field
in status --json. A verified delivered companion satisfies its own delivery
requirement; other skills retain ordinary lock and target health checks.
The first ordinary invocation (dalo, next, status, source/target commands,
or sync) prepares the packaged bundle automatically, creating a missing store
without a separate init. Every normal use verifies the complete receipt and
updates only an unmodified bundle to match the running executable. JSON and
noninteractive calls follow the same policy.
For the default global store, existing known agent skill folders receive only
the companion skill. They are not registered as targets for other skills.
Custom stores only use already linked targets; project invocations only use
validated project targets. target link remains the explicit route for new
agent paths. init remains an optional setup command. status --json exposes
verified companion delivered_paths; setup/sync JSON reports include an
additive assistant status field when automatic setup is enabled.
Help/version, dry runs, plan, explicit assistant inspection, and independent
team/tool/hook/binary/scheduler commands do not trigger first-use setup.
DALO_ASSISTANT_CHECK=never disables automatic setup and freshness updates.
It does not remove a bundle or exclude it from ordinary sync. Preserve modified
or externally installed assistants and inspect reported conflicts before
switching ownership. Companion-only links use assistant-links.toml, separately
from full-target ownership in state.toml.
dalo assistant install
Prepare the complete assistant bundled with this executable in the initialized
store's local/skills/dalo directory. It works offline and does not fetch
sources, commit local work, link targets, or run sync. The standard enabled,
unnamespaced local source is required. See the assistant guide
for the conversational setup flow.
dalo --dry-run --json assistant install
dalo assistant install
dalo --dry-run sync
dalo sync --check
Link the intended target before syncing. Sync applies the entire store to all linked targets; inspect its full preview. Repeating installation of an unchanged bundle performs no replacement. After upgrading Dalo, run the command again to update the assistant to the executable's version. Existing target symlinks read bundle updates immediately, before another sync.
Installation refuses an unrecorded local dalo directory, modified bundle,
symlink, or unsupported receipt schema. It does not take over a skill installed
by another manager. A foreign target entry remains a normal sync conflict.
See bundled assistant recovery for interrupted
installations. Older binaries may not provide this command; check its --help.
JSON output shape: AssistantInstallReport. The action is install, update,
or existing; dry_run distinguishes a preview from an applied operation.
next_command previews the whole store's sync.
dalo next
Show a compact summary of the selected store and one copyable next action. It
chooses initialization, target discovery, source addition, an exact pending
approval, synchronization, or detailed status when the already-computed store
facts contain errors or inventory warnings. Health problems take precedence
over onboarding guidance. Only when no action is needed does it report
All synced.
Running bare dalo shows this same summary only when stdout is a terminal;
when output is piped it keeps printing the normal static help. Use dalo next
in scripts or whenever you want the state-aware result explicitly.
dalo next
dalo --store /tmp/dalo-demo next
dalo --json next
JSON output shape: NextActionReport with store counts, state, message,
and an optional copyable command.
dalo team init <source-id>
Create dalo.toml in the current team repository. Use --repo <path> on the
team command to target another checkout. Team-management commands do not read
or initialize the personal Dalo store, and they do not commit or push changes.
The global --store flag is accepted for uniformity but has no effect on team
commands; select the target repository with --repo instead. They write the
manifest in canonical TOML form; catalog mutations may normalize formatting and
do not preserve comments.
Examples:
dalo team init company --name "Company Skills"
dalo team --repo ../company-skills init company
dalo --dry-run team init company
An existing manifest with the same source ID is left unchanged. A different ID
is never overwritten. JSON output shape: TeamManifestMutationReport.
dalo team catalog add <id> <git-url-or-path> --version <revision> [--path <directory>] [--track]
Add an external skill set to the team manifest, pinned by default. Repeat --skill for
include/exclude filters; omitting it means all skills.
dalo team catalog add marketing https://github.com/coreyhaines31/marketingskills.git \
--version 0123456789abcdef0123456789abcdef01234567 \
--skill +copywriting \
--skill +launch \
--skill -seo-audit
Use --priority <number> to override the derived default. JSON output shape:
TeamManifestMutationReport.
Use --path <directory> to acquire only a repository-relative skill directory.
This requires a full lowercase commit ID in --version and upgrades the team
manifest to schema version 2. Sync uses a shallow, blob-filtered sparse checkout
and fails if the Git server cannot provide the pinned commit and filtering.
Use --track --version <branch> for explicit fast-forward branch tracking on
every real sync. This upgrades the manifest to schema version 3 and conflicts
with --path. Without --track, symbolic versions retain their resolved local
pin until the declaration changes. See branch tracking.
dalo team catalog skills <id> [filter]...
Replace the complete filter list. Calling the command without filters sets
skills = [], which means all skills.
dalo team catalog skills marketing +copywriting +launch -seo-audit
dalo team catalog skills marketing
JSON output shape: TeamManifestMutationReport.
dalo team catalog version <id> <revision> [--track]
Change the requested commit, tag, or ref. The next dalo sync on each team
member's machine stages, audits, and pins the resolved commit before publishing
it.
dalo team catalog version marketing v2.0.0
Without --track, this disables any existing branch tracking. Add --track
with a short branch name to opt the catalog into tracking instead.
JSON output shape: TeamManifestMutationReport.
dalo team catalog update <id> --from <ref>
Resolve an upstream branch, tag, or ref in a temporary clone, compare the
currently declared version with the candidate inventory, and run deterministic
audits for the selected candidate skills. A successful real update writes the
exact candidate commit to dalo.toml; it never leaves the shared version as a
floating ref. By default it only edits the local manifest; commits and pushes
require the explicit --pr flag.
dalo --dry-run team catalog update marketing --from main
dalo --json --dry-run team catalog update marketing --from v2
dalo --dry-run team catalog update marketing --from main --pr
dalo team catalog update marketing --from main --pr
dalo team catalog update marketing --from main
dalo team catalog update marketing --from main \
--accept-risk "reviewed pinned automation"
Dry-run performs network reads and temporary filesystem work but does not edit
the repository or personal Dalo store. A non-fast-forward candidate, a removed
selected skill, an invalid candidate selection, or a blocking audit finding
prevents the write. --accept-risk <reason> is required to be non-empty and
accepts only blocking security-audit findings from this exact candidate. It
does not bypass non-fast-forward updates, removed skills, invalid selections,
or other structural blockers. Each accepted audit report retains its
content-bound risk_acceptance scope hash; no personal store state is written.
With --pr, Dalo reuses the GitHub CLI adapter used by promote. It requires
an authenticated gh, write access to the GitHub.com origin, and a clean
team repository root matching the current default branch. The update is
committed and pushed from a temporary checkout; the original checkout and
personal store remain unchanged. Only the reviewed version value in dalo.toml
changes in the proposal; existing comments and formatting are preserved.
The PR body is exactly the human dry-run summary, including both full commit
IDs, inventory drift, deterministic audit findings and any accepted-risk reason.
--dry-run --pr does not authenticate, commit, push or create a PR; it still
performs catalog reads and audits. GitHub base freshness is checked on submission.
Repeating the same command for the same base, candidate and review reuses the proposal branch and an existing open PR. If PR creation fails after pushing, the error names the retained branch and tells you to retry. Dalo verifies existing branch contents and never force-pushes; changed branches and closed PRs require review on GitHub. Already current pins create no PR. Other forges, fork-based submissions and scheduling are not supported by this mode.
JSON output shape: TeamCatalogUpdateReport, including
old_version, exact old_commit and candidate_commit, outcomes[],
audits[], accepted_risk_reason, blocking_reasons[], dry_run, and
updated, plus optional branch and pull_request_url. In PR mode updated
remains false because the original manifest was not edited.
dalo team catalog remove <id>
Remove the declaration. The next team-member sync removes generated source state, approvals, owned links, and checkout state for that catalog.
JSON output shape: TeamManifestMutationReport.
dalo team show
Print the source identity and catalog declarations from dalo.toml. Use
--json for TeamManifestView.
dalo target detect
List known agent targets, their linked paths when configured (otherwise their
default paths where known), whether those paths exist, and whether they are
linked in Dalo state. The text output finishes with the next link command when
it finds an installed-but-unlinked agent, a repair command when a recorded
target path is missing, or a generic-folder command when no agent folder is
present. dalo target list is an alias for this command.
Examples:
dalo target detect
dalo --json target detect
Built-in target IDs:
| ID | Default path | Support |
|---|---|---|
codex |
~/.agents/skills |
supported |
claude |
~/.claude/skills |
supported |
cursor |
~/.cursor/skills |
supported |
openclaw |
~/.agents/skills |
supported |
hermes |
~/.hermes/skills |
supported |
opencode |
~/.config/opencode/skills |
supported |
generic |
none, path required | supported |
Each built-in target names the agent release its skill directory and symlink
behavior were verified against in the
agent support matrix. Use dalo target link cursor
for Cursor's user-level skills, or pass a project's .cursor/skills directory
as the target path. Cursor also reads ~/.agents/skills, which the built-in
codex target already covers. See the Cursor verification
for invocation and safety results.
Targets reported as experimental are not covered by the stability promise for
a major version: their IDs, default paths, and behavior may change in any
release. See Compatibility and stability.
JSON output shape: TargetDetectReport.
dalo target link <target> [path]
Record a target materialization directory. The generic target requires an explicit path. Known targets can use their default path or an explicit override.
Examples:
dalo target link codex
dalo target link generic ./tmp/agent-skills
dalo --dry-run target link claude ~/.claude/skills
When a target path does not exist yet, Dalo creates its missing directory
ancestors only after validating the state update. If persisting state.toml
fails, newly created empty ancestors are removed again; pre-existing directories
and any concurrent content are preserved.
JSON output shape: TargetLinkReport.
dalo target unlink <target>
Disable a target in state. unlink itself removes nothing from the target
directory. The next dalo sync then reconciles the target and removes the
Dalo-owned links it had materialized there; unmanaged files and real
directories are never touched.
Examples:
dalo target unlink codex
dalo --json target unlink generic
JSON output shape: TargetUnlinkReport.
dalo source add <id> <git-url-or-path> [--namespace <prefix>] [--ref <git-ref>] [--subpath <directory>]
Add a trusted team source, clone it into sources/<id>/checkout, configure it
with update_policy = "track", and run a deterministic security preflight for
every discovered skill. Source IDs must be a single path component using only
letters, digits, ., _, and -; . and .. are rejected.
Local paths are supported; relative paths resolve against the current working
directory.
--subpath scans only a directory inside the checkout. It must be a non-empty
relative path without .. traversal; missing directories and symlinks that
escape the checkout block scanning. --ref resolves a branch, tag, or commit
to an exact detached commit and sets update_policy = "pin"; omit it to track
the repository's default branch. The selected subpath is recorded in
config.toml and lock.toml, so changing it reports lock drift.
Examples:
dalo source add platform git@github.com:example/platform-skills.git
dalo source add company git@github.com:example/company-skills.git --namespace company
dalo source add platform git@github.com:example/monorepo.git --ref v1.2.0 --subpath tools/skills
dalo --dry-run source add team https://github.com/example/team-skills.git
JSON output shape: SourceAddReport.
When discovery skips or degrades a skill, source add prints each inventory
warning with its path and actionable reason before continuing to audit the
valid skills. Skipped skills are not audited or materialized. JSON consumers
receive the same typed entries in SourceAddReport.inventory_warnings[].
dalo source add-catalog <id> <git-url-or-path> [--namespace <prefix>]
Add an untrusted catalog source, clone it into sources/<id>/checkout, and
configure it with update_policy = "pin". Catalog skills are offers; nothing
from a catalog becomes active until selected and approved.
After adding a catalog, the CLI reports how many skills are available and prints
the exact source inspect and source select commands for the next step.
Local paths are supported; relative paths resolve against the current working
directory.
Examples:
dalo source add-catalog public https://github.com/example/skill-catalog.git
dalo source add-catalog editorial https://github.com/example/editorial-skills.git --namespace editorial
dalo source inspect public
dalo source select public review-helper
JSON output shape: CatalogAddOutcome (source, available_skills, dry_run).
available_skills is null during a dry run because no catalog checkout is
created or inspected.
dalo source list
List configured sources in priority order. Git-backed entries include a
read-only provenance object assembled from config, source-lock.toml, and the
checkout without fetching: management authority, credential-redacted origin,
requested ref, resolved pin, and checkout commit.
Examples:
dalo source list
dalo --json source list
JSON output shape: SourceListReport.
dalo source priority <id> <priority>
Change a source priority. Lower numbers win during resolution. The local source priority is fixed and cannot be changed.
Examples:
dalo source priority platform 10
dalo --dry-run source priority platform 20
JSON output shape: SourcePriorityReport.
dalo source namespace <id> [<prefix>] [--clear]
Set an optional namespace for every skill from a configured source.
Dalo installs namespaced skills as <prefix>__<skill> and resolves them under
that name, so same-named skills from distinct namespaced sources can coexist.
The source SKILL.md files and source-qualified approval identities remain
unchanged. Prefixes use the same portable lowercase token rules as skill names.
Use --clear to restore the source's original install names. The built-in
local source cannot be assigned a namespace, but --clear can restore its
original slot names if a legacy configuration contains one, so local adaptations
continue to override matching managed skills.
Examples:
dalo source namespace company company
dalo source namespace company --clear
JSON output shape: SourceNamespaceReport.
dalo source inspect <id>
Inspect a catalog source and list available candidate skills, including ID, slot name, path, description, compatibility, dependencies, and selection status.
Examples:
dalo source inspect public
dalo --json source inspect public
JSON output shape: CatalogInspectReport.
dalo source select <id> <skill>...
Select catalog skills by stable frontmatter ID, slot name, catalog-relative path,
or a source-qualified <source-id>:<slot-or-stable-id> reference. The source ID
must match the catalog being selected.
Selection runs the deterministic security preflight, writes
config.toml, and updates source-lock.toml with the pinned commit and
inventory snapshot. Human-readable output names the skills added or removed,
reports no-op requests explicitly, and shows the complete resulting selection
as secondary detail.
Examples:
dalo source select public review-helper
dalo source select public review-helper public:formatter
dalo source unselect public formatter
dalo --dry-run source select public review-helper
JSON output shape: CatalogSelectReport.
dalo source unselect <id> <skill>...
Unselect catalog skills by stable frontmatter ID, slot name, catalog-relative
path, or a source-qualified <source-id>:<slot-or-stable-id> reference. The
source ID must match the catalog being changed. This is the explicit negation
counterpart to source select.
Unselecting also cleans up release binaries. A staged binary whose declaring
skill is no longer selected, and that no other approved declaration pins, is
removed with its exposure link. The removed paths appear as removed: lines in
human output and in removed_binary_paths[] in JSON.
Examples:
dalo source unselect public formatter
dalo --dry-run source unselect public formatter
JSON output shape: CatalogSelectReport.
dalo source refresh <id>
Fetch a catalog source and compare the upstream inventory with the pinned
inventory snapshot. This is read-only for pins and selections. --check exits
non-zero when selected skills drifted upstream. --advance explicitly updates
only this catalog after candidate approval, dependency, audit, and
materialization preflight. Selected removal, dirty or divergent checkouts,
security-audit blocks, and unsafe target state stop the transaction.
Examples:
dalo source refresh public
dalo source refresh public --check
dalo --json source refresh public
dalo --dry-run --json source refresh public --advance
dalo source refresh public --advance
JSON output shape: CatalogDrift.
With --check, the command exits with code 1 when a selected skill changed,
moved, or was removed upstream. New unselected offerings remain informational.
--advance and --check are mutually exclusive. Global --dry-run with
--advance returns CatalogAdvanceReport, including the complete old and new
catalog lock entries, stable drift codes, reconciled selection, security audit
results, materialization plan, and blocking reasons. It performs no config,
lock, checkout, audit-cache, state, or target writes. A real advance updates the
checkout, source-lock.toml, any stable-ID move in config.toml, lock.toml,
and affected owned target links as one rollback-safe transaction. Newly
required unapproved skills remain unlinked and can be approved after the new
pin is installed; their dependents remain blocked until then. A candidate with
blocking audit findings stays in sources/.audit-staging/; the report prints
the exact staged path to review and, when justified, accept for that content
hash before retrying the advance.
dalo source remove <id>
Remove a team or catalog source as one coordinated change. Dalo first reconciles
only links it owns, then removes the source from config.toml, its catalog lock
entry (when present), and approvals qualified with that source ID. The source
checkout is removed after the durable store state is committed. Staged release
binaries that no other approved declaration pins are removed right after that
commit, and their paths are listed in affected_paths[]. Use
--keep-checkout to retain it for manual inspection. The built-in local
source cannot be removed. A retained checkout must be moved or removed before
the same source ID can be added again.
Examples:
dalo --dry-run --json source remove platform
dalo source remove public
dalo source remove public --keep-checkout
Both dry-run and real --json output use SourceRemoveReport. It lists
deactivated skills, the operation kind for every reconciled owned link, and any
non-fatal checkout cleanup warnings. Dry-run does not modify config, locks,
approvals, checkouts, or targets.
dalo status
Show source scans, linked targets, active skills, pending approvals, unlinked skills, user-lock drift, unmanaged target skills, instruction packs, topic overlaps, and instruction block drift.
Examples:
dalo status
dalo status --check
dalo --json status
JSON output shape: StatusReport.
--check exits with code 1 for unresolved source scans, skill or agent inventory warnings,
pending approvals, blocked required closure, blocking or failed security audits,
blocked materialization operations, missing targets for active skills, actionable
resolution diagnostics, lock drift, unmanaged blockers, instruction-block drift,
or unhealthy autosync state. It keeps the full report on stdout for JSON
consumers.
dalo plan
Show the effective plugin setup for every linked target without changing source,
approval, or target files. Use it before sync to review selected plugins,
target compatibility, approval state, and provider package paths. Planning never
runs tools or hooks. Pass --target to limit the report to one linked target.
dalo plan
dalo plan --target codex
dalo --json plan
JSON output shape: InstallationPlan.
dalo agent list [--check]; dalo agent show <source>:<name>
Canonical agent packages live in agents/<name>/AGENT.md inside a source.
agent list shows active, pending, and shadowed packages; agent show previews
the package for Claude and Codex without writing provider files.
dalo agent list --check
dalo agent show local:reviewer --provider codex
dalo approve agent team:reviewer
Non-local agents need explicit approve agent <source>:<name> records; skill,
source, author, and org approvals do not activate them. Invalid packages also
make status --check fail. agent list returns a non-zero exit code after
reporting source scan errors because its result is incomplete; --check also
returns a non-zero exit code for package inventory warnings. JSON shapes:
AgentListReport (resolution, inventory_warnings[], source_errors[]) and
AgentShowReport (agent, compilations[]).
dalo sync
Refresh clean tracking team sources, resolve the desired skill set, materialize owned symlinks into linked targets, and write lock.toml. Dirty tracking sources block refresh. Dalo does not overwrite unmanaged real directories or foreign symlinks.
Before materialization, Dalo audits the exact content hash of every active
skill. Unaccepted high or critical findings stop the command before any
links are changed. A previously recorded risk acceptance is reused only while
the complete directory hash, audit-engine versions, coverage, and finding set
remain unchanged.
Tracking team updates are fetched and audited in a detached worktree below
sources/.audit-staging/ before the live checkout fast-forwards. Existing
target links therefore continue to expose the last accepted commit. When an
update is blocked, the error prints a command for auditing and accepting the
exact staged skill; the next sync reuses that staged hash.
Examples:
dalo sync
dalo sync --check
dalo --dry-run sync
dalo --json sync
JSON output shape: SyncReport. deliveries[] records each logical skill and
physical target slot with target_ids, mode, optional provider, selected
artifact_path, content fingerprint, and any fail-closed reason.
dalo --dry-run sync does not fetch tracking team sources, so it prints a
note when upstream changes are not reflected in its plan. Run a real
dalo sync to fetch those sources first; JSON consumers can inspect
SyncReport.unrefreshed_tracking_sources[].
sync --check still renders the report, then exits with code 1 when materialization
is blocked or incomplete, including pending approvals, resolution diagnostics,
degraded sources, blocked operations, or active skills without linked targets.
An enabled source is degraded when Dalo cannot safely scan it, for example
because its checkout is missing or unreadable, a tracking refresh failed, or
inventory warnings make removals ambiguous. Dalo preserves recorded owned links
from that source instead of treating the incomplete scan as a deletion. A normal
sync can still apply unrelated safe work and exits successfully; sync --check
exits with code 1 until the source is healthy. Restore or re-clone the checkout,
or remove the source with dalo source remove <id>. Do not adopt or delete the
preserved target link as if it were an unmanaged conflict. Machine-readable
consumers can inspect each affected source in SyncReport.degraded_sources[].
sync also prints the individual inventory warnings that caused a degraded
scan, including the affected path and reason, so the removal-safety message is
not the only diagnosis. JSON consumers can inspect the same typed entries in
SyncReport.inventory_warnings[].
In project scope, skipped directory symlinks outside the declared skill selection
and its transitive same-source requires closure do not degrade the source when
that entire closure was inventoried successfully. This includes provider aliases
and unrelated monorepo fixtures. Symlinks overlapping the selected skill paths,
missing selected skills or requirements, other unsafe inventory warnings, and
scan or audit failures still block healthy installation and preserve recorded
links. Global stores retain conservative source-wide discovery.
Lock drift for local and team sources is commit-based. Uncommitted working-tree edits do not change the recorded commit, and materialized symlinks expose those live edits directly. Catalog selections are the source kind with content and metadata fingerprints for upstream drift checks.
dalo autosync install|status|uninstall
For updates managed by an agent, use the host's automation facility to choose timing, retries, and notifications; see Automate updates. The existing OS-native scheduler commands below remain supported in Dalo 1.x.
Install recurring dalo sync --check behavior through the current user's
native scheduler. macOS uses launchd. Linux prefers a systemd user timer and
falls back to cron only when the user manager is unavailable. Supported
schedules are hourly, daily (default for a first install), and weekly.
Omitting --schedule on a reinstall preserves the installed schedule.
Daily and weekly schedules run at a fixed per-store time in the local
early-morning window (00:00–05:59, derived from the store path so different
stores stagger rather than all firing at once). launchd coalesces missed jobs
on wake and the systemd timer uses Persistent=true, but the cron fallback has
no catch-up: a machine powered off throughout its scheduled window simply waits
for the next slot, so prefer hourly on machines that are usually asleep at
night. The window also overlaps the daylight-saving transition, so a skipped or
repeated local hour can shift a single run.
dalo autosync install
dalo autosync install --schedule hourly
dalo --json autosync status
dalo autosync uninstall
Installation records the stable absolute executable or launcher path that was
invoked, preserving Homebrew symlinks and the global npm launcher instead of
pinning their version-specific targets. Temporary npx executions cannot
install autosync; install getdalo globally or use another persistent Dalo
installation first. Generated artifacts never depend on shell startup files.
Reinstalling or removing the job is idempotent. Global --dry-run previews
install and uninstall without writing config, metadata, native artifacts, or
scheduler state. Re-run autosync install after moving the Dalo executable;
status treats a missing recorded executable as disabled instead of guessing a
replacement, and doctor reports the exact missing path.
If autosync.toml is malformed or uses a newer unsupported schema,
autosync uninstall quarantines it as autosync.toml.corrupt-*, reconstructs
the native scheduler identifiers from the store path for best-effort cleanup,
and leaves autosync ready for a clean reinstall.
The internal scheduled runner acquires the store lock once without waiting. If
an interactive Dalo process owns it, the run exits successfully as skipped
and retries on the next schedule. Dirty sources, malformed locks, pending
approvals, security findings, target conflicts, or managed instruction drift
remain fail-closed. autosync-run.toml records the last attempted and last
successful timestamps plus running, succeeded, skipped, or blocked and
an actionable reason. A run left running well past its schedule interval —
for example after a crash or power loss mid-sync — is surfaced by status and
doctor as an interrupted run.
autosync status, normal status, and doctor all surface this durable
state; non-JSON output renders timestamps as UTC calendar times and, when an
installed job is disabled, names the specific cause (missing artifacts, a moved
store, or a scheduler-reported disable). Logs are written to autosync.log and
autosync-error.log in the store. Before each scheduled run, Dalo trims each
file to roughly its most recent 1 MiB, marking discarded older output with a
truncation line. Both files are removed on autosync uninstall.
dalo adopt <skill> [--replace]
Copy an unmanaged target skill into local/skills/<slot>. With --replace, Dalo replaces the original unmanaged directory with an owned symlink after copying. Without --replace, the original directory remains untouched.
Adoption runs the same deterministic security preflight before copying or
replacing anything. --reviewer, --refresh-audit, and --accept-risk <reason>
have the same meaning as on dalo approve skill.
The <skill> argument can be a slot name, a disambiguating path, or an ID reported by status or resolve list. If the slot name exists in more than one target, Dalo refuses the ambiguous selector and lists the paths to choose from.
Before it audits or copies anything, adoption rejects a folder name or
SKILL.md frontmatter name that is not a portable lowercase slot name.
Rename the folder or correct the frontmatter first, then run dalo adopt
again.
Examples:
dalo adopt review-helper
dalo adopt review-helper --replace
dalo --dry-run adopt /path/to/target/review-helper
When --replace reuses an existing local copy, Dalo compares the complete
directory shape before removing the unmanaged original: file bytes and
executable bits, empty directories, and symlink targets must all match.
Successful JSON output combines the preflight and mutation as
{ "audit": AuditReport, "adoption": AdoptReport }. If the audit blocks the
operation, Dalo prints only the blocking AuditReport and exits non-zero.
dalo resolve list
List repairable unmanaged skills, target scan warnings, and recorded owned symlinks.
Examples:
dalo resolve list
dalo --json resolve list
JSON output shape: ResolveListReport.
dalo resolve adopt <id> [--replace]
Adopt an unmanaged skill by an ID returned from resolve list. Behavior matches dalo adopt.
Examples:
dalo resolve adopt review-helper
dalo resolve adopt review-helper --replace
JSON output matches dalo adopt: successful output is
{ "audit": AuditReport, "adoption": AdoptReport }; a blocking audit prints
only AuditReport and exits non-zero.
dalo resolve keep <id>
Protect an unmanaged target skill so Dalo reports it as intentionally unmanaged. Protection is stored by logical target and slot, follows later target-path updates, and turns the sync conflict into a non-failing keep operation. An explicit resolve adopt --replace remains an override.
Examples:
dalo resolve keep review-helper
dalo --dry-run resolve keep review-helper
JSON output shape: KeepReport.
dalo resolve unkeep <target>:<slot>
Remove protection from one target slot. A bare slot name removes matching protection across targets.
Examples:
dalo resolve unkeep claude:review-helper
dalo --dry-run resolve unkeep review-helper
JSON output shape: UnkeepReport.
dalo resolve remove-owned <target>:<slot>
Remove a recorded owned symlink by ID. If the recorded path is already missing, Dalo drops the stale state record. If a different, foreign symlink occupies the path, Dalo leaves that symlink untouched and drops only the stale ownership record. If a real entry exists at that path, Dalo blocks removal, prints the blocked report, and exits non-zero.
Examples:
dalo resolve remove-owned claude:review-helper
dalo --json resolve remove-owned claude:review-helper
JSON output shape: RemoveOwnedReport.
dalo doctor
Run read-only diagnostics for store layout, config, state, lock, approvals, Git availability, targets, owned symlinks, dirty sources, pending approvals, required closures, instruction packs, declared skill commands, and cloud-synced target paths.
Examples:
dalo doctor
dalo doctor --check
dalo --json doctor
JSON output shape: DoctorReport.
--check exits with code 1 when the report contains an error finding. Warnings
remain report-only so CI can choose its own warning policy. A declared skill
command that is missing from PATH is a skill_command_missing warning, so it
keeps --check green.
Doctor emits source_lock_ok only when source-lock.toml exists and parses. If
the file is malformed, it reports source_lock_invalid and suppresses dependent
catalog provenance comparisons so recovery guidance cannot contradict itself.
dalo audit <skill-or-path>
Inspect a skill before it is exposed to an agent. The target can be an existing directory or a source-qualified reference. Deterministic checks are local and never execute skill code.
dalo audit public:review-helper
dalo audit ./my-skill --check
dalo audit public:review-helper --reviewer auto
dalo --json audit public:review-helper --reviewer codex
dalo audit public:review-helper --reviewer claude --refresh-audit
Use --refresh-audit to ignore a compatible cached semantic review and run the
selected provider again.
The report lists each release binary the skill declares under binaries[]:
identity, repository, tag, platforms, and contract_hash. The listing is
informational. Approving the skill does not approve its binaries, and neither
the verdict, the acceptance scope, --check, nor the cached report depends on
it. A declaration that fails validation adds one spec.binaries-invalid finding
(low severity) to spec_findings[] instead, and nothing is listed. An invalid
declaration also drops the skill from its source inventory, so <source>:<skill>
cannot resolve it; pass the skill directory path to audit it.
--reviewer auto|codex|claude|opencode adds a semantic review through an installed
agent CLI. Dalo starts a fresh non-persistent reviewer and treats a bounded
snapshot as untrusted data. Claude and OpenCode run with tools denied. Codex
currently retains its network-disabled, read-only sandbox shell, so Dalo never
selects it through auto; choosing --reviewer codex is an explicit acceptance of
that weaker isolation boundary. User configuration, project rules, skills,
plugins, and MCPs are disabled where the provider supports it. The structured
result contains evidence-backed findings, expected capabilities, and behavior
not disclosed by the skill. Depending on the installed agent configuration,
this can send skill contents to an external model provider and consume that
provider's quota. Dalo never includes .git metadata in that snapshot; a skill
containing a .git entry receives a blocking, partial-coverage finding instead.
Provider processes receive only an explicit runtime and provider-authentication
environment allowlist rather than inheriting Dalo's full environment. Omitting
--reviewer is fully local.
Agent review is optional and additive, not an approval mechanism. It can add
evidence-backed findings to the deterministic audit, but it never clears a
deterministic finding or certifies a skill as safe. A review with no additional
findings means only that this constrained assessment found no additional issue;
it is not an endorsement or safety guarantee. sync does not invoke a provider
on its own. Its human-readable result repeats that boundary after every sync.
--check exits non-zero for unaccepted high or critical findings. Record a
reviewed exception with a non-empty reason:
dalo audit public:review-helper \
--accept-risk "reviewed pinned upstream installer"
Persistence changes (such as shell startup files, scheduled tasks, or agent
configuration) and privileged command execution are high findings and block
by default. General dynamic execution remains a medium review finding: it is
reported, but does not block materialization on its own. This policy keeps
high-confidence persistence and privilege-escalation primitives behind an
explicit, content-bound risk acceptance without treating every technical skill
as unsafe by default.
Agent Skills specification checks run on SKILL.md against the
Agent Skills specification. They are
reported in spec_findings, with category spec, and cover these rules:
spec.frontmatter-missingandspec.frontmatter-malformed: the file has no---frontmatter block, or the block is not a YAML mapping within Dalo's safety limits. No other specification finding is reported in either case.spec.name-missing,spec.name-invalid, andspec.name-slot-mismatch:nameis 1 to 64 lowercase ASCII letters, digits, and hyphens, without a leading, trailing, or doubled hyphen, and it matches the slot Dalo materializes.spec.directory-name-mismatch(info): a validnamematches the slot, but the source folder has a different name.spec.description-missingandspec.description-too-long:descriptionis a non-blank string of at most 1024 characters.spec.compatibility-not-stringandspec.compatibility-too-long:compatibilityis a string of at most 500 characters.spec.metadata-not-mappingandspec.metadata-value-not-string:metadatais a mapping whose values are all strings.spec.unknown-key: a top-level key is outside the specification fields and Dalo'sid,owners,tags,requires, andbinaries.spec.body-too-long(info): the Markdown body after the closing fence has more than 500 lines.
Findings use the low or info severity. They are recomputed on every audit
rather than read from the report cache, and they never change status,
--check, or risk acceptance.
Reports live below audits/ and are keyed by both the source-qualified skill
reference and the complete skill directory hash. After re-hashing the current
directory, a report with the matching source, static-engine version, and scan
mode reuses its deterministic findings and coverage instead of reading and
scanning every file again. Missing, malformed, old-version, changed-content,
unreadable, or incompatible-mode reports are rebuilt before they can affect the
result.
When a non-dry-run audit produces the same durable report content, Dalo retains
the existing report (including its scanned_at_unix value) without rewriting
it.
Cached agent results additionally require the same content, scan mode,
provider, and Dalo review-prompt version. Risk acceptance is bound to source
provenance, engine versions, coverage, and exact deterministic and semantic
findings, so a different source or newly discovered risk requires a new
decision even when the skill bytes did not change.
The audit directory and report files are restricted to the current user when Dalo writes them. Audit state is still a local trust boundary rather than a cryptographically authenticated log: a process running as the same user can replace it. Protect the store like other security-sensitive user state and do not place it in a shared or untrusted writable directory. No-finding results are best-effort observations, not a security certification.
JSON output shape: AuditReport.
dalo plugin validate <source-path>
Validate an author source without initializing or consulting a personal store.
The source must contain plugins/<name>/PLUGIN.toml packages. Dalo uses its
production discovery and dependency rules, reads package files, and reports
contract errors and unresolved references. It never runs handlers, installs
dependencies, grants trust, or changes provider files.
dalo plugin validate ./my-source
dalo --json plugin validate ./my-source
dalo --json plugin validate ./my-source --source-id company
Unqualified references resolve inside the supplied source. --source-id
defaults to validation; set it when the source uses explicit references such
as skill:company:review. Other source identities are reported as unavailable
external references. Validation does not fetch them or read the user's source
registry. Required unresolved references fail validation; optional omissions
remain visible.
JSON output shape: PackageValidationReport, report schema 1. The report keeps
package validity, reference resolution, provider hook capabilities, and execution
authorization separate. A provider capability result does not verify an installed
runtime, all native tool payloads, or permission to execute code. Use plugin review and plan after adding and selecting a package to assess activation.
Exit 0 means the checked source is valid; exit 1 means an invalid or empty package
inventory or unresolved required references. Invalid usage or source paths exit
2. Invalid-source reports remain on stdout with --json; the standard error
envelope appears on stderr. Global --store and --dry-run have no effect on
this read-only command. See the package specification and
compatibility matrix for the bounded contract.
dalo plugin list|show|select|unselect|decline
Inspect and manage direct local plugin selection. Plugin references use
<source-id>:<slot-or-stable-id>.
dalo plugin list
dalo plugin show company:review-workflow
dalo plugin select company:review-workflow
dalo plugin unselect company:review-workflow
dalo plugin decline company:review-workflow \
--rule-id no-shell-hooks \
--reason "shell hooks are outside local policy"
list returns every valid candidate plus the canonical selected graph; show
returns one candidate and its selected state, when reachable. Both commands are
read-only. select adds a direct user selection without replacing
source-authored selections, while unselect removes only that direct user
selection. decline retains selected intent but blocks the plugin with a local
policy record. It requires the plugin to be selected, a unique lower-kebab
--rule-id, and a non-empty --reason for audit context.
The three mutations support --dry-run and report whether configuration would
change. JSON shapes: PluginListReport (candidates[], resolution),
PluginShowReport (candidate, optional selected), and
PluginMutationReport (plugin, action, changed, dry_run).
dalo plugin review <source:plugin>
Review every component decision for one selected portable plugin and its selected dependency closure in deterministic plugin/component/target order:
dalo plugin review company:review-workflow
dalo --dry-run plugin review company:review-workflow
dalo --json plugin review company:review-workflow
The report embeds the same typed installation-plan facts as dalo plan, plus
package provenance, content/contract hashes, agent activation, inactive
instruction recommendations, tool capabilities, hook event/effect/matcher/
timeout/failure semantics, and provider mappings or fallbacks. Existing exact
approvals are marked reused; changed hash-bound contracts are invalidated;
blocked, unsupported, and inactive boundaries stay distinct.
Interactive mode collects y/n answers in memory and requires a final
confirmation before one atomic approval-ledger write. EOF, q, or declining
the final confirmation grants nothing. The displayed review token is rebuilt
under the store lock immediately before commit, so source, approval, audit, or
target drift requires a fresh review. Only the displayed exact skill,
agent, tool, and hook values can be committed—never a plugin/source/
author/org/wildcard approval. Tool bytes may be content-addressed and staged as
an inert prepare step; tools, hooks, generators, semantic reviewers, and target
mutations are never executed by review.
JSON and dry-run modes are read-only and do not prompt. JSON reports set
interactive_approvals to skipped_in_json_mode explicitly; no approval is
granted. Prefer the individual commands below for a single known component,
for revocation, or when a skill's blocking findings require --accept-risk.
dalo tool list [--check]; dalo tool show|audit <source:plugin#tool:id>
Inspect plugin-local executable contracts without running them:
dalo tool list --check
dalo tool show company:review-workflow#tool:detector
dalo tool audit company:review-workflow#tool:detector
dalo --json tool show company:review-workflow#tool:detector
list joins validated tools with their approval, immutable staging, runtime,
platform, and audit state. show returns the full descriptor, contract hash,
source provenance, exact approval value, staged path when present, and an
actionable diagnostic. audit rechecks the tool's declared executable closure
and contract hash; it does not stage, approve, or execute the tool. A failed
audit returns a non-zero exit code after printing its findings. tool list --check returns a non-zero exit code when rejected plugin packages produce
inventory warnings.
JSON shapes: ToolListReport (tools[], warnings[]), ToolStatusReport
(tool, plugin_package_hash, plugin_path, source_provenance,
approval_value, state, optional staged_path, diagnostic), and
ToolAuditReport (tool, contract_hash, plugin_package_hash, passed,
findings[]).
dalo binary list [--check]; dalo binary show <source:skill#binary:id>
Inspect release binaries declared in SKILL.md frontmatter (see
Binary declarations in the SKILL.md Frontmatter section). Both commands
are read-only and never download, verify, stage, or execute a binary:
dalo binary list --check
dalo binary show company:review-helper#binary:impeccino
dalo --json binary show company:review-helper#binary:impeccino
list reports every valid declaration with its state and contract hash,
followed by an actionable diagnostic. show returns the declaration with each
platform's asset, digest, and derived URL, the platform of the running Dalo
binary, the exact approval value, the staged path when present, and the
diagnostic. States are platform_unsupported, pending_approval, hash_drift,
revoked, approved_not_staged, audit_failure, ready, and blocked.
ready requires
the exact approval, staged bytes that re-hash to the pinned digest, and the
exposure link <store>/bin/<id> pointing at those bytes; show reports that
link as exposed_path. Verified bytes that are staged but not linked report
approved_not_staged with the command that links them. Only
dalo approve binary <identity> downloads or stages a binary; list and show
never do. binary list --check returns a non-zero exit code when any skill has
an invalid binary declaration; each one is listed as an
invalid_binary_declaration warning. dalo --json status also lists the
binaries of each active skill under resolution.active_skills[].binaries.
JSON shapes: BinaryListReport (binaries[], warnings[]) and
BinaryStatusReport (binary, skill_source_ref, skill_path,
source_provenance, approval_value, host_platform, state, optional
staged_path, optional exposed_path, optional slot_owner, diagnostic).
blocked is an exposure conflict. Two declarations with the same binary id
compete for <store>/bin/<id>. The declaration that comes first by source
priority (a lower dalo source priority value wins), then by source ID, then by
skill ref, owns the slot, whatever its state. Every other declaration with that
id is blocked, is never exposed, and cannot be approved: dalo approve binary
refuses it before any download. Its slot_owner names the owner, dalo doctor
reports binary_slot_conflict with dalo binary show <owner> as the next step,
and dalo binary list shows it. A catalog skill that its source does not select
is an offer rather than part of the resolution, so it is not listed at all.
dalo status prints each declared binary of an active skill as
binary <identity>: <state> under that skill.
dalo hook list [--check]; dalo hook show <source:plugin#hook:id>
Inspect portable hook contracts without installing or executing them:
dalo hook list --check
dalo hook show company:review-workflow#hook:check-shell
dalo --json hook show company:review-workflow#hook:check-shell
list reports every validated hook with its independent trust state and the
referenced tool's state. show returns the exact hook and tool contracts,
source provenance, approval value, event/effect/matcher/binding semantics, and
an actionable diagnostic. A hook becomes ready only when both its own contract
and its referenced tool contract are ready. These public inspection commands
never project or execute a hook. hook list --check returns a non-zero exit
code when rejected plugin packages produce inventory warnings.
JSON shapes: HookListReport (hooks[], warnings[]) and HookStatusReport
(hook, plugin_package_hash, source_provenance, approval_value,
tool_state, tool, state, diagnostic).
dalo approve
Grant, list, and revoke approval records without editing approvals.toml.
Component and owner values are source-qualified, so an approval cannot
accidentally apply to a different source with the same name.
dalo approve list
dalo approve skill public:review-helper
dalo approve skill public:review-helper --reviewer codex
dalo approve skill public:review-helper --accept-risk "reviewed exception"
dalo approve agent team:reviewer
dalo approve tool team:quality#tool:detector
dalo approve binary team:page-engine#binary:impeccino
dalo approve delivery team:generated-review
dalo approve hook team:quality#hook:pre-commit
dalo approve source team
dalo approve author public:maintainers
dalo approve org public:example-org
dalo approve revoke skill public:review-helper
dalo approve revoke tool team:quality#tool:detector
dalo approve revoke binary team:page-engine#binary:impeccino
dalo approve revoke delivery team:generated-review
dalo approve revoke hook team:quality#hook:pre-commit
Approval writes support --dry-run and --json. A pending skill shown by
status can be approved narrowly with dalo approve skill <source:skill>.
A pending canonical agent shown by agent list can be activated with
dalo approve agent <source:agent>. Tool approval validates and immutably
stages the exact executable closure without running it. Binary approval
downloads only the host platform's asset over HTTPS from GitHub, verifies its
SHA-256 digest before anything is renamed into place, stages the bytes read-only
under binaries/<sha256>/, links them at <store>/bin/<id>, and then records
the exact approval. A mismatch, an oversized asset, or a redirect outside GitHub
fails without writing anything. Revoking a binary removes its approval, then removes the staged bytes
and the link that no approved declaration still backs. The human output names
each removed path as removed: <path> and each kept entry as
warning: <text>; the JSON report carries removed_paths[] and
cleanup_warnings[]. Cleanup does nothing, with a warning, while an enabled
source cannot be scanned or a source is disabled, because the declarations
behind it cannot be seen. Delivery approval is
inert and grants only the exact revision- and recipe-bound generated delivery.
Hook approval grants the exact hook contract after its referenced tool is
ready. Revoking a generated delivery withdraws its Dalo-owned materialized
output on the next sync. The revoke scope is one of skill, agent, tool,
binary, delivery, hook, source, author, or org; Clap validates this
value and exposes the choices to shell completion.
Skill approval always runs the deterministic preflight first and refuses a
blocking result unless a reason is supplied with --accept-risk. --reviewer
adds the same isolated semantic review as dalo audit.
approve list preserves each approval record and adds its recorded grant time
when available (older ledgers are explicitly labeled as lacking it). It also
surfaces every persisted accepted-risk audit, marking whether its exact content
and audit binding are still active, with its source reference, reason/timestamp,
scope binding, and a same-store command for re-inspection. The human output
explains that @sha256: suffixes bind a record to an exact reviewed contract or
recipe hash.
JSON output shapes: ApprovalListReport for list; successful approve skill
output is { "audit": AuditReport, "approval": ApprovalReport }, plus
compatibility when the skill declares it and binaries[] when it declares
release binaries; agent, source, author, and org mutations emit a bare
ApprovalReport; tool, binary, delivery, and hook grants and revocations emit
ToolApprovalReport, BinaryApprovalReport, DeliveryApprovalReport, and
HookApprovalReport, respectively. Other revocations emit ApprovalReport. If
the skill audit blocks approval, Dalo prints only the blocking AuditReport and
exits non-zero.
After a successful approve skill, the human output names each binary the skill
declares: binary <identity>: ready when it is ready, and otherwise its state
with the command that approves it, for example
binary <identity>: pending_approval (run: dalo approve binary <identity>).
Skill approval never approves a binary; the binary keeps its own approval.
dalo instructions enable <pack-ref> <file|--target agent...>
Render a local pack from local/instructions/<pack>.md, or a source-backed pack
selected as <source>:<pack>, into an instruction file as a managed block. The
target file is created if missing. Enabling the same pack again is idempotent
and refreshes the block. Source-backed packs must be tracked in a clean Git
checkout; Dalo records the exact source commit and declared pack version in the
user lock. Running instructions enable is the explicit activation boundary:
discovering or refreshing a source never activates a new pack automatically.
Repeat --target to resolve one pack to several verified native user files in
one operation. codex maps to $CODEX_HOME/AGENTS.md (default
~/.codex/AGENTS.md) and claude maps to
$CLAUDE_CONFIG_DIR/CLAUDE.md (default ~/.claude/CLAUDE.md). Existing
symlinks are resolved before planning, so aliases of the same physical file are
written once. Targets without a verified mapping fail closed and require an
explicit file.
Examples:
dalo instructions enable team-style ~/.codex/AGENTS.md
dalo instructions enable company:engineering-defaults ~/.claude/CLAUDE.md
dalo instructions enable company:engineering-defaults --target codex --target claude
dalo --dry-run instructions enable team-style ./AGENTS.md
Explicit-file JSON output uses InstructionPackReport. Target-aware output uses
InstructionPackBatchReport with source_id, pack_id, dry_run, and
de-duplicated operations[]; every operation includes logical_targets[], the
effective physical target, action, and an optional warning.
dalo instructions disable <pack-ref> <file|--target agent...>
Remove a pack's managed block from an instruction file and remove its active lock entry.
Examples:
dalo instructions disable team-style ~/.codex/AGENTS.md
dalo instructions disable company:engineering-defaults ~/.claude/CLAUDE.md
dalo instructions disable company:engineering-defaults --target codex --target claude
dalo --json instructions disable team-style ./AGENTS.md
JSON output shape: InstructionPackReport with source_id, pack_id, target,
action, dry_run, and an optional warning when recovery leaves a malformed
target block untouched. Disabling a pack removes its lock entry even when its managed
markers are malformed; the target file is left unchanged and the warning
explains the remaining drift. Mutations abort if the target changed on disk
after it was read. Target updates lock the opened inode and verify both its
content and identity before and after writing, so a file replaced by another
process is left untouched and the command fails safely.
dalo instructions adopt <source:pack> [file]
Keep a manually edited, active team or catalog instruction block as a new local pack. Preview first:
dalo --dry-run instructions adopt company:engineering-defaults ~/.claude/CLAUDE.md
dalo instructions adopt company:engineering-defaults ~/.claude/CLAUDE.md
The file is optional when exactly one target is active for this pack. With
several targets, specify the file to choose which block to keep. Adoption writes
local/instructions/<pack>.md with local version 1, replaces the source-qualified
markers with local markers, and switches that target's lock entry to local.
The edited Markdown and all content outside the block stay unchanged. Other
targets continue following the source pack. Later team updates do not overwrite
the adopted block. Use the local pack ID with instructions enable or disable
after adoption; disabling leaves the local pack file intact.
The source must still be enabled, approved, clean and at the recorded activation commit. Missing, malformed, nested, empty or unedited blocks, existing local packs or local blocks, and redirected local directories block adoption. Content that the pack renderer would alter, such as leading metadata or extra boundary blank lines, also blocks adoption. No existing local file or symlink is overwritten. Concurrent target changes abort the operation. A failed lock write restores the original target and removes the newly created pack when safe; concurrent edits are preserved with recovery details in the error.
Dry-run shows the adopted body and destination without changing files or locks.
The new local pack remains uncommitted in the local Git source: review and
commit it yourself. This command does not commit, push, or change the team
checkout. JSON output is InstructionAdoptReport with source_ref, pack_id,
target, local_path, source_commit, body, and dry_run.
Instruction blocks are rendered copies. Linked skills use symlinks: editing a linked skill edits the underlying source, and agents can read those changes immediately. Use the existing local skill/adopt workflow for skill variants; dirty-source checks on a later sync do not isolate edits from agents.
dalo instructions list
List active instruction packs recorded in lock.toml.
Examples:
dalo instructions list
dalo --json instructions list
JSON output shape: InstructionPackListReport with
active_instruction_packs[] entries.
dalo completions <shell>
Generate shell completions to stdout. Supported shell names are provided by clap_complete, including bash, zsh, and fish. This command generates plain text only; dalo --json completions <shell> exits with a plain-text usage error.
Examples:
dalo completions zsh > _dalo
dalo completions bash > dalo.bash
dalo completions fish > dalo.fish
Release archives include generated completions. This command is also available for Cargo installs and local shell setup.
dalo manpage
Generate the dalo(1) man page to stdout from the same Clap command definition used for --help. This command generates plain text only; dalo --json manpage exits with a plain-text usage error.
Example:
dalo manpage > dalo.1
Release archives include the generated man page. This command is also available for Cargo installs and local documentation setup.
Exit Codes
Dalo uses a small scripting contract:
| Code | Name | Meaning |
|---|---|---|
0 |
success | Command completed. |
1 |
expected failure | User-actionable input/state problem, such as semantic value validation, unknown source, unknown target, unsupported schema, parse error, a failed explicit check, a security-audit block during sync or approve, or adoption destination already existing. |
2 |
usage error | Invalid arguments or flags from Clap. This output is plain text even with --json. |
3 |
unsafe state | Dalo refused to mutate because the state needs human attention, such as a dirty source, active store lock, or malformed instruction block. |
4 |
environment problem | Dependency, path, Git, filesystem, or external command problem. |
Scripts should treat 3 differently from 1: it means Dalo intentionally stopped before touching state that may require review.
JSON Output Shapes
--json prints one JSON value to stdout on success for commands with structured output. manpage and completions generate plain text only and reject --json with a plain-text usage error. Runtime errors are printed to stderr as {"error":{"code":"...","message":"..."}} and keep the same exit code as text output. Path fields serialize as strings. Enum fields serialize as snake_case unless noted. Commands that mutate and support --dry-run include a dry_run boolean in their report.
| Command | Shape | Important fields |
|---|---|---|
init |
InitReport |
store, dry_run, operations[] with action, path, status, optional assistant |
assistant status |
AssistantStatusReport |
store, skill_path, version, nullable installed_version, state, nullable reason, external_paths[], undelivered_targets[], delivered_paths[], nullable next_command |
assistant install |
AssistantInstallReport |
store, skill_path, version, nullable previous_version, action, dry_run, next_command |
target detect |
TargetDetectReport |
targets[] with id, name, support, path, exists, linked |
target link |
TargetLinkReport |
target_id, path, canonical_path, status, created_dir, optional assistant |
target unlink |
TargetUnlinkReport |
target_id, status |
team init |
TeamManifestMutationReport |
path, action, dry_run, optional warnings[], resulting manifest |
team catalog add |
TeamManifestMutationReport |
path, action, catalog_id, dry_run, optional warnings[], resulting manifest |
team catalog skills |
TeamManifestMutationReport |
path, action, catalog_id, dry_run, optional warnings[], resulting manifest |
team catalog version |
TeamManifestMutationReport |
path, action, catalog_id, dry_run, optional warnings[], resulting manifest |
team catalog update |
TeamCatalogUpdateReport |
catalog_id, old_version, old_commit, from_ref, candidate_commit, outcomes[], audits[], optional accepted_risk_reason, blocking_reasons[], dry_run, updated, optional branch, optional pull_request_url, resulting manifest |
team catalog remove |
TeamManifestMutationReport |
path, action, catalog_id, dry_run, optional warnings[], resulting manifest |
team show |
TeamManifestView |
path, manifest |
source add |
SourceAddReport |
source, dry_run, audits[] with one AuditReport per discovered skill, optional inventory_warnings[] (code, path, message) |
source add-catalog |
CatalogAddOutcome |
resulting source, nullable available_skills, dry_run |
source list |
SourceListReport |
sources[], each with existing SourceConfig fields plus provenance |
source priority |
SourcePriorityReport |
source, dry_run |
source namespace <id> [<prefix>] [--clear] |
SourceNamespaceReport |
source, changed, dry_run |
source inspect |
CatalogInspectReport |
source_id, candidates[] (id, slot_name, path, description, compatibility, requires[], selected) |
source select |
CatalogSelectReport |
source_id, changed user references in added[] / removed[], complete resulting selected[], dry_run, audits[] for skills named by the operation, migration_warnings[] for degraded legacy sibling catalogs, and optional removed_binary_paths[] and binary_cleanup_warnings[] after source unselect |
source refresh |
CatalogDrift |
source_id, pinned_commit, upstream_commit, outcomes[], migration_warnings[] for degraded legacy sibling catalogs |
source refresh --advance |
CatalogAdvanceReport |
exact old_lock/new_lock, selections, outcomes[], audits[], sync, blocking_reasons[], dry_run, and advanced |
source remove |
SourceRemoveReport |
source_id, checkout_path, kept_checkout, removed_approvals, removed_catalog_lock, reconciled_links[], deactivated_skills[], deactivated_instruction_packs[], cleanup_warnings[], affected_paths[] (including removed staged-binary paths), dry_run |
agent list |
AgentListReport |
resolution, inventory_warnings[], source_errors[] |
agent show |
AgentShowReport |
agent, provider compilations[] |
plan |
InstallationPlan |
schema_version, store, canonical_plugins, inventory_warnings[], tools[], hooks[], optional native_plugins[], physical destinations[] with per-target plugin/component explanations |
plugin list |
PluginListReport |
candidates[], canonical resolution |
plugin show |
PluginShowReport |
candidate, optional selected state |
plugin validate |
PackageValidationReport |
schema_version, profile, package contract checks, reference resolution, provider hook capabilities, execution authorization, diagnostics[] |
plugin select / unselect / decline |
PluginMutationReport |
plugin, action, changed, dry_run |
plugin review |
PluginReviewReport |
schema_version, root_plugin, plugin_closure[], installation_plan, separately scoped decisions[], review_token, interactive_approvals, read_only |
tool list |
ToolListReport |
tools[] with exact trust/runtime/staging state, warnings[] |
tool show |
ToolStatusReport |
tool descriptor, package and source provenance, approval_value, state, optional staged_path, diagnostic |
tool audit |
ToolAuditReport |
tool, contract_hash, plugin_package_hash, passed, findings[] |
hook list |
HookListReport |
hooks[] with hook and referenced-tool states, warnings[] |
hook show |
HookStatusReport |
hook and tool contracts, package and source provenance, approval_value, tool_state, state, diagnostic |
binary list |
BinaryListReport |
binaries[] with declaration, owning skill, approval_value, host_platform, state, optional staged_path, diagnostic; warnings[] (invalid_binary_declaration) |
binary show |
BinaryStatusReport |
declaration, owning skill and source provenance, approval_value, host_platform, state, optional staged_path, optional exposed_path, optional slot_owner (blocked only), diagnostic |
autosync install / uninstall |
AutosyncMutationReport |
action, dry_run, resulting status |
autosync status |
AutosyncStatusReport |
configured, installed, enabled, backend, schedule, executable, store, artifacts, optional scheduler_error, optional disabled_reason, and optional last_run |
autosync run |
SyncReport or AutosyncRunState |
SyncReport when synchronization starts; AutosyncRunState with outcome: "skipped" and reason when another process holds the store lock. Catalog-drift and blocked failures keep the JSON sync report on stdout and emit the standard JSON error on stderr. |
status |
StatusReport |
store, assistant, sources[] with skill_count, agent_count, and provenance, targets[], inventory_warnings[], agent_inventory_warnings[], resolution, dry-run materialization[], blocking_audits[], audit_failures[], lock, unmanaged_skills[], target_warnings[], instruction_packs[], instruction_pack_overlaps[], instruction_block_drifts[], autosync |
sync |
SyncReport |
store, optional assistant, dry_run, linked_targets, skill operations[], optional instruction_operations[] (source_id, pack_id, target, action, previous_commit, commit), resolution, degraded_sources[] (id, path, reason), optional inventory_warnings[] (code, path, message), optional missing_commands[] (source_ref, command, optional compatibility), optional unrefreshed_tracking_sources[], unselected_catalogs[] (source_id, available_skills) |
audit |
AuditReport |
schema_version, source_ref, skill_path, content_hash, static_engine_version, scanned_at_unix, coverage, status, optional max_severity, static_findings[], optional spec_findings[], optional binaries[] (identity, repo, tag, platforms[], contract_hash), optional agent_review, optional risk_acceptance |
approve list |
ApprovalListReport |
schema_version, approvals[] (optional granted_at_unix), accepted_risks[] (source_ref, content_hash, reason, accepted_at_unix, scope_hash, active, audit_command) |
approve skill |
audited approval outcome | audit (AuditReport), approval (ApprovalReport), optional compatibility, optional binaries[] (BinaryStatusReport, omitted when the skill declares none) |
approve agent / source / author / org |
ApprovalReport |
scope, value, action, dry_run |
approve tool / approve revoke tool |
ToolApprovalReport |
tool, content-bound approval_value, action, optional immutable staged_path, dry_run |
approve binary / approve revoke binary |
BinaryApprovalReport |
binary (identity), content-bound approval_value, action (planned, granted, unchanged, or revoked), optional staged_path and exposed_path, dry_run; a revocation adds removed_paths[] and cleanup_warnings[] |
approve delivery / approve revoke delivery |
DeliveryApprovalReport |
skill, revision- and recipe-bound approval_value, optional generator and generator_contract_hash, providers, action, dry_run, execution (not_run during approval) |
approve hook / approve revoke hook |
HookApprovalReport |
hook, content-bound approval_value, action, dry_run |
approve revoke skill / agent / source / author / org |
ApprovalReport |
scope, value, action, dry_run |
adopt / resolve adopt |
audited adoption outcome | audit (AuditReport), adoption (AdoptReport) |
resolve list |
ResolveListReport |
unmanaged_skills[], target_warnings[], owned_skills[] |
resolve keep |
KeepReport |
skill, existing, dry_run |
resolve unkeep |
UnkeepReport |
selector, removed[], dry_run |
resolve remove-owned |
RemoveOwnedReport |
id, link_path, status |
doctor |
DoctorReport |
store, findings[], summary |
instructions enable / disable with explicit file |
InstructionPackReport |
source_id, pack_id, target, action, dry_run, optional warning |
instructions enable / disable with logical targets |
InstructionPackBatchReport |
source_id, pack_id, dry_run, de-duplicated operations[] with logical_targets[], effective target, action, optional warning |
instructions adopt |
InstructionAdoptReport |
source_ref, pack_id, target, local_path, source_commit, adopted body, dry_run |
instructions list |
InstructionPackListReport |
active_instruction_packs[] with pack_id, target, optional logical_targets[], source_id, optional commit, optional version |
Each AuditReport.static_findings[] entry contains id, severity,
category, path, optional line, message, and optional bounded evidence.
AuditReport.spec_findings[] entries have the same shape.
When present, risk_acceptance contains reason, accepted_at_unix, and
scope_hash; agent_review identifies the provider and isolation boundary and
includes its findings, summary, expected capabilities/actions, and undeclared
behaviors. source add and source select expose security preflight results in
their top-level audits[] arrays. source add-catalog returns the resulting
CatalogAddOutcome: adding a pinned catalog does not audit anything until a
skill is selected.
Each StatusReport.audit_failures[] entry contains source_ref, source_id,
and the technical reason. The failed skill is omitted from the active
materialization plan, while the owning source is treated as degraded so an
existing owned link is not removed solely because the audit was incomplete.
Every ResolvedSkill in a resolution object (status, sync, install,
plan) carries an optional compatibility string copied from the skill's
frontmatter.
Common status values:
| Field | Values |
|---|---|
TargetSupport |
supported, experimental |
TargetLinkStatus |
planned, linked, updated, existing |
TargetUnlinkStatus |
planned, unlinked, missing |
MaterializeOperationKind |
create, relink, remove, drop_record, conflict, keep, no_op |
MaterializeOperationStatus |
planned, applied, existing, blocked |
AdoptCopyStatus |
planned, copied, existing |
AdoptReplacementStatus |
planned, replaced, skipped, protected |
RemoveOwnedStatus |
planned, removed, dropped_missing, blocked_real_entry, dropped_foreign_symlink |
InstructionBlockDriftKind |
missing, malformed, stale, source_missing |
CatalogDrift.code |
new_available, selected_changed, selected_moved, selected_removed |
AutosyncRunOutcome |
running, succeeded, skipped, blocked |
TargetScanWarningCode |
unreadable_target_dir |
DoctorFinding uses:
{
"severity": "warning",
"code": "pending_approval",
"message": "human-readable diagnostic",
"next_command": "optional next command"
}
Doctor severities are error, warning, info, and ok.
SourceProvenance contains management (direct or team_manifest), optional
declared_by, credential-redacted origin_url, optional requested_ref, the
canonical resolved_commit, and the observed checkout_commit. For catalogs,
the resolved commit comes from source-lock.toml; a differing checkout commit
is preserved in output so drift remains visible.
Resolution diagnostics use these codes when present in status.resolution.diagnostics: pending_approval, local_override, shadowed, required_expanded, cross_source_require, required_blocked, legacy_bare_approval, audit_failed, blocked_winner_alternate_available, and undeclared_project_skill. Each JSON entry has code, a human-readable message, and optional source_ref. blocked_winner_alternate_available is advisory: its source_ref identifies the approved alternate, while required_blocked identifies the blocked winner and remains the check-blocking diagnostic. undeclared_project_skill appears only for a project store: it names a skill outside the declaration's selectors and their required closure, which is held back and makes --check fail. For recovery steps, see Troubleshooting and FAQ.
Store Layout
After dalo init, the store contains:
| Path | Purpose |
|---|---|
config.toml |
User-authored config: settings and source list. |
lock.toml |
Resolved user lock written by sync and instruction commands. |
state.toml |
Internal target/materialization/protection state. |
approvals.toml |
Local approval records. |
source-lock.toml |
Catalog source pins, selections, and inventory snapshots. |
catalog-advance.toml |
Durable recovery record for an interrupted catalog advance; consumed during recovery. |
.catalog.lock |
Catalog coordination lock while catalog operations run. |
autosync.toml |
Installed scheduler backend, schedule, exact paths, identifier, and artifacts. |
autosync-run.toml |
Last attempted/successful scheduled run and its durable outcome/reason. |
autosync.log, autosync-error.log |
Native scheduler stdout and stderr. |
audits/<content-hash>-<source-ref-hash>.json |
Source- and content-bound deterministic and optional agent security reports. |
.lock |
Temporary coarse lock file while mutating commands run. |
local/skills/ |
Local private skill directories. |
local/agents/ |
Local portable canonical agent packages. |
local/instructions/ |
Local instruction pack Markdown files. |
tools/ |
Immutable, approved tool closures, addressed by their exact staged content. |
generated/ |
Content-addressed generated-delivery cache; only approved derivations are promoted. |
sources/<id>/checkout/ |
Team and catalog Git checkouts. |
sources/.audit-staging/ |
Detached incoming team commits retained only while security review is required. |
The bundled assistant is prepared automatically or explicitly. Hook, plugin,
and binary paths are created lazily, not by dalo init:
| Path | Created when |
|---|---|
local/skills/dalo/, including .dalo-bundle.toml |
Automatic setup or assistant install prepares the embedded skill and its versioned receipt. |
assistant-links.toml |
Schema version 1 records canonical owned companion link paths in links[]. Only the Dalo skill is delivered; these folders are not registered as general targets. |
.assistant-installing/ |
An assistant installation stages new/ and temporarily preserves previous/; retained if recovery is needed. |
hooks/, hooks/state.json |
The first native hook projection is applied; the state file records dispatcher ownership. |
plugins/, plugins/state.json |
The first native plugin projection is applied; the state file records projection ownership. |
binaries/<sha256>/<id> |
Created by the first dalo approve binary for that digest: the verified asset, read-only, addressed by its pinned SHA-256. Later approvals of the same bytes reuse it. Removed once no approved declaration references the digest (approve revoke binary, source unselect, source remove). |
bin/<id> |
Created by dalo approve binary: a relative symlink to the verified file, the stable path launchers look for. Removed with the last digest it points at, or when no approved declaration owns <id>. A real file or foreign link at that path is never removed. |
Provider plugin and hook projections are experimental: the native files
Dalo writes under plugins/ and hooks/, and the provider mappings behind
them, track upstream harness formats and may change in any release. The store
layout itself is internal and is not covered by the stability promise; read it
through dalo commands rather than directly. See
Compatibility and stability.
Dalo rejects unsupported schema versions in persisted TOML files.
Bundled assistant receipt
local/skills/dalo/.dalo-bundle.toml has schema_version = 1, a dalo_version,
and an entries map keyed by relative path. Each entry records its kind
(file or directory), a file's executable flag, and its sha256 content
hash. Directory entries have executable = false and an empty hash. The receipt
itself is excluded from the map. Before replacing a recorded bundle, Dalo checks
the complete tree, including added files, empty directories, and file executable
bits. Symlinks and special files block replacement. The receipt records update
ownership; it is not a signature or an approval for third-party content.
An interrupted installation leaves .assistant-installing/ outside source
discovery. Further assistant installs stop until it is recovered. Preserve and
inspect new/, previous/, and the current local/skills/dalo before moving
anything. If the local slot is absent and previous/ contains the old bundle,
restore that whole directory into the empty slot. If a current bundle already
occupies the slot, do not overwrite it; compare and preserve both copies. After
recovering the intended bundle, move the remaining transaction directory to a
backup outside the store, then retry assistant install --dry-run. Do not clear
a transaction merely because a new command reported it.
Accepted 0.x Store Shapes
A store written by an older release keeps working. These are the shapes Dalo still accepts on read, what it does with each, and where you can observe it. None of them are CLI spellings; every deprecated flag and command spelling was removed before 1.0 (see Troubleshooting and FAQ).
| Older shape | What Dalo does | Where you see it |
|---|---|---|
| A skill approval that names only the skill, without its source | Rejects it as ambiguous across sources and keeps the skill pending | legacy_bare_approval resolution diagnostic, with the exact dalo approve skill <source-id>:<skill> to re-grant |
state.toml protected_skills[] entries recorded as target paths |
Rewrites them to target_id plus slot_name on the next write |
dalo resolve list and doctor, which report the protected slot by name |
A source-lock.toml written before the current schema version |
Rehashes the catalog inventory in memory and writes the current schema on the next selection or advance | migration_warnings[] on source select and source refresh, in both human output and JSON, for a sibling catalog that could not be migrated |
A team manifest [[catalog]] with skills = ["name"] bare entries |
Treats each bare name as an include, identical to +name |
The selection of the derived catalog source, via dalo source inspect <team>.<catalog> |
| An instruction managed block that still carries pack metadata | Re-renders it without the metadata during the next pack refresh, and only when the block still matches Dalo's exact older rendering | dalo sync, which reports the refreshed pack; an externally edited block still fails closed |
Dalo never migrates a shape it cannot recognize byte for byte. Anything ambiguous is reported as blocked instead of rewritten.
Because each rewrite happens on the next write of that file, a store can hold
several of these shapes at once. dalo doctor prints one
schema_migration_pending line per migration still outstanding, and a
legacy_approval_record warning carrying the exact command for the one shape
that needs a decision. See
Upgrade and downgrade.
config.toml
Schema version: version = 2. A version = 1 file is read and migrated
forward on the next write.
Example:
version = 2
[settings]
autosync = false
sync_interval = "hourly"
[[sources]]
id = "local"
kind = "local"
path = "/Users/alex/.dalo/local"
priority = 0
enabled = true
trusted = true
[[sources]]
id = "team"
kind = "team"
path = "/Users/alex/.dalo/sources/team/checkout"
priority = 10
enabled = true
trusted = true
url = "git@github.com:example/team-skills.git"
update_policy = "track"
[[sources]]
id = "public"
kind = "catalog"
path = "/Users/alex/.dalo/sources/public/checkout"
priority = 20
enabled = true
trusted = true
url = "https://github.com/example/catalog.git"
update_policy = "pin"
selection = ["review-helper"]
Fields:
| Field | Meaning |
|---|---|
settings.autosync |
Whether dalo autosync install has configured a scheduler job. |
settings.sync_interval |
Installed hourly, daily, or weekly schedule. |
sources[].id |
Stable source ID. |
sources[].kind |
local, team, or catalog. |
sources[].path |
Local filesystem path for the source root or checkout. |
sources[].subpath |
Optional directory inside a team checkout used as the inventory root. Must remain inside the checkout. |
sources[].priority |
Lower numbers win. |
sources[].namespace |
Optional prefix applied to every materialized skill from the source. A skill named review becomes prefix__review; the source content and source-qualified approval identity stay unchanged. |
sources[].enabled |
Disabled sources are skipped by resolution. |
sources[].trusted |
Trusted sources are approved automatically. User-added catalog sources always start untrusted. In a project store, install sets it from the declaration's approval mode. |
sources[].url |
Git URL for team/catalog sources. URLs with embedded credentials are rejected; use SSH or a credential helper. |
sources[].branch |
Optional requested Git ref for team/direct pinned sources or the branch of a generated tracking catalog. |
sources[].update_policy |
Usually track for team sources and pin for direct catalogs. Generated manifest catalogs use manifest for pins or manifest-track for explicit branch tracking. |
sources[].selection |
Persisted catalog selections by stable ID, slot name, or catalog-relative path. Source-qualified command input is normalized before storage. Empty for local/team sources. |
sources[].declared_by |
Team source whose dalo.toml owns this derived catalog. Generated by sync; do not edit directly. |
sources[].declared_ref |
Git version requested by the declaring team manifest. Generated by sync. |
Unknown fields are rejected.
Team repository dalo.toml
Schema version: schema_version = 1, 2, or 3. Version 2 or later is
required when a catalog has path; version 3 adds explicit branch tracking.
Versions 1 and 2 retain their existing meaning.
Team repositories may compose their checked-in skills with pinned external
catalogs. sync namespaces ordinary IDs as <team-id>.<catalog-id> and stores
the resolved commit in source-lock.toml. If either component itself contains
a dot, Dalo losslessly encodes both components into a reserved point-free
team-<hex>-catalog-<hex> ID so different declarations cannot collapse onto
the same source.
schema_version = 1
[source]
id = "company"
name = "Company Skills"
kind = "team"
[[catalog]]
id = "marketing"
url = "https://github.com/coreyhaines31/marketingskills.git"
version = "0123456789abcdef0123456789abcdef01234567"
skills = ["+copywriting", "+launch", "+seo-audit", "-seo-audit"]
priority = 11
namespace = "marketing"
Catalog fields:
| Field | Meaning |
|---|---|
id |
ID local to the manifest. The local source ID is namespaced with the team source. |
url |
Git URL. Embedded credentials are rejected. |
version |
Required Git commit, tag, or ref. ref is accepted as an alias. Immutable commits are recommended. |
update |
pin (default) or track (requires schema version 3). update_policy is accepted as a compatibility alias. Tracking interprets version as a short branch name, fetches it on every real sync, and accepts fast-forwards only. Cannot be combined with path. |
path |
Optional repository-relative subdirectory containing the selected skills. Requires schema version 2 and a full lowercase 40- or 64-character commit ID. Dalo acquires only this directory with a shallow, blob-filtered sparse checkout. |
skills |
Include/exclude filters. Omitted or empty means all. |
priority |
Optional global resolver priority; defaults to the team source priority plus one. |
namespace |
Optional prefix applied to every materialized skill from this catalog. |
Filter evaluation is set-based and independent of list order:
- no filters: all catalog skills
- only
-skill: all except the exclusions - any
+skillor bareskill: whitelist mode - exclusions always win over inclusions
Unknown or ambiguous filter references block sync. team catalog add rejects
missing or non-Git local paths before writing the manifest, warns for absolute
paths because they are not portable to another checkout, and defers remote
access checks to sync so team authoring remains usable offline. Manifest-derived catalogs
are untrusted by default, so their newly selected skills remain pending until a
local approval matches. source select, source priority, source remove, and
pin advancement reject derived catalogs; edit and review dalo.toml instead.
Changing a catalog URL uses an explicit two-sync replacement: remove the
declaration and sync, then add the reviewed replacement URL and sync again.
Adding or changing path replaces a clean managed checkout after auditing the
new one. Local tracked changes, untracked files, and ignored files block the
replacement. Removing path requires removing the catalog declaration and
syncing, then adding it again without path and syncing a second time. A dry
run of sync cannot preview a scoped checkout that has not yet been acquired.
Real sync reports expose manifest_catalogs[] with source_id, update_policy,
requested_ref, old_commit, commit, and upstream_checked. Dry-run reports
only existing local pins and sets upstream_checked = false. A failed branch
fetch or validation aborts reconciliation and preserves previous catalog state.
To disable tracking, run team catalog version <id> <exact-commit> without
--track. Add --track with a branch to opt an existing catalog in.
dalo-project.toml
Schema version: schema_version = 1, schema_version = 2, or
schema_version = 3.
The committed project declaration read by dalo install and
edited by the dalo project commands. init writes schema version 1. Schema
version 2 adds the optional approval field. Schema version 3 adds an optional
source path for a repository-relative skill directory; Dalo versions without
schema version 3 support reject that declaration, so every teammate and
automation needs a supporting version before a project opts in.
schema_version = 3
approval = "declaration"
targets = ["claude", "codex"]
[[source]]
id = "team"
url = "https://github.com/example/team-skills.git"
commit = "0123456789abcdef0123456789abcdef01234567"
path = "skills"
skills = ["review", "documentation"]
Fields:
| Field | Meaning |
|---|---|
schema_version |
1, 2, or 3. Other values are rejected. |
approval |
Schema version 2 or 3 only. "local" (default) keeps per-store approvals in .dalo/approvals.toml. "declaration" approves every explicitly selected skill and its required closure for the project store; audits still block. Any other value, or the field in schema version 1, is rejected. |
targets |
Non-empty list of claude, codex, opencode, hermes, or openclaw, each with a distinct project folder. |
source[].id |
Source ID unique in the project; local is reserved. |
source[].url |
Git URL or a project-relative local repository path. Embedded credentials are rejected. |
source[].commit |
Full lowercase Git commit ID. Branches and tags are resolved by project add and project update, not stored. |
source[].path |
Schema version 3 only. Repository-relative directory that contains the source skills. "." and "/" explicitly select the repository root. If omitted, Dalo infers the shared parent of tracked SKILL.md files outside dot-folders. When set to a directory, skill paths in skills are relative to it; existing repository-relative paths remain accepted. |
source[].skills |
Non-empty explicit selectors: stable ID, catalog name, or skill path relative to source[].path when set. |
Unknown fields are rejected. project add --path records the scope and moves
the declaration to schema version 3. project add without --path,
project update, and project remove preserve the existing schema version,
the approval field, comments, and formatting.
In both approval modes, a project store delivers only the declared selectors
and their required closure. A plugin selection in a source's own dalo.toml
([selection]) is ignored in project scope and projects nothing; any other
skill outside the declared closure is held back with an
undeclared_project_skill diagnostic. Source trust in a project store approves
skills only, never instruction packs, agents, tools, hooks, or generated
deliveries. See
Project installations for the approval modes and
the migration path.
approvals.toml
Schema version: schema_version = 1.
Example:
schema_version = 1
[[approvals]]
scope = "source"
value = "team"
[[approvals]]
scope = "skill"
value = "team:review-helper"
[[approvals]]
scope = "author"
value = "team:platform-team"
Approval scopes:
| Scope | Value | Matches |
|---|---|---|
skill |
<source-id>:<slot> or <source-id>:<stable-id> |
One skill from one source. Bare slot names and bare stable IDs do not match. |
agent |
<source-id>:<name> or <source-id>:<stable-id> |
One canonical agent package from one source. |
tool |
<source-id>:<plugin>#tool:<name>@sha256:<contract-hash> |
One exact plugin-local executable contract. Approval also requires its immutable staged closure. |
delivery |
<source-id>:<slot>@id:<source-id>:<stable-id>@<commit>@sha256:<recipe-hash> |
One exact generated-delivery recipe at one source revision. Both recorded identities remain valid for revocation. |
hook |
<source-id>:<plugin>#hook:<name>@sha256:<contract-hash> |
One exact plugin-local hook contract. The referenced tool must be independently ready. |
source |
<source-id> |
Every skill from that source. |
author |
<source-id>:<owner> |
Skills from that source whose owners frontmatter contains that owner. |
org |
<source-id>:<owner> |
Same matching behavior as author; the scope is a policy label. |
Local skills and skills from trusted = true sources are approved automatically. Non-interactive commands can use existing approvals but never create new approvals. In a project whose dalo-project.toml sets approval = "declaration", install marks the declared sources trusted and leaves this file unchanged; its records apply again after a switch back to approval = "local".
Prefer dalo approve for all approval changes. The TOML format remains
documented for auditability and recovery, but does not need to be edited for
normal approval workflows.
lock.toml
Schema version: schema_version = 6.
This file is Dalo's resolved user lock. sync rewrites source snapshots, active skills, pending approvals, unlinked skills, and target materialization summaries. Instruction commands preserve and update active instruction-pack entries.
Top-level fields:
| Field | Meaning |
|---|---|
sources[] |
Source ID, kind, path, optional subpath, and optional commit. |
active_skills[] |
Skills that should be linked into targets. |
pending_approval_skills[] |
Skills blocked by approval. |
unlinked_skills[] |
Managed skills not linked, with a reason such as shadowing. |
target_materializations[] |
Last sync operations by target path. |
active_instruction_packs[] |
Instruction packs rendered into instruction files. |
binaries[] |
Release binaries staged and exposed at the last sync, one per binary in state ready. Omitted when empty. |
Important record fields:
| Record | Fields |
|---|---|
LockedSource |
id, kind, path, optional subpath, optional commit |
LockedSkill |
source_ref, slot_name, optional id, source_id, source_kind, optional delivery provenance/recipe/derivation/output fingerprints, optional reason |
LockedTargetMaterialization |
link_path, optional desired_path, kind, status, optional reason |
LockedInstructionPack |
pack_id, target, optional logical_targets[], source_id, optional commit, optional version |
LockedBinary |
source_ref, contract_hash, platform, digest, staged_path, exposed_path |
binaries[] is additive, so the schema version stays at 6. Dalo builds that
predate the field refuse a lock that contains it, as described in
Downgrade; the list is written only when a binary
is ready, so a lock without staged release binaries is unchanged. Every real
sync rewrites the list, and so does source remove in the same commit.
approve binary, approve revoke binary, and source unselect change the
staged files at once, and the list catches up at the next sync.
state.toml
Schema version: schema_version = 1.
This is internal state. Users normally inspect it through target detect, status, sync, and resolve list.
Top-level fields:
| Field | Meaning |
|---|---|
targets[] |
Logical target links with id, path, canonical_path, and enabled. |
materialization_dirs[] |
Canonical physical directories and the logical target IDs sharing each directory. |
owned_skills[] |
Symlinks Dalo owns: target_id, slot_name, link_path, store_path, plus additive delivery mode/provider/fingerprint/derivation provenance. |
protected_skills[] |
Unmanaged target slots kept by the user: target_id, slot_name. Legacy path-based entries migrate on read. |
Unknown fields in this internal state model are retained across reads and writes for downgrade safety after additive changes. Breaking changes still require a schema-version bump. User-authored configuration remains strict.
source-lock.toml
Schema version: schema_version = 3.
This file stores catalog pins and inventory snapshots. It is written by catalog selection and read by drift checks. sync and doctor treat a directly-added catalog checkout whose HEAD differs from this pin as degraded: they preserve recorded owned links rather than resolving drifted content. Restore the checkout to its pinned commit, then use dalo source refresh <id> --advance only for a reviewed update.
Top-level fields:
| Field | Meaning |
|---|---|
catalogs[] |
One CatalogLock per pinned catalog source. |
catalogs[].source_id |
Catalog source ID. |
catalogs[].commit |
Pinned commit used for the inventory snapshot. |
catalogs[].selected[] |
Selected skill references. |
catalogs[].inventory[] |
Pinned catalog entries. |
Inventory entry fields:
| Field | Meaning |
|---|---|
id |
Optional stable skill ID from frontmatter. |
slot_name |
Install slot name. |
path |
Skill directory path relative to the catalog root. |
content_hash |
Hash over skill directory content, executable file bits, and symlink metadata. |
metadata_hash |
Hash over parsed skill metadata. |
requires[] |
Declared same-source dependencies. |
SKILL.md Frontmatter
Dalo discovers a skill by finding a directory containing SKILL.md. If the file starts with YAML frontmatter fenced by --- lines, Dalo reads these fields:
---
id: review-helper
name: review-helper
description: Review pull requests for behavior regressions
owners:
- platform-team
tags:
- review
requires:
- base-style
compatibility: "Rendered-page scans need agent-browser on PATH; everything else works without it."
metadata:
dalo.requires-commands: "agent-browser"
binaries:
impeccino:
source: github-release
repo: sebastian-software/impeccino
tag: engine-v0.2.0
availability: required
assets:
macos-arm64:
asset: impeccino-darwin-arm64
sha256: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
linux-x64:
asset: impeccino-linux-x64
sha256: "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
---
# Review Helper
| Field | Required | Meaning |
|---|---|---|
id |
no | Stable skill identity. Use for catalog selections and source-qualified approvals. |
name |
no | Preferred slot name. Must be a safe slot name; otherwise Dalo falls back to the folder name and records an inventory warning. |
description |
no | Human-readable description shown in catalog inspection. |
owners[] |
no | Approval owner strings matched by author and org approvals. |
tags[] |
no | User metadata. |
requires[] |
no | Same-source or same-catalog dependencies. Required skills are expanded only when the closure is linkable and approved. |
compatibility |
no | Free-text environment requirements from the Agent Skills specification (at most 500 characters). Shown unchanged by source inspect, status, sync, approve skill, and plugin review so the person approving a skill sees what it needs from the machine. |
metadata |
no | String-to-string mapping, the specification's extension point. Dalo carries string-valued entries; non-string entries are ignored. |
binaries |
no | Verified release binaries the skill needs, keyed by id. Dalo validates each declaration, shows its state with dalo binary list and dalo binary show, and downloads, verifies, stages, and exposes the host asset only through dalo approve binary. |
Binary declarations. binaries maps each binary id to one declaration. The
id is the mapping key: lower kebab-case, unique (a duplicate key is a YAML
error), so the identity is <source>:<skill>#binary:<id>, where <source>:<skill>
is the skill's source reference. binaries: {} declares no binaries, and a value
that is not a mapping is invalid. Each declaration takes source (required,
exactly github-release); repo (required, <owner>/<name>: two segments of 1
to 100 characters from letters, digits, ., _, and -, neither starting with
.); tag (required, 1 to 128 characters from letters, digits, ., _, /,
and -, not starting with -, ., or /, not ending with /, and containing
neither .. nor //); availability (optional, required or optional,
default required); and assets (required, a non-empty mapping keyed by
macos-arm64, macos-x64, linux-arm64, or linux-x64). Each asset requires
asset (1 to 255 characters from letters, digits, ., _, and -, not
starting with ., not containing ..) and sha256 (exactly 64 lowercase
hexadecimal characters). Unknown keys are invalid at every level. Dalo derives
each download URL as https://github.com/<repo>/releases/download/<tag>/<asset>.
The contract hash covers the id, source, repo, tag, availability, and each
asset's platform, file name, and digest, so a description edit does not change
it. The approval value is <identity>@sha256:<contract-hash>.
A declaration that breaks any rule drops its skill from the inventory and
reports one invalid_binary_declaration warning naming the binary id and rule,
so the skill does not activate. Dalo releases that predate this field ignore
binaries and activate the skill without the binary, so upgrade before relying
on a declaration. A YAML error inside binaries makes the whole
frontmatter malformed, as any other frontmatter error does.
Reading a declaration never touches the network. dalo approve binary <identity>
is the only command that downloads one. It fetches the host platform's asset
from https://github.com/<repo>/releases/download/<tag>/<asset>, verifies the
bytes against the pinned digest, stages them read-only under
binaries/<sha256>/<id>, links them at <store>/bin/<id>, and then records the
exact approval. Assets for other platforms are never fetched.
dalo approve revoke binary <identity> removes only the approval.
A skill launcher should look for the verified file first and fall back to its own download on hosts without Dalo:
#!/bin/sh
candidate="${DALO_STORE:-$HOME/.dalo}/bin/impeccino"
if [ -x "$candidate" ]; then
exec "$candidate" "$@"
fi
exec "$(dirname "$0")/impeccino-fallback" "$@"
The lookup contract is ${DALO_STORE:-$HOME/.dalo}/bin/<id>. The path stays the
same when a digest changes, so launchers never need to know the digest.
If name is absent, the directory name is the slot name. Duplicate slot names within one source are warned and de-duplicated by resolver behavior.
Dalo reads one metadata key as a command requirement: dalo.requires-commands,
a space-separated list of command names such as agent-browser in the example
above. Each name must be 1 to 128 characters from [A-Za-z0-9._+-] and must not
start with - or .; other tokens are skipped, and repeated names count once.
Dalo checks each name with a file lookup on PATH and never runs it, so version
checks are out of scope. A missing command is a doctor warning
(skill_command_missing) and one line in the note after sync and install.
The skill's compatibility text is shown as the install hint. The check never
blocks a skill.
SKILL.md may reference another file inside the same source checkout, but a
metadata symlink whose resolved target escapes the checkout is skipped and
reported as skipped_symlink. This keeps skill identity and approval metadata
contained within the source being scanned.
PLUGIN.toml Portable Plugins, Tools, and Hooks
For a worked walkthrough of authoring, selecting, reviewing, and approving a package, see the plugins guide; this section is the field-level contract.
The PLUGIN.toml file format Dalo reads is stable within a major version. The
cross-implementation Portable Agent Packages specification
built on it is an experimental draft, and so is any claim that another tool
interprets the same file identically. See
Compatibility and stability.
Plugins are exact plugins/<name>/PLUGIN.toml packages. The top-level schema is
closed: unknown fields are rejected. schema_version = 1 and [plugin] with
name and description are required; id, version, providers,
[[plugin.members]], [[plugin.requires]], [[tool]], and [[hook]] are
optional.
schema_version = 1
[plugin]
name = "review-suite"
description = "Review helpers"
[[plugin.members]]
ref = "skill:review"
requirement = "required"
[[tool]]
schema_version = 1
id = "inspect"
entry = "bin/inspect"
runtime = "executable"
argv = []
cwd = "tool_root"
availability = "required"
[[hook]]
schema_version = 1
id = "before-shell"
tool = "inspect"
subject = "tool_call"
phase = "before"
effect = "allow_deny"
requirement = "required"
timeout_ms = 2000
failure_policy = "fail_closed"
retry = "never"
error_visibility = "model_and_user"
blocking_scope = "matched_event"
Plugin members and dependencies
Plugin members use ref, requirement (required, optional, or
recommended), and optional fallback with required kind and skill.
Members may reference skills, agents, or instructions; recommended is only
valid for instructions. A fallback is only valid for an agent member, has
kind = "inline", names a skill in skill, and that skill must also be a
required member. Dependencies use ref to a plugin with requirement
required or optional.
Tools
Tools require schema_version, id, entry, runtime (executable,
python, node), argv, cwd (tool_root), and availability (required
or optional). Optional fields are runtime_version, platforms (macos,
linux), inputs, files, env, and capabilities (filesystem_read,
filesystem_write, subprocess, or network). Tool inputs are closed name,
type (string, path, integer, boolean), and optional required
(default true) records. Paths must be plugin-root-relative and remain inside
the plugin-owned closure; Dalo stages and hashes that closure before approval.
Hooks
Hooks are closed descriptors. They require schema_version, id, tool,
subject, phase, effect, requirement, timeout_ms, failure_policy,
retry, error_visibility, and blocking_scope; matcher, bindings, and
fallback are optional fields. tool references the same-plugin tool.
subject is session, user_prompt, tool_call, or workflow; phase is
before, after, end, or completion_attempt; effect is observe,
add_context, allow_deny, rewrite_input, replace_output, or
continue_workflow. requirement is
required or optional; failure_policy is fail_open, fail_closed, or
report; retry is only never; error_visibility is user or
model_and_user; and blocking_scope is only matched_event.
matcher.tool_names is an optional unique exact provider-tool-name list and is
valid only when subject = "tool_call".
Bindings are closed input/field records and map a lower-snake tool input to
one admitted event field: session.id, session.cwd,
session.permission_mode, actor.kind, actor.id, transcript.path,
session.end_reason, prompt.text, tool.call_id, tool.name,
workflow.already_continued, or workflow.last_message. Required hooks have
no fallback; optional hooks use the fallback value omit explicitly as
fallback = "omit" when omitted
behavior is intended. The subject/phase/effect combination must have a
verified mapping in at least one supported provider. fail_closed is valid
only for a before pre-action enforcement effect (allow_deny or
rewrite_input) or completion_attempt plus continue_workflow; observe
and replace_output require failure_policy = "report". A binding's field
must be available for the selected subject and phase. IDs are lower kebab-case, input names are lower
snake-case, timeout_ms is 100 through 120000, and each matcher or binding
list holds at most 256 entries. Hooks reference a same-plugin tool and are
independently approved; malformed, unknown, unsafe, or unsupported contracts
are blocked.
DELIVERY.toml Provider Builds
Direct delivery remains the default: without a DELIVERY.toml, Dalo links the
discovered skill directory unchanged to every target.
A logical skill can instead select existing, provider-specific build artifacts from the same pinned source checkout:
schema_version = 1
kind = "prebuilt"
universal_fallback = false
[providers]
codex = ".agents/skills/impeccable"
claude = ".claude/skills/impeccable"
opencode = ".opencode/skills/impeccable"
Provider paths are relative to the source checkout. Each artifact must be a
real directory inside that checkout, contain SKILL.md, and contain no
symlinks or special filesystem entries. Dalo fingerprints every artifact,
audits it, and links the matching artifact for each logical target. Artifact
directories referenced by a delivery manifest are not inventoried again as
independent logical skills. The provider ID universal is reserved for the
canonical artifact selected by universal_fallback and cannot be declared in
the providers table.
An omitted provider mapping blocks that target. Set universal_fallback = true
only when the logical skill directory is intentionally valid for every unmapped
provider. When multiple logical targets share one physical target directory,
their selected artifact must be identical; otherwise Dalo reports a conflict
instead of choosing one implicitly.
sync, status, and doctor expose delivery selections in JSON. Human-readable
sync and status output lists prebuilt selections and blocked mappings. The
user lock records the manifest, provider paths, and fingerprints; changing a
provider artifact therefore appears as skill_delivery_changed lock drift.
Audit reports use provider-qualified selectors such as
dalo audit impeccable:impeccable@codex, so findings, risk acceptance, and
persisted provenance stay bound to the exact provider artifact.
A generated delivery requires a stable skill frontmatter id, declares a
same-source plugin tool, and names the relative output directory expected for
each provider:
schema_version = 1
kind = "generated"
generator = "company:builder#tool:build"
output_input = "output_dir"
[providers]
codex = "codex/review"
claude = "claude/review"
The referenced tool must be required, declare filesystem_write, and expose
the named required path input in its argument contract. The delivery
manifest, plugin manifest, and every file in the tool closure must be tracked
by the same clean Git source commit. Dalo binds the recipe fingerprint to that
commit and the exact tool contract. Generated delivery schema v1 requires the
tool runtime to be executable; Python and Node runtime lookup is rejected so
sync never selects an interpreter from its ambient PATH. An executable script
must use an absolute shebang such as #!/bin/sh; /usr/bin/env shebangs are
rejected for the same reason. Generated execution also rejects a declared
PATH environment input and sets PATH to the empty string, so scripts must
not resolve subprocesses through the invoking user's environment.
Generator execution is fail-closed behind an operating-system sandbox inherited by every descendant. The sandbox permits filesystem writes only below the one delivery staging directory. macOS uses the system Seatbelt launcher and denies network operations. Linux requires a fully enforced Landlock ABI v4 domain and denies TCP connection and bind operations. If the required sandbox cannot be fully enforced, Dalo does not run the generator.
This is not a general read-confinement boundary: a generator can read files its OS user can read, including the native runtime files that executable tools need. Linux Landlock network controls do not cover UDP or UNIX-domain sockets. Treat a generated-delivery approval as permission to run the exact staged tool closure within these stated write and network limits, not as permission for arbitrary code or as proof that its inputs are confidential.
Generated delivery has two independent approvals:
dalo approve delivery company:review
dalo approve tool company:builder#tool:build
The first approves only the exact revision-bound recipe; the second approves
the generator tool contract. A new source commit or changed recipe invalidates
the recipe approval. The approval key records both the current slot and the
required stable ID, so stale trust remains revocable after a rename, deletion,
or invalid recipe through either historical identity. Approval itself remains
inert. Once both exact approvals exist, a real sync invokes the immutable
staged tool closure with an empty environment except for explicitly declared
variables. Dalo passes a newly created staging directory as the declared output
input, enforces a bounded runtime and output tree, rejects undeclared paths,
symlinks, multiply linked or special files, oversized output, and
source-checkout changes. Surviving members of the generator process group are
terminated before Dalo copies the validated output into a fresh-inode snapshot.
Dalo audits that snapshot, promotes it, and verifies and audits the immutable
cache path again before it can reach materialization. The source commit and
cleanliness are rechecked after that final cache verification, immediately
before materialized state is persisted, and again immediately before the user
lock commit. Source drift during generation therefore rolls back activation and
prevents provenance from being committed. Blocking findings or a failed
generator leave the last known-good target link unchanged.
Successful output is made read-only and atomically promoted below
generated/sha256/<derivation-hash>. The derivation identity binds the logical
skill, source commit, recipe, and exact tool contract; subsequent syncs verify
and reuse that cache instead of executing again. Only after verification does
the normal transactional materializer link provider outputs. Dry-run, JSON,
status, and doctor expose miss, generated, or hit cache state,
derivation identity, selected output fingerprint, and any blocking remediation.
AGENT.md Canonical Packages
An agent package is an agents/<name>/AGENT.md directory. AGENT.md starts
with YAML frontmatter and then contains the portable Markdown prompt. Required
fields are schema_version: 1, name, and description; model.profile,
targets, and skills express portable intent and requirements.
---
schema_version: 1
name: reviewer
description: Reviews pull requests for behavior regressions
model:
profile: balanced
targets: [claude, codex]
skills: [review-helper]
---
Review behavior before style nits.
targets may omit providers (all compatible providers) or name claude and
codex; skills lists required skill references. Optional id, owners,
tags, tools, filesystem, network, and providers metadata add identity,
boundaries, and provider overlays. Packages are bounded to 256 entries, 16
directory levels, and 16 MiB total; AGENT.md itself is limited to 1 MiB.
Symlinks and unsupported special files are rejected.
Instruction Packs
Instruction packs are Markdown files in local/instructions/<id>.md or
<source>/instructions/<id>.md. Dalo discovers both locations. Bare IDs select
local packs; source packs use an explicit source-qualified reference such as
company:engineering-defaults. Pack IDs use the same safe token rule as source
IDs: letters, digits, ., _, and -, excluding . and ...
Local managed-block markers retain their existing bare pack ID. Source-backed
markers use the full source-qualified reference, allowing same-named packs from
different sources to coexist in one instruction file. Source-backed lock entries
bind the activation to the exact clean Git commit. If that checkout advances,
normal dalo sync refreshes only packs already present in the user lock and
updates their commit and version provenance. Newly discovered packs remain
inactive. Refresh requires the source to remain trusted or source-approved and
the existing managed block to match the previously rendered immutable commit.
Revoked approval, dirty or missing sources, missing Git history, untracked pack
files, malformed markers, and externally edited managed blocks fail closed with
an actionable error instead of overwriting the target. Tracking team sources
advance through normal sync; catalog sources retain their explicit pinned
advancement workflow.
Dalo reads an optional version: entry from the first five lines and optional
topics: or tags: metadata from the first eight lines:
version: 1.0.0
topics: review, formatting
# Team Style
Use concise review comments.
tags: can be used instead of topics:. Topics are comma-separated and are used for advisory overlap warnings when multiple active packs share topics.
Managed blocks use these markers:
<!-- dalo:start team-style -->
...
<!-- dalo:end team-style -->
Dalo only rewrites bytes inside the pack's own managed block. Content outside managed blocks is preserved.
dalo install
Restore the current project from its dalo-project.toml:
dalo install
dalo --project ../service install
dalo --dry-run --json install
install works only in project scope. It creates the project's .dalo/ store
when it is missing, clones the declared sources at their exact commits, and
links approved skills into the project folders of the declared targets. It then
reports like dalo sync --check: pending approvals, unaccepted blocking audit
findings, dirty checkouts, and unmanaged same-name entries make it exit
non-zero instead of being overridden. Rerun it after approving skills or after
pulling a changed declaration; repeated runs keep the declared pins even when
upstream has advanced. JSON output is the SyncReport shape.
The declaration's approval mode decides who approves the
selected skills. With approval = "declaration", install approves the explicit
selection and its required closure without local approval records, so a fresh
clone or worktree installs without pending approvals; audits still block.
Install reconciles each declared source's trusted flag from that mode on
every run, and it never creates approval records. Human output names the mode
on stderr, for example approvals: declaration (dalo-project.toml).
--dry-run validates and previews the declaration without fetching, creating
a store, auditing, or linking. Its JSON object contains scope, project,
store, dry_run, approval (local or declaration), sources,
targets, removals, and note. The removal preview applies the declared
approval mode, so removals.deactivated_skills includes skills that a switch
to local returns to pending.
Outside a project, install fails with exit 1 and names
dalo --project . init, which writes the declaration. --global and --store
select a non-project store and therefore fail the same way. See
Project installations for scope discovery, the definition
format, and the review flow.
dalo project add
Resolve one repository and explicit skill selection into the discovered or
explicit project's dalo-project.toml:
dalo project add company https://github.com/acme/skills.git --ref main --skill review
dalo project add company https://github.com/acme/skills.git --ref main \
--skill review --expect-commit <previewed-commit> --apply
dalo install
The default is a read-only preview. It fetches to a temporary directory, resolves
the requested ref to an exact commit, lists the selected skills and target
folders, and prints the TOML entry and apply command. --apply writes only the
declaration; installation and approval remain separate (local approvals, or
the declaration itself with approval = "declaration"). Applying a
branch or tag requires --expect-commit to match the commit shown in the
preview. A full commit ID can be applied directly. Repeat required --skill
options to select multiple catalog entries. Local repositories must be inside
the project to keep their relative paths portable. JSON reports include
project, source_id, url, requested_ref, commit, skills, targets,
declaration_change, applied, dry_run, and next_command.
With --path skills, --skill react-best-practices writes
skills = ["react-best-practices"]. A nested skill path such as
--skill guides/review is resolved below skills/.
See Project installations for the review and restore workflow.
dalo project update
Review a new pin for an existing project source. The default previews the old and candidate commit, selected inventory changes, dependencies, audits, and project targets without writing files:
dalo project update company --ref main
dalo project update company --ref main --expect-commit <previewed-commit> --apply
dalo install
Applying a branch or tag requires --expect-commit to match the preview. A
full commit ID can be applied directly. Without --skill, Dalo preserves the
current explicit selection by stable ID or path. Repeat --skill to replace
the selection. An implicitly selected skill removed upstream blocks apply; an
explicit replacement selection is required. A candidate with a blocking audit
finding is reported and cannot be applied. --apply changes only the
declaration's commit and skills values; install stages the new checkout and
uses the ordinary approval and transactional delivery flow. With
approval = "declaration", the reviewed update approves the changed content.
Installing a changed pin checks every existing per-skill approval for that source, including dependencies and deselected skills. Changed or removed content loses its approval; unchanged content keeps it. Selecting a skill again does not revive approval for content changed by an earlier pin update.
The JSON ProjectUpdateReport contains project, source_id, url,
requested_ref, previous_commit, commit, selection_before,
selection_after, outcomes, dependency_changes, skills, audits,
targets, blocking_reasons, declaration_change, applied, dry_run, and
next_command.
dalo project remove
Preview removing a source or exact selectors from dalo-project.toml:
dalo project remove company --skill review
dalo project remove company --skill review --apply
dalo project remove company --apply
dalo install
Repeat --skill to remove multiple explicit selectors. Omit it to remove the
whole source; removing the last selector has the same effect. Required skills
remain active while another selected skill needs them. --apply writes only
the declaration; --dry-run suppresses that write. Neither preview nor apply
fetches sources or modifies delivery. Run install to reconcile the change,
including declaration removals pulled from Git.
Installation unregisters absent sources and their pins, revokes their
source-scoped approvals, and removes only verified owned target links. Cached
checkouts, local edits, foreign symlinks, and unmanaged directories are retained.
Deselection alone keeps unchanged approvals. Dirty sources still declared in the
project and unsafe store paths remain blocking. Removal never deletes caches;
preserve local work before any manual cleanup. Retry interrupted or failed
installation with dalo install.
The JSON ProjectRemoveReport contains project, source_id,
selection_before, selection_after, declaration_change, effects,
applied, dry_run, and next_command. effects contains
retained_checkouts[] (source_id, path, dirty), deactivated_skills[],
approvals_to_revoke, link_operations[] (the ordinary materialization operation
shape), and delivery_preview_complete. Effects use local installed pins;
missing or changed declared pins make the preview incomplete. Project install
dry-run JSON exposes the same effects as removals.
See Project removal for dependency, cache, and recovery behavior.
dalo migrate skills-sh
Preview a project migration from a version 1 skills-lock.json. --apply writes a
verified dalo-project.toml and backs up the former installation; --dry-run
suppresses applying. Verification may fetch Git repositories. It never imports
approvals or guesses a Git commit from a foreign content hash.
Use --project <directory> for an exact root, or let Dalo discover the nearest
lock within the Git boundary. Global/store overrides are rejected. --json
reports project, applied, ready, targets, skills (each with name,
commit, paths, and blocked), and backup. Blocked entries return a nonzero
exit code with the report on stdout and the error on stderr.
See Project migration for supported sources, scope, backups, recovery, and the required local approval steps.
dalo promote
Create a review-first contribution from one local skill to an explicitly selected GitHub.com team repository:
dalo --dry-run promote review-helper --target company
dalo promote review-helper --target company
# If you cannot push to the team repository:
dalo promote review-helper --target community --fork
# Explicitly promote changes to this skill from the team's working tree:
dalo promote review-helper --target company --from-dirty
<skill> is a unique slot name or stable skill ID in the built-in local source.
--target names a directly configured Dalo team repository. The destination is
skills/<slot-name> at the repository root. Existing destinations block local
source additions. --from-dirty can update the selected existing team skill (or
add it if the directory is new), but only when the checkout's base commit matches
the current PR base and no unrelated files are changed. Target changes outside
the selected skill, non-GitHub forges, manifest-managed
sources, pinned targets, target subpaths, and skills with nested Git metadata,
symlinks, or special files are blocked.
The dry-run scans and statically audits local content without network access or
persistent writes. An unaccepted blocking finding prevents promotion. Review and
accept a specific audited snapshot with dalo audit <source:skill> --accept-risk <reason> before retrying if that is your decision. A real promote requires an
authenticated GitHub CLI (gh), a Git commit identity, and network access. Dalo
uses a temporary clone, adds only the selected skill, commits it on a fresh
dalo/promote-* branch, pushes that branch, and opens a PR against the target's
configured/default branch. It never commits or pushes to the default branch.
With --fork, Dalo explicitly creates or uses a fork owned by the authenticated
GitHub user and uses it as the PR head. It does not create a fork implicitly.
The PR body includes the source commit, content fingerprint, and deterministic
audit status. Dalo leaves the existing managed checkout and local skill intact;
--from-dirty replaces only the selected skill in the temporary PR branch.
If the branch push succeeds but PR creation fails, the branch remains on the
selected repository for recovery; the error reports its name. JSON returns a
PromoteReport with the selected source, destination, audit summary, branch, and
PR URL when created.
Source: docs/reference.md