Advanced plan execution
Go beyond dojops apply. Learn how to preview, resume, replay, and surgically target individual tasks in a multi-step plan.
Difficulty: Intermediate Duration: 30 minutes What you’ll build: A fully executed CI/CD plan with hands-on practice using dry runs, partial failure recovery, deterministic replay, and audit trail verification
What you’ll learn
- Why
--dry-runis a critical safety step before any apply - How plan resumption and retry differ — and when to use each
- What
--replaymode actually does at the provider level - How to target a single task without re-running the whole plan
- How to read and verify the hash-chained audit log
Prerequisites
- DojOps 1.1.6 installed:
npm i -g @dojops/cli - A project initialized:
dojops init - An LLM provider configured:
dojops provider add openai --token sk-...
Workshop steps
Step 1: Create a multi-task plan
Start with a realistic scenario: set up CI/CD for a Node.js app that needs a GitHub Actions workflow, a Dockerfile, and a Docker Compose file.
dojops plan "Set up CI/CD with GitHub Actions, Dockerfile, and docker-compose for a Node.js app"┌ Plan Created
│
│ Plan ID: plan-f7a2b1c3
│ Tasks: 3
│
│ Task 1: Generate GitHub Actions CI workflow
│ → ci-specialist
│ Task 2: Generate multi-stage Dockerfile
│ → docker-specialist
│ Task 3: Generate docker-compose.yml
│ → docker-specialist
│ → depends on Task 2
│
└ Run `dojops apply` to executeThe planner decomposed your goal into three tasks with a dependency relationship: Task 3 depends on Task 2, so it only runs after Task 2 succeeds. Task 1 is independent and can run in parallel with Task 2.
Step 2: Preview with --dry-run
Before writing anything to disk, see exactly what the plan would do:
dojops apply --dry-run┌ Dry Run - plan-f7a2b1c3
│
│ Task 1: github-actions
│ Would create: .github/workflows/ci.yml
│
│ Task 2: dockerfile
│ Would create: Dockerfile
│
│ Task 3: docker-compose
│ Would create: docker-compose.yml
│
│ Summary: 3 files would be created, 0 modified
│
└ No files were written (dry run)Dry run performs the full LLM generation cycle but stops before writing to disk. Use it when working in a shared repo or when you want to inspect generated content before committing. Any existing files that would be overwritten are listed here, with .bak backup creation noted.
Step 3: Execute with approval prompts
Run the plan with the default per-file approval workflow:
dojops apply┌ Executing Plan: plan-f7a2b1c3
│
│ Task 1/3: github-actions
│ Generated: .github/workflows/ci.yml
│
│ ◆ Approve this file? (y/n): y
│ ✓ Written: .github/workflows/ci.yml
│
│ Task 2/3: dockerfile
│ Generated: Dockerfile
│
│ ◆ Approve this file? (y/n): y
│ ✓ Written: Dockerfile
│
│ Task 3/3: docker-compose
│ Generated: docker-compose.yml
│
│ ◆ Approve this file? (y/n): y
│ ✓ Written: docker-compose.yml
│
└ Plan complete - 3/3 tasks succeededThe approval gate shows you each generated file before writing it. Answer n to skip a file while letting the rest of the plan continue.
For CI/CD or scripted environments where you trust the output, bypass the approval prompts:
dojops apply --yesStep 4: Simulate a partial failure and resume
Partial failures happen — network timeouts, LLM rate limits, transient errors mid-plan. If your plan failed partway through (say, Task 2 timed out), run:
dojops apply --resume┌ Resuming Plan: plan-f7a2b1c3
│
│ Task 1/3: github-actions - ✓ already completed (skipped)
│ Task 2/3: dockerfile - resuming...
│ Generated: Dockerfile
│ ✓ Written: Dockerfile
│
│ Task 3/3: docker-compose
│ Generated: docker-compose.yml
│ ✓ Written: docker-compose.yml
│
└ Plan complete - 3/3 tasks succeeded (1 resumed)--resume reads the plan state from .dojops/plans/plan-f7a2b1c3.json and skips tasks that already have a completed status. Task 1 was done, so it’s skipped — no extra LLM call, no file re-written.
For unattended recovery in CI pipelines:
dojops apply --resume --yesStep 5: Retry failed tasks
--resume alone skips failed tasks and continues with unblocked ones. To re-attempt tasks that previously errored, add --retry:
dojops apply --resume --retry┌ Resuming Plan: plan-f7a2b1c3 (with retry)
│
│ Task 1/3: github-actions - ✓ already completed (skipped)
│ Task 2/3: dockerfile - ✗ previously failed - retrying...
│ Generated: Dockerfile
│ ✓ Written: Dockerfile
│
│ Task 3/3: docker-compose
│ Generated: docker-compose.yml
│ ✓ Written: docker-compose.yml
│
└ Plan complete - 3/3 tasks succeeded (1 retried)The distinction matters. --resume without --retry is safe for continuing after an unrelated failure. --resume --retry is for when you’ve fixed the underlying problem (rate limit lifted, timeout extended) and want to re-run what failed.
Step 6: Deterministic replay
Replay mode locks temperature to 0 and validates that your current environment matches what the plan was created with. It’s useful for audits, reproducing output, and verifying nothing has changed in your setup.
dojops apply --replay┌ Replay Mode - plan-f7a2b1c3
│
│ Environment Validation:
│ ✓ Provider: openai (matches plan)
│ ✓ Model: gpt-4o (matches plan)
│ ✓ Skill hashes: all match
│
│ Executing with temperature=0...
│
│ Task 1/3: github-actions ✓
│ Task 2/3: dockerfile ✓
│ Task 3/3: docker-compose ✓
│
└ Replay complete - deterministic executionIf your provider or model has changed since the plan was created, replay warns you before executing:
⚠ Environment mismatch:
Provider changed: openai → anthropic
Skill hash changed: dockerfile (.dops file modified)
Use --force to proceed despite mismatches.Take this warning seriously. A different provider or modified skill will produce different output, which defeats the purpose of replay. If you genuinely want to re-run with the new environment, use a fresh plan instead.
Step 7: Execute a single task
Sometimes you only want to regenerate one file — say, the Dockerfile after changing your base image requirement. Run a single task by its number without touching the others:
dojops apply --task 2┌ Executing Single Task: plan-f7a2b1c3 / Task 2
│
│ Task 2: dockerfile
│ Generated: Dockerfile
│ ✓ Written: Dockerfile
│
└ 1 task completedThe plan state is updated: Task 2 is marked completed with the new timestamp. Tasks 1 and 3 are unchanged. This is the cleanest way to regenerate a single file without touching anything else.
Step 8: Timeouts, force mode, and verification
Set a per-task timeout when working with large files or slow models (default is 60 seconds):
dojops apply --timeout 120Force mode bypasses the git dirty working tree check, the HIGH risk confirmation gate, and replay environment validation. Use it in CI where the working directory may have uncommitted changes:
dojops apply --forceSkip external verification if you don’t have tools like terraform validate or actionlint installed and don’t want DojOps to auto-install them:
dojops apply --skip-verifyAllow all paths bypasses the DevOps file write allowlist. DojOps normally restricts writes to standard DevOps output paths. Use this only when your skill needs to write to a non-standard location:
dojops apply --allow-all-pathsStep 9: Roll back an applied plan
If you applied a plan and want to undo everything, use rollback. It deletes created files and restores any .bak backups that were made before overwriting:
dojops rollback plan-f7a2b1c3┌ Rolling Back: plan-f7a2b1c3
│
│ ✓ Deleted: .github/workflows/ci.yml
│ ✓ Deleted: Dockerfile
│ ✓ Deleted: docker-compose.yml
│ ✓ Restored: nginx.conf from nginx.conf.bak
│
└ Rollback complete - 3 files deleted, 1 restoredEvery plan that modifies an existing file keeps a .bak copy. Rollback uses those backups to restore your pre-apply state. If no backup exists for a file (because it was newly created), it’s simply deleted.
Step 10: Clean up without restoring backups
If you want to remove generated files without restoring backups — for example, after reviewing and committing them to version control — use clean instead:
dojops clean plan-f7a2b1c3┌ Cleaning: plan-f7a2b1c3
│
│ ✓ Removed: .github/workflows/ci.yml
│ ✓ Removed: Dockerfile
│ ✓ Removed: docker-compose.yml
│
└ 3 artifacts removedclean removes the tracked output files but does not restore .bak files. Use rollback when you want to undo, and clean when you want to wipe the slate after the files are no longer needed.
Step 11: Review execution history
List all past plan executions:
dojops history list◇ Plans (3) ────────────────────────────────────────────────────────────╮
│ │
│ plan-f7a2b1c3 COMPLETED 3/20/2026 Create multi-stage Dockerfile │
│ with CI workflow │
│ plan-e6d5c4b2 COMPLETED 3/19/2026 Add Kubernetes manifests for │
│ staging environment │
│ plan-d1a2b3c4 COMPLETED 3/18/2026 Set up Terraform for AWS S3 │
│ and CloudFront │
│ │
├────────────────────────────────────────────────────────────────────────╯Get the full details of a specific plan:
dojops history show plan-f7a2b1c3Step 12: Verify the audit trail
DojOps maintains a hash-chained audit log of every operation. Each entry’s hash depends on the previous entry’s hash, so you can detect tampering:
dojops history verifyAudit chain integrity: verified
Entries: 47
Chain status: valid (all hashes match)If entries have been manually edited or deleted, verify reports which entry broke the chain. To repair a corrupted chain (entries can’t be un-tampered, but the chain pointers can be rebuilt):
dojops history repairTry it yourself
-
Simulate a network failure. Run a plan with
--timeout 5(5-second timeout) on a complex prompt that will likely exceed it. Then use--resume --retrywith a normal timeout to complete the plan. -
Single-task regeneration. Create a plan with 4+ tasks, apply it fully, then modify your prompt slightly and re-run only Task 1 with
--task 1. Compare the original and new output. -
Audit trail inspection. After several plan executions, run
dojops history auditto browse the raw audit entries. Locate the entry for your most recent plan and verify the hash manually withdojops history verify.
Troubleshooting
--resume re-runs tasks that already completed
Plan state is stored in .dojops/plans/<plan-id>.json. If that file was deleted or the plan ID changed, --resume can’t find completed tasks. Check that .dojops/plans/ exists and contains the plan file before resuming.
Replay warns about skill hash mismatch
The .dops file for a skill was modified after the plan was created. If the change was intentional, create a new plan rather than replaying the old one. If the change was accidental, revert the .dops file to match the hash stored in the plan file.
--force is not writing files I expect
--force skips safety gates but does not change what files get written — it only bypasses the checks that would otherwise abort the run. If a file isn’t being written, check the plan’s task output for an LLM or schema validation error.
Rollback leaves .bak files behind
Rollback restores .bak files and deletes them after restoration. If a .bak file remains, a restore step failed — usually because the original path is now read-only. Fix the permissions and run rollback again.
What you learned
Plan execution in DojOps is a state machine, not a one-shot command. Every plan is persisted to .dojops/plans/ so that --resume and --retry can pick up exactly where things failed. Replay mode adds reproducibility by pinning temperature to 0 and verifying the environment matches the plan’s recorded snapshot. The audit log’s hash-chaining gives you a tamper-evident record of every operation, which matters for compliance workflows. Dry run and single-task execution give you surgical control over when and what gets written to disk.
Next steps
- CI/CD from Scratch — Apply these techniques to build a complete pipeline
- CI Debugging & Analysis — Debug failures in plans that include verification steps
- API Server & Dashboard — Trigger plans via the REST API
- CLI Reference — Full
apply,rollback, andhistoryflag reference