Skip to content

Cloud folders in ~/Library (CloudStorage, iCloud Drive) are reachable like Documents - #432

Merged
plonkus merged 8 commits into
mainfrom
feat/cloudstorage-like-documents
Nov 9, 2026
Merged

plonkus merged 8 commits into
mainfrom
feat/cloudstorage-like-documents

Conversation

@srosro

@srosro srosro commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

What

On a Mac, latch hides ~/Library from every worker that reads home (exec, file get/put), except ~/Library/Caches. This PR exposes two more folders, judged by the gatekeeper like any other home path, as if they were ~/Documents:

  • ~/Library/CloudStorage: Dropbox, Google Drive, OneDrive, Box and the like, as macOS's File Provider places them.
  • ~/Library/Mobile Documents/com~apple~CloudDocs: iCloud Drive, as Finder shows it.

Everything else in ~/Library stays hidden, Messages, Mail and Keychains included. So do other apps' iCloud containers in Mobile Documents beside iCloud Drive, such as com~example~App, which hold apps' private data rather than the owner's files.

How

One list, sandbox::VISIBLE_IN_LIBRARY (Caches, CloudStorage, Mobile Documents/com~apple~CloudDocs), now drives both places that encoded the old Caches-only exception:

  • the Seatbelt profile: (require-all (subpath ~/Library) (require-not (subpath …)) …);
  • the host's own path check, exec::is_hidden, which file get/put and exec's write paths go through.

The gatekeeper's two exec prompts now end with one shared statement of what exec can reach (exec_reach!), which names the visible folders and says what a cloud read or write does: reading an online-only file downloads it to the Mac, and a write may sync to the owner's other devices and to anyone the folder is shared with. The prompt hash changes. The help text (serve --help, file get), SKILL.md, APP.md, DOCKER.md, HOW-LATCH-WORKS.md, GETTING-STARTED.md and REVIEW.md now name the visible folders.

The app's Info.plist gains NSFileProviderDomainUsageDescription, the purpose string macOS can show when Latch reads a cloud folder:

Latch reads and writes files in your cloud folders, such as Dropbox, Google Drive and iCloud Drive, when your agents ask and your rules allow it. Reading a file that is only in the cloud downloads it to this Mac. Changes Latch makes may sync to your other devices and to anyone the folder is shared with.

Online-only files. Whether a process's reads may download an online-only (dataless) file is a setting it inherits from its parent, and macOS's default is no (setiopolicy_np(3)). A host started by launchd, as the app and latch serve -d start it, therefore had every read of an online-only cloud file fail with EDEADLK; shasum even reports that as the hash of an empty file. The workers that read home (exec's and a get's) now turn downloading on for themselves just before the sandbox (sandbox::platform::confine), and exec's program inherits it. Other workers are unchanged.

Not changed: exec's implicit cache writes (still only Library/Caches), anything on Linux, and the Messages/Contacts workers.

Evidence

  • Tests:
    • files::place (macOS): put into CloudStorage/Dropbox and iCloud Drive is allowed; into Mobile Documents/com~example~App and Messages it is refused (bad_path).
    • tests/worker.rs (macOS, kernel-enforced Seatbelt): the read worker reads files in Caches, CloudStorage/Dropbox and iCloud Drive, and is refused another app's iCloud container.
    • an_exec_reading_home_downloads_online_only_files (macOS): a worker started with downloading off, as launchd starts a host, gives its program downloading on. It fails without the fix (the program reports 1, off).
  • macOS gate (just test) at d0d891f: test.py: all passed (rust 826 tests run: 826 passed, Swift app 304 passed, plus fmt, clippy, installers and app bundle).
  • Online-only files, live, through this branch's sandboxed worker run as a host runs it, at a344ab2 (only the flag state, size and a hash match were printed):
    • Dropbox: a file marked dataless (online-only) was read in full (38 bytes) and macOS downloaded it in place (no longer dataless). The bytes match the file. ~/Library/Messages/chat.db is still refused (sandbox_denied).
    • Box: an online-only file was read in full (86,906 bytes) and downloaded in place, and the bytes match the file.
  • iCloud Drive, live, through a host started with latch serve -d (its own launchd job) on an unsigned dev build of this branch, called by an agent on a local Plow stack. Only sizes, flags and hashes were printed.
    • The first access to iCloud Drive made macOS ask: "latch" wants to access files managed by "iCloud Drive". The owner allowed it. The worker then listed iCloud Drive: every file in it was online-only.
    • Before the fix: reads of an online-only file failed with EDEADLK (Resource deadlock avoided) and the file stayed online-only. exec shasum -a 256 exited 0 with the hash of empty input; file get failed (transfer_failed on the host, client exit 5) and wrote nothing. A program in the worker that turned downloading on for itself read the whole file (156,599 bytes), which is what pointed to the fix.
    • After the fix, on another online-only file (3,345,445 bytes, flags 0x40000060): exec cat exited 0 and the file was downloaded in place (flags 0x40, no longer dataless). exec shasum -a 256, file get (as the host reported it) and the copy file get wrote all give the same size and sha256, eb9cfd30…9d59f. Now-local files read the same way: a re-read of the 156,599-byte file matched across exec, file get and the copy.
    • Gatekeeper: every exec and file get above was allowed.
    • Still refused: file get of ~/Library/Preferences/… and of the host's own state folder (bad_path, exit 4); exec of either (Operation not permitted).
  • Remaining checks:
    • An online-only Dropbox or Box file read through a launchd-started host. The fix is not specific to a provider, but only iCloud Drive was tried this way.
    • After release: whether the signed Plow Latch, which has Full Disk Access, still gets the iCloud Drive file-provider prompt. The run above used an unsigned dev build, which prompted as latch.

For the reviewers

  • Scope: CloudStorage plus only com~apple~CloudDocs, not all of Mobile Documents.
  • Writes: agents can now write in these folders when the gatekeeper allows it, and those writes may sync to other devices and shared-folder members.
  • Downloads: reading an online-only file makes macOS download it onto the Mac. Exec's and a get's workers now ask for that explicitly, whatever started the host.

Size

+200/−34 across 13 files: about 65 lines of code (comments included), 95 of tests, and the rest prompt, help, docs and the purpose string.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RFixJUe7wjDssghZka6U2f

srosro and others added 2 commits November 4, 2026 16:09
~/Library/CloudStorage (Dropbox, Google Drive and the like) and iCloud Drive
(Mobile Documents/com~apple~CloudDocs) join Caches as the folders of Library
that are not hidden: exec and file calls read and write them, judged like any
other home path. One list, VISIBLE_IN_LIBRARY, now gives both the sandbox
profile and the host's own path check; other apps' iCloud containers beside
iCloud Drive, and the rest of Library, stay hidden. The gatekeeper's prompt
and the help say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnohWTa9se2qd8YTYgMCP6
@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

📋 First review of this PR — reviewed a344ab2. 🧪 Tests not run. ✅ Prior-art (KID) checked. ⚡ Small-diff lane (117 lines): skipped consumers — screened by aggregator.

It appears @srosro is working towards letting agents work with users’ Dropbox, Google Drive and iCloud Drive files on a Mac as readily as Documents, under the existing gatekeeper and write grants, by exposing ~/Library/CloudStorage and iCloud Drive through the shared sandbox::VISIBLE_IN_LIBRARY policy and exec::is_hidden checks while keeping other Library content and apps’ private iCloud containers hidden. — reviewing against that goal.

Overview — The diff delivers the requested cloud-folder access through the existing host checks and Seatbelt policy. For this pre-PMF internal tool, with one engineer and a handful of hosts, the implementation is appropriately scoped; the only surviving probe is a small policy-deduplication opportunity.

Strengths — One shared exception list drives both enforcement paths, while implicit cache-write grants remain separate. The existing tests gain positive cloud-access cases and negative cases for neighboring private iCloud containers, exercising the intended boundary without adding another test framework.

Probes

  1. [low] [from: architecture-refined] [shape] Both exec prompts repeat the same home-visibility and secret-environment policy, requiring this PR to update both copies. Could their distinct authorization instructions append one shared literal, removing that repeated maintenance work? Files: latch/src/gate/mod.rs:78, latch/src/gate/mod.rs:197. Edit: Extract the common suffix using the existing vault_fill!/concat! pattern at line 81; replace both copies, approximately +8 structural LOC while deleting one duplicated policy paragraph.

Security — None.

Test coverage — The extended destination and kernel-enforced worker tests cover the new cloud roots and continued private-container denial; staged just test could not run because Cargo was absent (reviewer-environment limitation, exit 127). The author reports a passing macOS gate with 806 Rust tests and successful live online-only cloud-file reads; these were not independently rerun.

For AI authors — (Codex, Claude Code, Cursor, etc. reading this PR): The Probes above are load-bearing. Treat each [open] probe as a hard requirement — answer it directly in your reply or revisit the structural decision. Do NOT silently absorb a probe by adding more code; that path inverts the cost stance the probe is encoding. This repo's operating point (see its REVIEW.md) prefers cutting LOC over adding it; an [open] [simplification] probe whose answer is "no, this complexity isn't needed" should land as a deletion in your next push, not a new defensive guard.


How to use: auto-reviews every new PR and re-reviews after a period of inactivity. Trigger an incremental re-review with /srosro-update-review, or a whole-PR re-review with /srosro-review.

For humans only: push-access collaborators can post:

  • /srosro-approve — APPROVE the PR.
  • /srosro-props [from: <specialist>] — give props to a specialist's contribution.
  • /srosro-critique [from: <specialist>] — flag a specialist's contribution as a misread.
  • /srosro-memorize <feedback> — teach a calibration lesson (learn-from-replies updates COMMENT_REVIEW_MISTAKES.md from your body, sentiment-aware via LLM).

Props: /srosro-props [from: shape] caught a real layering bug we'd have shipped.
Critique: /srosro-critique [from: architecture-refined] DRY suggestion misread distinct seams.
Calibration: /srosro-memorize the architecture-refined DRY finding was a misread; those helpers serve different contracts.

AI agents must not use /srosro-memorize, /srosro-props, or /srosro-critique — those signals tune shared global state.

Generated by sam's ai review bot.

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author
  1. [low] Applied in 2a76036. Both exec judgments now end with one exec_reach!() paragraph (what exec can read, the visible Library folders, hidden secret env values), joined with concat! as vault_fill! already does. Both prompts are byte-identical to before. The diff is +17/−2 lines because rustfmt spreads the concat! over several lines, but one copy of the 600-character paragraph is gone. Gate unit tests pass (47).

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

/srosro-update-review

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

📋 Re-review of changes from a344ab2 to 2a76036 (git diff a344ab2..2a76036). 🧪 Tests not run. ✅ Prior-art (KID) checked. ⚡ Small-diff lane (19 lines): skipped security, data-integrity, architecture-refined, tests, consumers — screened by aggregator.

It appears @srosro is working towards letting agents work with owners’ cloud-synced files on macOS as naturally as files in Documents. The title and description frame that broader access change, while the staged diff consolidates its existing explanation into a shared exec_reach! statement for both gatekeeper exec judgments in latch/src/gate/mod.rs. — reviewing against that goal.

Overview — This increment addresses the previous review’s sole finding by sharing the exec visibility and hidden-secret policy between both prompts. Their expanded text, spacing and distinct authorization instructions are preserved. The change remains appropriately scoped for this pre-PMF internal tool, maintained by one engineer for a handful of hosts.

Strengths — The extraction follows the adjacent vault_fill!/concat! pattern, removing duplicated policy text without introducing runtime composition or another configuration path. Request assembly and audit prompt hashing continue to consume the expanded strings, so the extraction preserves both judgment inputs and prompt identity.

Probes

None.

Probe resolved: the duplicated exec-policy suffix is replaced by exec_reach!() at latch/src/gate/mod.rs:80, with both exec judgments using it. The cited duplication is gone at HEAD; no carry-forward finding remains.

Security — None.

Test coverage — Existing macOS destination and sandboxed-worker tests cover cloud-folder access and denial of neighboring private iCloud containers. Staged just test was not run successfully because Cargo is unavailable in the reviewer environment (exit 127); the author reports 47 passing gate unit tests after this extraction, which were not independently rerun.

For AI authors — (Codex, Claude Code, Cursor, etc. reading this PR): The Probes above are load-bearing. Treat each [open] probe as a hard requirement — answer it directly in your reply or revisit the structural decision. Do NOT silently absorb a probe by adding more code; that path inverts the cost stance the probe is encoding. This repo's operating point (see its REVIEW.md) prefers cutting LOC over adding it; an [open] [simplification] probe whose answer is "no, this complexity isn't needed" should land as a deletion in your next push, not a new defensive guard.


How to use: auto-reviews every new PR and re-reviews after a period of inactivity. Trigger an incremental re-review with /srosro-update-review, or a whole-PR re-review with /srosro-review.

For humans only: push-access collaborators can post:

  • /srosro-approve — APPROVE the PR.
  • /srosro-props [from: <specialist>] — give props to a specialist's contribution.
  • /srosro-critique [from: <specialist>] — flag a specialist's contribution as a misread.
  • /srosro-memorize <feedback> — teach a calibration lesson (learn-from-replies updates COMMENT_REVIEW_MISTAKES.md from your body, sentiment-aware via LLM).

Props: /srosro-props [from: shape] caught a real layering bug we'd have shipped.
Critique: /srosro-critique [from: architecture-refined] DRY suggestion misread distinct seams.
Calibration: /srosro-memorize the architecture-refined DRY finding was a misread; those helpers serve different contracts.

AI agents must not use /srosro-memorize, /srosro-props, or /srosro-critique — those signals tune shared global state.

Generated by sam's ai review bot.

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Acknowledged — no findings raised.

@srosro srosro added the converged knightwatch review converged on the current head label Nov 5, 2026
srosro and others added 2 commits November 4, 2026 16:56
… a write there do

Info.plist gets NSFileProviderDomainUsageDescription, the text macOS shows
when latch first reaches a cloud folder. The gatekeeper's exec text and the
agent guide say that reading an online-only file downloads it, and that a
write in a cloud folder syncs to everyone it is shared with. REVIEW.md and
GETTING-STARTED.md no longer say all of ~/Library but Caches is hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnohWTa9se2qd8YTYgMCP6
@srosro srosro removed the converged knightwatch review converged on the current head label Nov 5, 2026
@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

/srosro-update-review

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

📋 Re-review at 5c50582 — clean incremental unavailable for 2a76036 (rebase, force-push, or merge from base branch); evaluated full PR. 🧪 Tests not run. ✅ Prior-art (KID) checked. ⚡ Small-diff lane (147 lines): skipped consumers — screened by aggregator.

It appears @srosro is working towards letting agents work with users’ Dropbox, Google Drive and iCloud Drive files on a Mac as easily as files in Documents, under the owner’s rules, by extending the sandbox and host path checks through sandbox::VISIBLE_IN_LIBRARY. The gatekeeper prompts and Mac app permission text also explain that cloud-only reads download files and writes sync to the cloud and shared recipients — reviewing against that goal.

Overview — This full-diff re-review finds the implementation aligned with the stated goal: the existing enforcement paths expose CloudStorage and iCloud Drive while retaining the surrounding Library boundary. The scope fits this pre-PMF internal tool, maintained by one engineer for a handful of hosts. No unresolved findings remain.

Strengths — The shared visibility list keeps host validation and Seatbelt enforcement aligned, while cloud writes still require explicit exec grants. The tests extend existing destination and sandboxed-worker cases to cover both permitted cloud roots and denied neighboring private iCloud containers. Sharing exec_reach!() also gives both exec judgments the same explanation of cloud downloads, synchronization and hidden environment values.

Probes

None.

Probe resolved: both exec judgments consume exec_reach!() at latch/src/gate/mod.rs:88 and latch/src/gate/mod.rs:211; the previously cited policy duplication remains removed.

Security — None.

Test coverage — The added cases exercise host destination checks and kernel-enforced read boundaries; no surviving coverage finding remains. Staged just test could not run because Cargo was unavailable (exit 127), a reviewer-environment limitation. The author reports a passing macOS gate with 806 Rust tests, 47 gate unit tests after prompt deduplication, and successful live online-only reads through sandboxed workers; these results were not independently rerun.

For AI authors — (Codex, Claude Code, Cursor, etc. reading this PR): The Probes above are load-bearing. Treat each [open] probe as a hard requirement — answer it directly in your reply or revisit the structural decision. Do NOT silently absorb a probe by adding more code; that path inverts the cost stance the probe is encoding. This repo's operating point (see its REVIEW.md) prefers cutting LOC over adding it; an [open] [simplification] probe whose answer is "no, this complexity isn't needed" should land as a deletion in your next push, not a new defensive guard.


How to use: auto-reviews every new PR and re-reviews after a period of inactivity. Trigger an incremental re-review with /srosro-update-review, or a whole-PR re-review with /srosro-review.

For humans only: push-access collaborators can post:

  • /srosro-approve — APPROVE the PR.
  • /srosro-props [from: <specialist>] — give props to a specialist's contribution.
  • /srosro-critique [from: <specialist>] — flag a specialist's contribution as a misread.
  • /srosro-memorize <feedback> — teach a calibration lesson (learn-from-replies updates COMMENT_REVIEW_MISTAKES.md from your body, sentiment-aware via LLM).

Props: /srosro-props [from: shape] caught a real layering bug we'd have shipped.
Critique: /srosro-critique [from: architecture-refined] DRY suggestion misread distinct seams.
Calibration: /srosro-memorize the architecture-refined DRY finding was a misread; those helpers serve different contracts.

AI agents must not use /srosro-memorize, /srosro-props, or /srosro-critique — those signals tune shared global state.

Generated by sam's ai review bot.

@srosro

srosro commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Acknowledged — no findings raised. The macOS gate on 5c50582 (mbp, just test): test.py: all passed, rust 807 tests run: 807 passed. Merge waits on the reviewers' remaining condition, the test on the signed, installed app on mba.

@srosro srosro added the converged knightwatch review converged on the current head label Nov 5, 2026
plonkus and others added 3 commits November 9, 2026 14:46
…es named in Getting Started

The app's File Provider purpose string now says changes may sync to the
owner's other devices and to anyone the folder is shared with. SKILL.md
and the exec judgment say a write "may" sync, to other devices and
sharers. GETTING-STARTED.md lists every Library exception, Caches too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RFixJUe7wjDssghZka6U2f
A process inherits whether its reads may download a dataless (online-only)
file, and macOS's default is no. A host started by launchd therefore had
every read of an online-only Dropbox, Box or iCloud Drive file fail with
EDEADLK, which shasum reported as the hash of an empty file. The workers
that read home now turn materialization on for themselves before the
sandbox, and exec's program inherits it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RFixJUe7wjDssghZka6U2f
@plonkus

plonkus commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

/srosro-update-review

@srosro

srosro commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

📋 Re-review at d0d891f — clean incremental unavailable for 5c50582 (rebase, force-push, or merge from base branch); evaluated full PR. 🧪 Tests not run. ✅ Prior-art (KID) checked. 🔍 8 sibling repos not searched (8 allowlist; names withheld on a public repo). 📐 Complexity budget unchecked — the PR body is missing Goal, Outside users today, Minimal solution for that user count, Complexity added, Size: Expected net LOC; fill in those PR-template fields so the next review can check the budget.

It appears @srosro is working towards letting Mac users’ agents work with Dropbox, Google Drive and iCloud Drive files like ordinary Documents, including files stored only online, by extending the sandbox and host path checks to those cloud folders and enabling downloads on read. The gatekeeper prompts and app permission text explain that reads can download files and writes may sync to other devices and shared-folder members — reviewing against that goal.

Overview — This full-diff re-review finds the implementation aligned with the stated goal. Online-only downloads are enabled through existing worker confinement setup, addressing the reported launchd failure without provider-specific branches. The scope fits this pre-PMF internal tool, maintained by one engineer for a handful of hosts; no surviving findings remain.

Strengths — One visibility list drives both host path validation and Seatbelt exclusions, while independent state-directory protections remain effective inside cloud folders. Download-policy failures stop the worker before dispatch, and exec programs inherit the enabled policy. Existing boundary tests gain cloud-folder cases, while the new test specifically exercises inheritance from a parent with downloading disabled.

Probes

None.

Probe resolved: both exec judgments still consume exec_reach!() at latch/src/gate/mod.rs:88 and latch/src/gate/mod.rs:211; the previously cited policy duplication remains removed.

Security — None.

Test coverage — The tests cover allowed cloud roots, denial of neighboring private iCloud containers, and inheritance of the download policy. Staged just test could not run because cargo-nextest was unavailable (exit 127), a reviewer-environment limitation. The author reports a passing macOS gate at d0d891fd with 826 Rust and 304 Swift tests, plus successful live iCloud reads through a launchd-started host after the fix; these were not independently rerun. Signed installed-app behavior remains unverified in the staged evidence.

For AI authors — (Codex, Claude Code, Cursor, etc. reading this PR): The Probes above are load-bearing. Treat each [open] probe as a hard requirement — answer it directly in your reply or revisit the structural decision. Do NOT silently absorb a probe by adding more code; that path inverts the cost stance the probe is encoding. This repo's operating point (see its REVIEW.md) prefers cutting LOC over adding it; an [open] [simplification] probe whose answer is "no, this complexity isn't needed" should land as a deletion in your next push, not a new defensive guard.


How to use: auto-reviews every new PR and re-reviews after a period of inactivity. Trigger an incremental re-review with /srosro-update-review, or a whole-PR re-review with /srosro-review.

For humans only: push-access collaborators can post:

  • /srosro-approve — APPROVE the PR.
  • /srosro-props [from: <specialist>] — give props to a specialist's contribution.
  • /srosro-critique [from: <specialist>] — flag a specialist's contribution as a misread.
  • /srosro-memorize <feedback> — teach a calibration lesson (learn-from-replies updates COMMENT_REVIEW_MISTAKES.md from your body, sentiment-aware via LLM).

Props: /srosro-props [from: shape] caught a real layering bug we'd have shipped.
Critique: /srosro-critique [from: architecture-refined] DRY suggestion misread distinct seams.
Calibration: /srosro-memorize the architecture-refined DRY finding was a misread; those helpers serve different contracts.

AI agents must not use /srosro-memorize, /srosro-props, or /srosro-critique — those signals tune shared global state.

Generated by sam's ai review bot.

@plonkus
plonkus merged commit 6e9679b into main Nov 9, 2026
36 of 38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

converged knightwatch review converged on the current head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants