Skip to content

refactor(native-chat): keep each chat's scratch files in chat-scratch - #28219

Closed
brennanb2025 wants to merge 2 commits into
mainfrom
brennanb2025/cvs-s0-chat-scratch-folder
Closed

brennanb2025 wants to merge 2 commits into
mainfrom
brennanb2025/cvs-s0-chat-scratch-folder

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 16 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​341 $\color{#cf222e}{\Huge{\mathbf{−}}}$​138 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​203
Prod 17 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​119 $\color{#cf222e}{\Huge{\mathbf{−}}}$​65 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​54

ELI5

Each native chat gets a private folder on the computer that runs it, where the agent saves files such as the HTML pages Orca shows inline. That folder was called native-chat-visuals, but it is really the chat's scratch space. This PR renames it to chat-scratch (and the agent's variable to ORCA_CHAT_SCRATCH_DIR) before later PRs make the name part of bigger contracts.

What Changed

Problem. The folder's name says "visuals", but it is the chat's general scratch area: it is keyed only by the chat's id, sits outside the workspace, and is cleaned up with the chat. The next PRs in this stack let ordinary file opens reach this folder on paired and SSH hosts, publish its path on the chat's status, and expire it after 30 days without use. Once those land, the path is shown to users, stored in open tabs and share links, and checked by host access rules, so renaming later would need a real migration. Renaming now is cheap because nothing persists or publishes the path yet.

User-facing change. Nothing visible in the app. Agents see a different variable name, and the visuals skill gains two short factual sentences:

  • Before: the agent wrote visuals to $ORCA_CHAT_VISUALS_DIR (<state dir>/native-chat-visuals/<hash>).
  • After: the agent writes to $ORCA_CHAT_SCRATCH_DIR (<state dir>/chat-scratch/<hash>). The skill now also says: "This folder is temporary: Orca may remove it after 30 days without chat activity or changes. Save files meant to last in the workspace."
  • Visuals written before this change show the existing "Visualization unavailable" state, because Orca reads only the new folder. That affects development data only, since native chat has no real users yet.
  • Old folders still get cleaned up, but not immediately. The cleanup sweep checks the old folder by the same rules as the new one: a folder is removed once its chat record is gone or its local workspace is proven removed. An old folder whose chat and workspace still exist stays until the 30-day idle expiry (S13) applies to it.

Mechanism.

  • native-chat-visuals-folder.ts is now native-chat-scratch-folder.ts, with nativeChatScratchRootFor / nativeChatScratchFolderName / nativeChatScratchFolderFor. Only the root folder name changes. The per-chat name is still the first 32 hex characters of sha256(session id).
  • Launches set ORCA_CHAT_SCRATCH_DIR and never set the old name. When Orca was itself started from a chat, it inherits that chat's variable. Every Claude, Codex, ACP and Pi agent therefore has both the new and the old name stripped from what it inherits: the shared env helper, the Claude child environment (case-insensitive on Windows), and the Codex, ACP and Pi inherited-env delete lists. Without that, an agent started by Orca could write into another chat's folder. Pi never stripped the old name on main. Pi gets no scratch folder, so any value it inherits belongs to another chat.
  • The cleanup sweep (native-chat-visuals-sweep.ts) lists the old native-chat-visuals/ root as well as chat-scratch/. Both roots get the same rules and one shared per-run removal limit: remove a folder whose chat record is gone, or whose local workspace is proven removed. A missing or symlinked root is ignored. If one root can't be listed, the sweep logs it and still sweeps the other. The old root's name appears in exactly one place, a clearly named legacy constant in the folder module.
  • Unchanged: the ::orca-visual{file=...} reply line, the orca-chat-visuals skill name, the packaged plugin folder resources/native-chat-visuals/, the agentSession.readVisual endpoint, and the attachments store.

Why

chat-scratch describes what this folder promises: per-chat working files that can expire. Rejected alternatives:

  • chat-storage: suggests durable storage, but this folder expires after 30 idle days (S13), and attachments must never live in it.
  • agent-session-scratch: would match the agent-session-* state folders, but it is longer and names an internal concept. The agent-facing variable and skill already say "chat".

No compatibility alias is emitted for the old variable. Aliasing would only help agents launched before the upgrade, which still have their original environment anyway. Stripping the old name is not an alias: it only stops a stale parent value from leaking through.

Stack position. S0, the root of the chat-visuals scratch-folder stack, based on main. S2 (#28189), S3 and S13 (#28193) will merge this branch once and use the new helper names. S9 builds on it. S1 and S8 do not depend on it.

Differences from the common pattern.

  • Intended: this folder expires after 30 days without use (S13), whereas the common pattern removes per-thread storage only when the thread is deleted. That is safe because this is scratch space. The skill says so, and files meant to last belong in the workspace.

Linked Issue

Part of the chat visuals scratch-folder stack (internal; no separate issue).

Visual Proof

N/A: no UI change. The only agent-visible change is the variable name and two sentences in the skill text.

Testing

  • Automated tests added/updated
  • New native-chat-scratch-folder.test.ts: the new root, the unchanged hash derivation, and the legacy root path.
  • Sweep: old-root folders are removed under the same rules (no record, proven-removed workspace) and kept otherwise; the old root is swept when the new one doesn't exist; a symlinked old root is never followed; when either root can't be listed, the failure is logged and the other root is still swept.
  • Env: the new variable is set on Claude, Codex and ACP launches. An inherited new or old variable is stripped for Claude, Codex, ACP and Pi; for Claude this includes differently cased names on Windows. No launch emits ORCA_CHAT_VISUALS_DIR. The skill text names the new variable for POSIX and PowerShell and no longer mentions the old one.
  • The launch-parity snapshot was regenerated. Its diff is only the new path and variable, the old name in the delete lists, and both names in Pi's delete list.
  • Real CLIs: ORCA_REAL_CLAUDE_CLI_TEST=1 ORCA_REAL_CODEX_CLI_TEST=1 on claude-structured-real-cli, claude-structured-real-cli-fold, claude-structured-real-cli-visuals and codex-structured-real-cli-visuals: 4 files, 16 tests, all passed. Both visuals tests ran against the real CLIs; neither was skipped.
  • Platforms run: macOS. Windows env handling is covered by unit tests. SSH: the folder is derived on the host that runs the chat, as before. Nothing about where it is derived changed.

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance

  • Mixed versions: nothing on the wire changes. The visual read endpoint still takes a session id and a file name, and the host resolves the folder itself, so old clients against a new host keep working.
  • Mobile: no change.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

The per-chat folder agents write into is the chat's scratch space, not
only a visuals folder. Rename its root to <state>/chat-scratch/<hash> and
the agent variable to ORCA_CHAT_SCRATCH_DIR before later work publishes
the path. The old variable is still stripped from inherited environments,
and the sweep keeps removing folders under the old root by the same rules.
The visuals skill names the new variable and says the folder is temporary.
…h env from Pi

A root that cannot be listed is logged and skipped, so an unreadable
pre-rename root never stops the live root's cleanup (and vice versa).
Pi launches get no scratch folder, so both the new and the pre-rename
variable are stripped from what a Pi child inherits.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Superseded by the rebuilt six-PR chat scratch stack (#28385 merged, #28389, #28397, #28437, #28394, #28479). This piece is replaced by #28389 (the rename). Closing.

@brennanb2025
brennanb2025 deleted the brennanb2025/cvs-s0-chat-scratch-folder branch October 14, 2026 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant