docs(cloud-agents): document customizing workspace snapshots#105
Conversation
Add a new page under cloud-agents/handoff documenting how to customize the end-of-run snapshot pipeline that backs local-to-cloud and cloud-to-cloud handoff. Targets self-hosted and CLI users who run outside the bundled warp-agent-docker image and need to provide their own declarations script (or a static declarations file) for handoff to work. The page covers: - When to customize (custom Docker image, Direct backend, unmanaged oz agent run in CI) - The two env vars Warp respects (OZ_SNAPSHOT_DECLARATIONS_SCRIPT, OZ_SNAPSHOT_DECLARATIONS_FILE) - The JSONL declarations file format (v1 schema, repo vs file kinds) - A minimal bash script template + the static declarations file pattern (no script needed) - --no-snapshot for disabling snapshots per run Wire the new page into the Handoff sidebar group and add single-sentence cross-links from local-to-cloud, cloud-to-cloud, self-hosting/unmanaged, and self-hosting/index so readers arriving from any of those entry points can find it. Co-Authored-By: Oz <oz-agent@warp.dev>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Drop the "Continue locally" mention from the intro. Cloud-to-local handoff doesn't apply workspace patches to a local checkout (per handoff/index.mdx), so the claim was misleading. - Replace "empty workspace" with "without the prior session's uncommitted changes". The cloud workspace isn't empty without a snapshot — the environment still clones repos at HEAD; what's missing is the uncommitted delta. - Restructure "How snapshotting works" to lead with the two modes (script-driven vs static) before walking through each one. Removes the implicit assumption that the script always runs. - Drop the setup_command half of the Direct backend tip. setup_command injects env vars via OZ_ENVIRONMENT_FILE, which is more indirection than this page should explain — just point at `environment` config. - Remove the local-to-cloud cross-link to the snapshots page. The local-to-cloud path uses upload_snapshot_for_handoff() with Vec arguments, not OZ_SNAPSHOT_DECLARATIONS_SCRIPT, so the cross-link could mislead readers. cloud-to-cloud, self-hosting/unmanaged, and self-hosting/index still link to the page. Co-Authored-By: Oz <oz-agent@warp.dev>
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds a new Cloud Agents handoff page that explains workspace snapshot customization, wires it into the sidebar, and adds cross-links from related handoff and self-hosting docs. The structure and most technical details align with the available implementation context.
Concerns
- The new page should warn users that declared file paths are uploaded as snapshot content, especially because the examples mention logs and scratch files.
- The bash template should escape JSON metacharacters in repository paths before writing declarations.
- The related-page link claims the CLI reference includes
--no-snapshot, but that flag is not documented there.
Security
- Add an explicit privacy/data-handling caution for arbitrary
filedeclarations so users do not accidentally snapshot secrets, credentials, or sensitive logs.
Verdict
Found: 0 critical, 0 important, 3 suggestions
Approve with nits
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| * **Paths must be absolute.** Relative paths are rejected and logged as malformed. | ||
| * **Prefer `repo` over `file` for paths inside a repository.** Warp generates a git diff for each `repo` entry (tracked changes plus untracked files), so individual `file` entries inside that repo are redundant and dropped before upload. Including a `repo` entry is also more extensible than enumerating files. | ||
| * **Repos are diffed, not copied wholesale.** Only changed files are uploaded for each `repo` entry, so listing a large repository is cheap when the agent's changes are small. | ||
| * **`file` entries are for paths outside any declared repo** — for example, logs the agent wrote to `/tmp` or scratch files in `$HOME`. |
There was a problem hiding this comment.
💡 [SUGGESTION] [SECURITY] This section encourages declaring arbitrary files such as logs or scratch files, but it never warns that declared paths are uploaded to Warp. Add a caution to exclude secrets, credential stores, and sensitive logs before users copy this pattern.
| printf '{"version":1,"kind":"repo","path":"%s"}\n' "$repo_root" \ | ||
| >> "$OZ_SNAPSHOT_DECLARATIONS_FILE" |
There was a problem hiding this comment.
💡 [SUGGESTION] The script writes repo_root directly into JSON, so paths containing quotes or backslashes produce malformed declarations that Warp skips. Escape JSON metacharacters before writing the line.
| printf '{"version":1,"kind":"repo","path":"%s"}\n' "$repo_root" \ | |
| >> "$OZ_SNAPSHOT_DECLARATIONS_FILE" | |
| repo_json="$(printf '%s' "$repo_root" | sed 's/\\/\\\\/g; s/"/\\"/g')" | |
| printf '{"version":1,"kind":"repo","path":"%s"}\n' "$repo_json" \ | |
| >> "$OZ_SNAPSHOT_DECLARATIONS_FILE" |
| * [Handoff from cloud to cloud](/agent-platform/cloud-agents/handoff/cloud-to-cloud/) - Continue a finished cloud run; the prior session's workspace snapshot is what gets restored. | ||
| * [Self-hosting overview](/agent-platform/cloud-agents/self-hosting/) - Architecture decision guide for self-hosted workers, where customizing snapshots is most often needed. | ||
| * [Unmanaged architecture](/agent-platform/cloud-agents/self-hosting/unmanaged/) - Run `oz agent run` in CI, Kubernetes, or your dev environment outside the bundled image. | ||
| * [Oz CLI](/reference/cli/) - Full reference for `oz agent run` and `oz agent run-cloud`, including the `--no-snapshot` flag. |
There was a problem hiding this comment.
💡 [SUGGESTION] The CLI reference does not currently document --no-snapshot, so this related-page description sends readers to a page that cannot answer the flag-specific question. Either add the flag to /reference/cli/ in this PR or remove the including the --no-snapshot flag claim here.
Three suggestions from the Oz review on PR #105, all accepted: 1. Add a security caution after the declarations format section. Explicit warning that declared `file` paths are uploaded verbatim and `repo` paths upload the git diff (tracked + untracked, non-gitignored). Tells users to keep secrets, credentials, and API tokens out of declared `file` entries before copying the pattern. 2. Escape JSON metacharacters in repo paths in the bash template. The previous example printf'd `repo_root` straight into JSON; a path containing `"` or `\` would produce malformed JSON that Warp skips with a WARN. Added a sed pass that escapes `\` first, then `"`, matching the bot's suggested patch. 3. Drop the "including the --no-snapshot flag" claim from the Oz CLI Related pages bullet. /reference/cli/ doesn't document the flag today, so the claim sent readers somewhere that couldn't answer the flag-specific question. The flag is already covered on this page in the Disable snapshots section. Co-Authored-By: Oz <oz-agent@warp.dev>
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
The "Prefer `repo` over `file`" rule said `repo` entries pick up "tracked changes plus untracked files" while the security caution right below said "tracked changes plus untracked, non-gitignored files". The caution is the accurate one (matches `git ls-files --others --exclude-standard` in `app/src/ai/agent_sdk/driver/snapshot.rs::build_repo_patch`), so tighten the rule to match. Co-Authored-By: Oz <oz-agent@warp.dev>
There was a problem hiding this comment.
Overview
This PR adds a new documentation page for customizing end-of-run workspace snapshots and wires it into the cloud-agent handoff sidebar and related self-hosting/handoff pages. I reviewed the supplied description, annotated diff, spec context, local docs guidance, and performed the supplemental security pass.
Concerns
No blocking concerns found. The changed content is documentation-only, the new internal links match existing docs paths, and the security review did not identify security issues.
Verdict
Found: 0 critical, 0 important, 0 suggestions
Approve
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
…ots docs The two GitHub URLs the new snapshots page used were both pointing at warpdotdev/warp-agent-docker, which is a private repo — anonymous visitors get HTTP 404. Replaced both with link-free user-facing prose and reworded all text mentions of the internal repo name. Specifically: * snapshots.mdx frontmatter description: "bundled warp-agent-docker image" → "bundled cloud agent image". * snapshots.mdx intro paragraph: drop the link to the private repo root; refer to "Warp's bundled cloud agent image" instead. * snapshots.mdx "When to customize" intro: replace "bundled warp-agent-docker image" with "bundled cloud agent image". * snapshots.mdx env-var reference: same swap for OZ_SNAPSHOT_DECLARATIONS_SCRIPT description. * snapshots.mdx "Write a custom declarations script": drop the link to the private snapshot-declarations.sh file; the sentence now just introduces the minimal pattern. * snapshots.mdx: add a :::note callout under the script example describing what the bundled image's richer implementation does beyond the minimal pattern (OZ_SNAPSHOT_SCAN_ROOTS override, jq for JSON encoding, dedup against existing repo declarations) so power users know what's available without us pointing at private artifacts. * unmanaged.mdx Tracking and observability cross-link: drop the "warp-agent-docker" qualifier. Verified with grep: no more "warp-agent-docker" references anywhere in src/content/docs/. Co-Authored-By: Oz <oz-agent@warp.dev>
| **Declared paths are uploaded to Warp.** `file` entries upload the file's contents verbatim, and `repo` entries upload the repo's git diff (tracked changes plus untracked, non-gitignored files). Before declaring logs, scratch files, or other agent outputs as `file` entries, make sure they don't contain secrets, credentials, API tokens, or other sensitive data. | ||
| ::: | ||
|
|
||
| ## Write a custom declarations script |
There was a problem hiding this comment.
do you think this is sufficient for a minimal pattern
There was a problem hiding this comment.
spoke offline about this, but I think it's cool to just include the whole script
|
|
||
| The default snapshotting behavior is sufficient when your cloud agent runs use the bundled cloud agent image and operate entirely inside the assigned workspace. Customize snapshots when: | ||
|
|
||
| * **You use a custom Docker base image** that doesn't include the bundled `snapshot-declarations.sh` script. |
There was a problem hiding this comment.
nit (and oo1): parts of this section are a little duplicative with the line 13's callout
There was a problem hiding this comment.
Addressed in bea343e — restructured the "When to customize snapshots" section so the bullets aren't duplicative with the intro paragraph anymore. The list now hits outside-bundled-image, repos/files outside the workspace, and dynamic scripted behavior as three distinct user-intent triggers.
|
|
||
| * **You use a custom Docker base image** that doesn't include the bundled `snapshot-declarations.sh` script. | ||
| * **You run cloud agents on a self-hosted Direct backend** or as unmanaged `oz agent run` invocations, where the bundled script isn't on disk. | ||
| * **You want to snapshot a fixed set of repositories or files** outside the agent's workspace (for example, a sibling repo that the agent reads but doesn't `cd` into). |
There was a problem hiding this comment.
I think we can make this a little more expansive, because it doesn't have to be a fixed set. Because the user can write a custom script to generate the snapshot file and have warp run it, they can really script whatever dynamic or static snapshotting behavior they want
There was a problem hiding this comment.
Addressed in bea343e — replaced the "fixed set" bullet with a broader "dynamic snapshotting behavior" item that calls out that the script can implement any logic the operator wants (filter by git status, dedupe against a baseline, emit a fixed list, etc.), not just a fixed set of paths.
|
|
||
| There are two ways to tell Warp what to snapshot at the end of a cloud agent run: | ||
|
|
||
| * **Script-driven** (default in the bundled image) - Warp invokes a declarations script that emits one JSON line per repository or file to snapshot. Use this when the set of repos isn't fixed ahead of time (for example, the agent may `git init` a new directory during its work). |
There was a problem hiding this comment.
it would probably be good to include the env var that points to the script here, so people know what to override? Or at least like reference it so that folks know that it's over-rideable before reading the script driven flow section
There was a problem hiding this comment.
Addressed in bea343e — the Script-driven bullet now names OZ_SNAPSHOT_DECLARATIONS_SCRIPT inline so readers know the path is overridable before they reach the Script-driven flow subsection. The Static bullet now names OZ_SNAPSHOT_DECLARATIONS_FILE for symmetry.
| ## Environment variables | ||
|
|
||
| * **`OZ_SNAPSHOT_DECLARATIONS_SCRIPT`** - Absolute path to the script Warp invokes at the end of each cloud agent run. The bundled cloud agent image sets this automatically. Set it yourself when running outside the bundled image. | ||
| * **`OZ_SNAPSHOT_DECLARATIONS_FILE`** - Absolute path to the JSONL file the script writes to (and Warp reads from). Warp sets this to a per-run path by default. Override it only when you want Warp to read from a static, pre-populated declarations file instead of running a script. |
There was a problem hiding this comment.
folks should also set/override this from the OZ_SNAPSHOT_DECLARATIONS_SCRIPT so that warp knows where to read the final snapshot file from
There was a problem hiding this comment.
Addressed in bea343e — the OZ_SNAPSHOT_DECLARATIONS_FILE entry now spells out its relationship with OZ_SNAPSHOT_DECLARATIONS_SCRIPT: when the script var is set, Warp picks a per-run path and exports it to the script; users can also set/override the file path themselves so Warp knows where to read from, either to drive the static (no-script) flow or to pin both Warp and the script to a path they control.
| * **Paths must be absolute.** Relative paths are rejected and logged as malformed. | ||
| * **Prefer `repo` over `file` for paths inside a repository.** Warp generates a git diff for each `repo` entry (tracked changes plus untracked files), so individual `file` entries inside that repo are redundant and dropped before upload. Including a `repo` entry is also more extensible than enumerating files. | ||
| * **Repos are diffed, not copied wholesale.** Only changed files are uploaded for each `repo` entry, so listing a large repository is cheap when the agent's changes are small. | ||
| * **`file` entries are for paths outside any declared repo** — for example, logs the agent wrote to `/tmp` or scratch files in `$HOME`. |
| **Declared paths are uploaded to Warp.** `file` entries upload the file's contents verbatim, and `repo` entries upload the repo's git diff (tracked changes plus untracked, non-gitignored files). Before declaring logs, scratch files, or other agent outputs as `file` entries, make sure they don't contain secrets, credentials, API tokens, or other sensitive data. | ||
| ::: | ||
|
|
||
| ## Write a custom declarations script |
There was a problem hiding this comment.
spoke offline about this, but I think it's cool to just include the whole script
…l example
Per Harry's Slack OK on showing the full script ("from a security POV,
definitely no issues with showing the entire script... any user who
cared could easily find the script by just running a cloud agent and
cat-ing it out"), include the canonical declarations script Warp
invokes inside the bundled cloud agent image in addition to (not
replacing) the minimal sed-based example.
Changes to snapshots.mdx:
* Keep the minimal sed-based example unchanged. It's a clean starting
point for users adapting a custom script.
* Add a new "### The full bundled script" subsection right after the
Direct backend tip. It introduces the canonical script in prose,
then shows it verbatim in a second bash code block.
* Add a :::note flagging that OZ_SNAPSHOT_JQ defaults to /agent/tools/jq
(an image-only path). External users adapting the script need to put
jq on PATH or override OZ_SNAPSHOT_JQ.
* Drop the previous :::note that summarized what the bundled script
did extra — the same information is now visible directly in the
script.
Co-Authored-By: Oz <oz-agent@warp.dev>
Apply Harry's four outstanding review comments on PR #105: - "When to customize snapshots" no longer duplicates the example list from the intro paragraph. Reframed around user intent rather than failure modes: outside-bundled-image, repos/files outside the workspace, and dynamic scripted behavior. - Replaced the "snapshot a fixed set of repositories or files" bullet with a broader "dynamic snapshotting behavior" item that calls out that the script can implement any logic the operator wants, not just a fixed list. - The "Script-driven" bullet under "How snapshotting works" now names OZ_SNAPSHOT_DECLARATIONS_SCRIPT inline, so readers know the script path is overridable before they reach the Script-driven flow subsection. The "Static" bullet now names OZ_SNAPSHOT_DECLARATIONS_FILE for symmetry. - The OZ_SNAPSHOT_DECLARATIONS_FILE entry in the Environment variables section now spells out its relationship with OZ_SNAPSHOT_DECLARATIONS_SCRIPT: when the script var is set Warp picks a per-run path and exports it to the script; users can also override the file path themselves so both Warp and the script use a path they control (or to drive the static, no-script flow). Co-Authored-By: Oz <oz-agent@warp.dev>
Summary
Adds a new page documenting how to customize end-of-run workspace snapshots for cloud agent handoff, and wires it into the Handoff sidebar group plus cross-links from existing pages.
The end-of-run snapshot pipeline backs both local-to-cloud and cloud-to-cloud handoff. Today the bundled
warp-agent-dockerimage ships a declarations script that snapshots every git repo under the agent's workspace, but customers running outside that image (custom Docker bases, self-hosted Direct backend, unmanagedoz agent runin CI) get no snapshotting by default and have no docs explaining how to opt back in. This PR closes that gap so we can:What this PR adds
src/content/docs/agent-platform/cloud-agents/handoff/snapshots.mdxOZ_SNAPSHOT_DECLARATIONS_SCRIPTandOZ_SNAPSHOT_DECLARATIONS_FILErepovsfile, absolute paths)--no-snapshotfor disabling per runHandoffinsrc/sidebar.tshandoff/local-to-cloud,handoff/cloud-to-cloud,self-hosting/unmanaged, andself-hosting/indexValidation
python3 .agents/skills/check_for_broken_links/check_links.py --internal-only— 0 broken internal links across 329 files.python3 .agents/skills/style_lint/style_lint.py --changed— Only flagged 2 pre-existing false positives inunmanaged.mdx's description, where "the oz agent run CLI" is matched as the deprecated "Oz agent" phrasing. Not introduced by this PR and out of scope to fix.Out of scope
warp-internal).OZ_SNAPSHOT_SCAN_ROOTSandOZ_SNAPSHOT_JQ— these are conventions of the bundled script, not part of Warp's contract.Conversation: https://staging.warp.dev/conversation/b33e43a6-1d68-48b4-a3bb-7721c4e87122
Run: https://oz.staging.warp.dev/runs/019e4216-6f14-7ac4-9d4e-5186b5227a2a
Plans:
This PR was generated with Oz.