# Each instance of a multi-instance dispatch system MUST have its own scratch directory keyed by instance name — concurrent instances must never collide in a shared `/tmp` or `AppData` ## What it says When designing a system that supports multiple concurrent instances of the same workflow (multi-agent dispatch, parallel AI calls, multi-conversation chat), each instance MUST have its own scratch directory keyed by its instance name (e.g., `dispatch_scratch_dir(conversation_name)`). The shared `/tmp`, `AppData\Local\Temp`, or `$env:TEMP` is OFF-LIMITS for scratch storage — concurrent instances will collide on filenames. ## Why nagent discovered this the hard way: when `` was implemented with a shared scratch directory, two concurrent conversations racing on `scratch.json` corrupted each other's outputs. The fix (per nagent commit `49e07f3`) was to thread a `conversation_scratch_dir(conversation_name)` through every write operation and pre-create the directory on session start. ## The pattern ```python def scratch_dir_for(instance_name: str) -> Path: """Return the scratch directory for this instance, creating it if missing. Each instance name (conversation name, worker ID, dispatch ticket ID) gets its own directory under the project's tests/artifacts/ tree. Concurrent instances never collide because the directories are distinct. """ safe_name = re.sub(r"[^A-Za-z0-9_.-]", "_", instance_name) path = REPO_ROOT / "tests" / "artifacts" / "scratch" / safe_name path.mkdir(parents=True, exist_ok=True) return path ``` ## Failure mode this prevents Two instances writing `scratch/state.json` to `/tmp` race on the file. The first writes "in-progress"; the second overwrites with "complete" before the first's `read-modify-write` cycle finishes. The first's `commit` then reads stale state and reverts the second's work. The fix: each instance has its own directory; file collisions are impossible. ## Where to apply this - **AI client dispatch** — when sending to a provider, route scratch state (rate-limit counters, retry budgets, cached responses) through `scratch_dir_for(conversation_name)`. - **Worker pool** — each Tier 3 worker has its own scratch dir keyed by `worker_id` (not the shared `tests/artifacts/tier2_state/`). - **Multi-conversation GUI** — when the user opens two discussions in parallel, each has its own scratch dir for "draft not yet flushed" state. - **MCP tool execution** — if a tool writes to disk and is called from multiple conversations, the scratch dir is per-conversation. ## Cross-refs - `conductor/tracks/nagent_review_20260608/decisions.md` §"Candidate 23: Per-conversation scratch directory for Manual Slop dispatch_inference" (MEDIUM priority) - `conductor/tracks/nagent_review_20260608/nagent_takeaways_v3_20260619.md` §3 ("v3 new candidates") — describes the per-conversation scratch dir hardening commit `49e07f3` - `conductor/code_styleguides/workspace_paths.md` — the broader rule that all paths must live under `./tests/`, never `%TEMP%`