Oh-My-Codex State Management: Architecture of the .omx Directory
Oh-my-codex persists all runtime state in a hidden .omx directory using a hierarchical layout that isolates global mode data, per-session snapshots, and team orchestration artifacts while centralizing path resolution through utility functions.
The oh-my-codex repository implements a hierarchical oh-my-codex state management system that stores all runtime data in a hidden .omx directory at the project root. This architecture isolates global mode state, session-specific snapshots, and team coordination artifacts while providing deterministic path resolution through centralized utility functions.
The Hierarchical .omx Directory Layout
The .omx folder is created lazily upon the first state-writing operation. Its structure isolates distinct runtime concerns into specific subdirectories and files:
.omx/state/– Stores core mode state JSON files (e.g.,autopilot-state.json,team-state.json,ralph-state.json) directly under this directory..omx/state/sessions/<session-id>/– Contains session-scoped state copies used by the MCP state-server to isolate interactive sessions..omx/state/team/<team-name>/– Houses all team orchestration artifacts including configuration, worker directories, tasks, mailboxes, and dispatch queues..omx/notepad.md– Free-form session notes written by leaders or sub-agents..omx/project-memory.json– Cross-session project-wide memory acting as a persistent key-value store..omx/plans/– Persisted product-requirement documents (prd-*.md) and test specifications..omx/logs/– Operational logs for diagnostics such as MCP request logs and notification cooldowns.
Core State Resolution and Path Utilities
All paths are generated by centralized utilities to prevent hard-coded strings. The omxStateDir function in src/utils/paths.ts establishes the root state directory:
import { join } from "path";
/** oh-my-codex state directory (.omx/state/) */
export function omxStateDir(projectRoot?: string): string {
return join(projectRoot || process.cwd(), ".omx", "state");
}
The MCP state server constructs concrete file names using getStatePath from src/mcp/state-paths.ts, which accepts a mode name, optional working directory, and optional session ID:
export function getStatePath(
mode: string,
workingDirectory?: string,
sessionId?: string,
): string {
return join(getStateDir(workingDirectory, sessionId), getStateFilename(mode));
}
This function returns a path such as .omx/state/team-state.json for global state or .omx/state/sessions/abc123/team-state.json for session-scoped data.
Session Scoping and Fallback Logic
The architecture supports read-scoped lookup that prefers session data but falls back to the root directory when a session file does not exist. This guarantees backward compatibility with scripts expecting only global state files.
The resolution logic in src/mcp/state-paths.ts implements a precedence system:
// Resolve reading precedence – root first, then session overrides.
for (const dir of [...readDirs].reverse()) {
const scope: StateFileScope = dir === rootDir ? 'root' : 'session';
// ... read operation
}
The listModeStateFilesWithScopePreference function leverages this loop to return active state files with their appropriate scope metadata, ensuring deterministic state retrieval across concurrent sessions.
Team Orchestration State Structure
When a $team workflow initiates, the system creates a dedicated subtree under .omx/state/team/<team-name>/. The layout mirrors the logical entities of the team runtime:
.omx/state/team/<team-name>/
├─ config.json # team configuration
├─ manifest.v2.json # static worker manifest
├─ workers/
│ └─ worker-1/
│ ├─ inbox.md # inbound messages
│ └─ status.json # worker status
├─ tasks/
│ └─ task-42.json # task definitions
├─ mailbox/
│ └─ leader-fixed.json # leadership coordination
├─ dispatch/
│ └─ requests.json # dispatch queue
├─ events/
│ └─ events.ndjson # event stream
└─ snapshots/
├─ monitor-snapshot.json
└─ team-phase.json
All team state operations are handled by the team state module in src/team/state.ts, which imports omxStateDir to locate the root and constructs paths via join(omxStateDir(), 'team', teamName, ...).
Auxiliary Runtime Files
Beyond mode and team state, the .omx directory contains several auxiliary files for operational continuity:
idle-notif-cooldown.json– Throttling data for idle notifications.dispatch-cooldown.json– Throttling for dispatch-based messages.subagent-tracking.json– Ledger of native sub-agent activity used byomx ralph.
These files are accessed directly via MCP tools (state_read, state_write, state_clear) defined in src/mcp/state-server.ts and documented in the project's AGENTS.md contract.
Practical Code Examples
Retrieve the Global State Directory
import { omxStateDir } from "./utils/paths.js";
const stateRoot = omxStateDir(); // → "/my/project/.omx/state"
console.log(stateRoot);
Write Custom Mode State
When using the MCP client, state_write automatically resolves the path via getStatePath:
import { state_write } from "@modelcontextprotocol/sdk/client";
await state_write({
mode: "my-mode",
active: true,
iteration: 1,
started_at: new Date().toISOString(),
});
This creates or updates .omx/state/my-mode-state.json.
Create a Team Worker Inbox
import { join } from "path";
import { writeFile } from "fs/promises";
import { omxStateDir } from "./utils/paths.js";
const teamRoot = join(omxStateDir(), "team", "alpha");
const inboxPath = join(teamRoot, "workers", "worker-1", "inbox.md");
await writeFile(inboxPath, "Welcome worker-1!\n");
List Active Mode States with Scope Preference
import { listModeStateFilesWithScopePreference } from "./mcp/state-paths.js";
const activeFiles = await listModeStateFilesWithScopePreference();
console.log(activeFiles.map(f => `${f.mode}: ${f.path}`));
// Output: my-mode: /project/.omx/state/sessions/abc/my-mode-state.json
Summary
- Oh-my-codex centralizes all runtime state in a hidden
.omxdirectory at the project root. - The
.omx/state/directory holds global mode JSON files, while.omx/state/sessions/<id>/isolates session-specific data. - Team orchestration stores artifacts under
.omx/state/team/<team-name>/, managed bysrc/team/state.ts. - Path resolution is deterministic via
omxStateDir()insrc/utils/paths.tsandgetStatePath()insrc/mcp/state-paths.ts. - The MCP state server supports read-scoped lookup with fallback to root state for backward compatibility.
- Auxiliary files like
project-memory.jsonandnotepad.mdpersist data across sessions and agent restarts.
Frequently Asked Questions
What is the purpose of the .omx directory in oh-my-codex?
The .omx directory serves as the centralized state store for oh-my-codex, housing all transient runtime information including mode configurations, session snapshots, team coordination data, and operational logs. It is created lazily upon the first state write and uses a hierarchical structure to isolate concerns while remaining discoverable via utility functions like omxStateDir().
How does oh-my-codex handle concurrent session states?
The MCP state server creates isolated subdirectories under .omx/state/sessions/<session-id>/ for each interactive session. When reading state, the server implements a fallback mechanism that checks session-scoped files first, then falls back to the global .omx/state/ directory if the file does not exist, ensuring both isolation and backward compatibility.
Where are team orchestration files stored?
Team-related state resides under .omx/state/team/<team-name>/, containing config.json, manifest.v2.json, worker inboxes in workers/<name>/inbox.md, task definitions, and dispatch queues. The team state module (src/team/state.ts) manages these paths by joining omxStateDir() with the team-specific subdirectory structure.
How are state file paths generated to ensure consistency?
All paths are constructed through centralized utilities to eliminate hard-coded strings. The omxStateDir() function in src/utils/paths.ts returns the root state directory, while getStatePath(mode, cwd, sessionId) in src/mcp/state-paths.ts builds complete file paths following the convention <mode>-state.json. This ensures deterministic resolution regardless of the execution context.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →