3.0 KiB
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 <nagent-write> 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
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 sharedtests/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 commit49e07f3conductor/code_styleguides/workspace_paths.md— the broader rule that all paths must live under./tests/, never%TEMP%