Documentation Command reference

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:

  1. --store <PATH>
  2. DALO_STORE
  3. ~/.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.

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.

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:

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:

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