Skip to main content
gaal sync --dry-run runs the full audit and planning pipeline but writes nothing. It’s the safety net you reach for whenever you’re not sure what’s in the pipeline.

The basics

$ gaal sync --dry-run
plan:
  repositories
    + clone   src/example          (git, main)
    ~ update  src/gaal             (git, main main, 2 commits ahead)
    = unchanged src/dataset
  skills
    + install code-review claude-code, cursor
    ~ update  git-helper claude-code (v1.2  v1.3)
    = unchanged refactor claude-code
  mcps
    + upsert  filesystem ~/.config/claude/claude_desktop_config.json
    = unchanged github ~/.config/claude/claude_desktop_config.json
The legend:
SymbolMeaning
+Will be created.
~Will be updated in place.
=Already in the desired state.
-Would be removed (only with --prune).

Exit codes

--dry-run uses the exit code as a status signal so you can drive it from scripts:
CodeMeaning
0Nothing to change. State is fully reconciled.
1Changes are pending. Run gaal sync to apply them.
2Error during planning (config invalid, source unreachable, …).
gaal sync --dry-run && echo "in sync"

Machine-readable output

gaal sync --dry-run -o json
Returns a structured plan suitable for piping into jq or feeding a CI step. The ASCII banner is suppressed automatically when -o json is set.

Combining with other flags

ComboBehaviour
--dry-run --pruneReports what would be removed, removes nothing.
--dry-run --forceReports installs that would happen into agents not currently detected.
--dry-run --sandbox /tmp/sbPlans against the sandboxed filesystem, not your real one.
--dry-run --serviceRejected. A dry-run service loop is meaningless.

CI pattern: fail the build on drift

Run dry-run with set -e in CI to fail when checked-in skills/MCP entries don’t match the committed config:
gaal sync --dry-run -o json | tee plan.json
test "$(jq -r '.changes | length' plan.json)" -eq 0

gaal sync

Pruning

Sync vs. service mode