EP-0128: OS-Native Directory Resolution and Runtime Storage Standards¶
| Field | Value |
|---|---|
| EP | 0128 |
| Title | OS-Native Directory Resolution and Runtime Storage Standards |
| Author | Eran Rivlis & Ariel |
| Status | Final |
| Type | Standards Track |
| Created | 2026-08-25 |
| Updated | 2026-08-25 |
Abstract¶
This proposal specifies the integration of the zero-dependency platformdirs
library into Tur's core runtime. It establishes canonical, cross-platform standards for resolving OS-native user data,
runtime IPC sockets, temporary lock files, and cache directories across Linux (XDG), macOS, and Windows. Crucially, it
codifies the boundary between global OS-level directories and local workspace storage, ensuring full compliance with
EP-0124 (Terrain Isolation).
Motivation¶
As Tur evolves towards multi-agent swarm coordination (EP-0118, EP-0122, EP-0123) and multi-tenant persona management (EP-0114), the framework must manage multiple distinct classes of file system state:
- Transient Runtime & IPC State: Named pipes, socket files, PID locks, and active signal databases (
.signals.db) used by the Inter-Agent Signal Protocol (IASP). Placing these in permanent user directories risks stale state surviving reboots and system crashes. - Ephemeral Cache State: Deductive memory graph indexes, telemetry aggregation logs, and temporary template compilation artifacts that can be safely purged by OS disk-cleanup utilities.
- Global Persona Configurations (The Traveler): Cross-project persona definitions and universal memory banks that belong in standard user config/data directories.
- Local Workspace State (The Terrain): Project-specific session notes and incarnational OKF memory that must remain strictly within the workspace repository.
Currently, Tur relies on ad-hoc Path.home() / ".tur" paths for global lookups, which ignores platform conventions
(e.g., %LOCALAPPDATA% on Windows, ~/Library/Application Support/ on macOS, and XDG specs on Linux). By adopting
platformdirs, Tur eliminates platform-specific path boilerplate while achieving robust runtime isolation.
Rationale¶
Council Alignment¶
- The Noether Module (Symmetry & Invariance):
platformdirsprovides symmetrical directory resolution across POSIX, macOS, and Windows platforms without customsys.platformbranches or OS-specific path parsing hacks. - The Golem Protocol (Containment & Boundaries): Clearly segregates ephemeral runtime data (
user_runtime_dir) and cache (user_cache_dir) from permanent identity DNA (user_data_dir), preventing corrupted caches from polluting core persona memory. - The Steward Principle (Harmony & Pragmatism):
platformdirsis a zero-dependency, lightweight, and universally trusted Python standard library maintained by the PyPA/tox-dev ecosystem. - The Shannon Module (Efficiency): Offloading platform-specific directory conventions to a dedicated library reduces internal codebase complexity and test matrix surface area.
Specification¶
1. Core Dependency (pyproject.toml)¶
Add platformdirs to core dependencies:
[project]
dependencies = [
"typer>=0.12.0",
"pydantic>=2.6.0",
"jinja2>=3.1.0",
"pyyaml>=6.0.0",
"rich>=13.0.0",
"networkx>=3.6",
"platformdirs>=4.2.0",
]
2. Path Resolution Architecture (src/tur/paths.py)¶
Refactor paths.py to expose distinct resolution primitives according to storage category using a unified PlatformDirs singleton, returning direct pathlib.Path objects and hardened with container fallbacks and POSIX permissions:
from functools import lru_cache
import logging
import os
from pathlib import Path
import tempfile
from typing import Any
from platformdirs import PlatformDirs
logger = logging.getLogger(__name__)
APP_NAME = "tur"
APP_AUTHOR = False # Suppress Windows publisher folder duplication (AppData/Local/tur vs tur/tur)
# Module-level PlatformDirs instance avoiding per-call object allocations
_PLATFORM_DIRS = PlatformDirs(
appname=APP_NAME,
appauthor=APP_AUTHOR,
roaming=False,
opinion=True,
)
@lru_cache(maxsize=16)
def resolve_runtime_dir() -> Path:
"""Resolve ephemeral runtime directory for IPC sockets, signal queues, and locks.
Linux: /run/user/<uid>/tur (or $XDG_RUNTIME_DIR/tur)
macOS: ~/Library/Caches/TemporaryItems/tur
Windows: %LOCALAPPDATA%\\Temp\\tur
Container / Headless Fallback:
If /run/user/<uid> is missing or read-only (e.g. minimal Docker/CI),
falls back to tempfile.gettempdir() / f"tur-runtime-{uid}".
"""
env_runtime = os.environ.get("TUR_RUNTIME_DIR")
if env_runtime:
p = Path(env_runtime).expanduser().resolve()
p.mkdir(parents=True, exist_ok=True)
return p
try:
runtime_dir = _PLATFORM_DIRS.user_runtime_path
runtime_dir.mkdir(parents=True, exist_ok=True)
# Apply POSIX 0700 permission mask for multi-user IPC socket security
if hasattr(os, "chmod") and os.name != "nt":
try:
os.chmod(runtime_dir, 0o700)
except OSError:
pass
return runtime_dir.resolve()
except (OSError, PermissionError) as exc:
uid = os.getuid() if hasattr(os, "getuid") else "win"
fallback = Path(tempfile.gettempdir()) / f"tur-runtime-{uid}"
fallback.mkdir(parents=True, exist_ok=True)
if hasattr(os, "chmod") and os.name != "nt":
try:
os.chmod(fallback, 0o700)
except OSError:
pass
logger.debug(f"Runtime dir fallback engaged: {fallback} (due to {exc})")
return fallback.resolve()
@lru_cache(maxsize=16)
def resolve_cache_dir() -> Path:
"""Resolve directory for ephemeral introspection indexes and graph caches."""
env_cache = os.environ.get("TUR_CACHE_DIR")
if env_cache:
p = Path(env_cache).expanduser().resolve()
p.mkdir(parents=True, exist_ok=True)
return p
cache_dir = _PLATFORM_DIRS.user_cache_path
cache_dir.mkdir(parents=True, exist_ok=True)
return cache_dir.resolve()
@lru_cache(maxsize=16)
def resolve_log_dir() -> Path:
"""Resolve directory for diagnostic logs, telemetry metrics, and traces."""
env_log = os.environ.get("TUR_LOG_DIR")
if env_log:
p = Path(env_log).expanduser().resolve()
p.mkdir(parents=True, exist_ok=True)
return p
log_dir = _PLATFORM_DIRS.user_log_path
log_dir.mkdir(parents=True, exist_ok=True)
return log_dir.resolve()
@lru_cache(maxsize=16)
def resolve_data_dir() -> Path:
"""Resolve global user data directory for permanent persona definitions."""
env_home = os.environ.get("TUR_HOME") or os.environ.get("TUR_DATA_DIR")
if env_home:
return Path(env_home).expanduser().resolve()
legacy_home = (Path.home() / ".tur").resolve()
if (legacy_home / "personas.yaml").exists() or (legacy_home / "personas").exists():
return legacy_home
data_dir = _PLATFORM_DIRS.user_data_path
data_dir.mkdir(parents=True, exist_ok=True)
return data_dir.resolve()
def is_global_path(p: Path) -> bool:
"""Returns True if *p* lives inside user-global data, runtime, log, or cache stores."""
resolved_p = p.resolve()
for root_getter in (resolve_data_dir, resolve_cache_dir, resolve_runtime_dir, resolve_log_dir):
try:
resolved_p.relative_to(root_getter())
return True
except (ValueError, Exception):
pass
try:
resolved_p.relative_to((Path.home() / ".tur").resolve())
return True
except (ValueError, Exception):
return False
def resolve_workspace_dir(ctx: Any | None = None) -> Path | None:
"""Deterministically resolves active workspace / Terrain directory.
INVARIANT (EP-0124): Workspace state is ALWAYS strictly co-located inside
<workspace_root>/.tur/ and NEVER redirects to global platformdirs paths.
"""
...
3. Subsystem Storage Mapping¶
| Category | Subsystem / Files | Target Path Function | OS Example (Linux / Windows) |
|---|---|---|---|
| Workspace Terrain | Incarnational OKF, Session Notes | resolve_workspace_dir() |
<repo>/.tur/ (Inviolable) |
| Global Traveler | Personas, Universal Memory | resolve_data_dir() |
~/.local/share/tur/ / %LOCALAPPDATA%\tur\ (or ~/.tur/) |
| Swarm IPC / Sockets | SQLite Signal DB, Whiteboard, Locks | resolve_runtime_dir() |
/run/user/1000/tur/ / %LOCALAPPDATA%\Temp\tur\ |
| Telemetry & Cache | Graph indexes, Token cost metrics | resolve_cache_dir() |
~/.cache/tur/ / %LOCALAPPDATA%\tur\Cache\ |
| Diagnostic Logs | Session telemetry, daemon traces | resolve_log_dir() |
~/.local/state/tur/log/ / %LOCALAPPDATA%\tur\Logs\ |
Backwards Compatibility¶
- Legacy
~/.tur/Preserved: The resolution pipeline automatically detects and respects existing~/.tur/personas.yamlor~/.tur/personas/directories, guaranteeing zero breakage for existing setups. - Environment Overrides:
TUR_HOME,TUR_DATA_DIR,TUR_RUNTIME_DIR,TUR_CACHE_DIR, andTUR_LOG_DIRtake top precedence, allowing custom deployment paths in CI/CD and sandboxes. - Terrain Isolation (EP-0124): No changes are made to local
<repo>/.tur/resolution.
How to Teach This / Documentation Plan¶
- Update
docs/concepts/harness-integration.mdanddocs/concepts/fractal-memory.mdto document global path resolution and runtime socket locations. - Update
AGENTS.mdto referenceTUR_HOMEenvironment overrides.
Reference Implementation¶
Implemented in src/tur/paths.py and validated via a 13-test matrix in tests/test_paths.py covering MCP context roots,
URI decoding, CWD detection, environment overrides (TUR_HOME, TUR_DATA_DIR, TUR_RUNTIME_DIR, TUR_CACHE_DIR,
TUR_LOG_DIR, TUR_PROJECT_DIR), and container fallback.
Rejected Ideas¶
- Moving Workspace State into OS Data Directories: Strictly rejected. Storing repository memories inside global user directories violates EP-0124 (Terrain Isolation) and prevents version-controlled project memory sharing.
- Writing Custom Platform Branching Logic: Rejected. Maintaining bespoke OS path resolvers violates the Shannon and
Steward principles when
platformdirsis already the battle-tested standard.
Open Questions & Council Directives¶
- Container Fallback Testing (Popper & Bacon): Assert that headless environments with missing
/run/user/<uid>fall back cleanly totempfile.gettempdir() / f"tur-runtime-{uid}"with 100% test coverage. - Resolution: Implemented in
src/tur/paths.pyand verified viatest_resolve_runtime_dir_container_fallbackintests/test_paths.py. - Global Path Predicate Completeness (Steward): Verify that
is_global_path()correctly identifies paths insideplatformdirsruntime, data, cache, and log directories. - Resolution: Fully implemented across all 4 store root getters in
src/tur/paths.pyand verified intests/test_paths.py. - Cache Pruning CLI (
tur-adm purge-cache): Shouldtur-adm purge-cachebe introduced as a dedicated CLI command leveragingresolve_cache_dir()? - Resolution: Deferred to
tur-admmaintenance suite in Phase 3 storage evolution (EP-0125), keeping the low-privilegeturagent CLI clean and non-administrative.
Change Log¶
- 2026-08-26:
- Expanded test coverage across all workspace resolution tiers (MCP context roots, URI parsing, CWD detection, and pure traveler fallback) in
tests/test_paths.py(13/13 tests passing). - Ratified under REV-0006 Council of Giants Implementation Audit.
- Expanded test coverage across all workspace resolution tiers (MCP context roots, URI parsing, CWD detection, and pure traveler fallback) in
- 2026-08-25:
- Implemented in
src/tur/paths.pyand verified with 100% test pass intests/test_paths.py. Promoted status to Implemented. - Integrated Council of Giants Review hardening mandates: container
/run/userfallback, POSIX0700runtime permissions, symmetricTUR_RUNTIME_DIR/TUR_CACHE_DIR/TUR_LOG_DIRenvironment overrides, andis_global_pathcoverage update. - Initial Draft proposing
platformdirsintegration for OS-native directory standards and ephemeral runtime IPC isolation.
- Implemented in