Archon Directories
This document explains the Archon directory structure and configuration system for developers contributing to or extending Archon.
Overview
Section titled “Overview”Archon provides a unified directory and configuration system with:
- Consistent paths across all platforms (Mac, Linux, Windows, Docker)
- Configuration precedence chain (env > global > repo > defaults)
- Workflow engine integration with YAML definitions in
.archon/workflows/
Directory Structure
Section titled “Directory Structure”User-Level: ~/.archon/
Section titled “User-Level: ~/.archon/”~/.archon/ # ARCHON_HOME├── workspaces/ # Per-project storage (project-centric layout)│ ├── <owner>/<repo>/ # a registered repo with a remote│ ├── _local/<basename>/ # a no-remote local git repo│ ├── _folder/<slug>/ # a folder project (non-git; runs in place)│ └── _cwd/<basename>/ # an unregistered working directory│ ├── source/ # Clone or symlink -> local path (repo kinds only)│ ├── worktrees/ # Git worktrees for this project (repo kinds only)│ ├── artifacts/ # Workflow artifacts — NEVER in git│ │ ├── runs/<run-id>/ # $ARTIFACTS_DIR for one run│ │ │ └── nodes/ # typed output sidecars (<id>.md + <id>.meta.json)│ │ ├── scopes/<workflow>/<scope>/ # cross-invocation artifacts (persist_session)│ │ └── uploads/<conv-id>/ # Web UI file uploads (ephemeral)│ ├── logs/<run-id>.jsonl # Workflow execution logs│ └── state/ # $STATE_DIR — cross-run state, shared per project├── workflows/ commands/ scripts/ # Home-scoped ("global") definitions├── worktrees/ # Legacy global worktrees (repos not in workspaces/)├── vendor/codex/ # Codex native binary (binary builds, user-placed)├── web-dist/<version>/ # Cached web UI dist (archon serve, binary only)├── update-check.json # Update check cache (binary builds only, 24h TTL)├── tier-notice.json # One-time tier-default notice state (CLI, per version)├── credential-key # Auto-provisioned per-user credential encryption key├── archon.db # SQLite database (when DATABASE_URL is unset)└── config.yaml # Global user configurationPurpose:
workspaces/<project>/- Everything one project produces. The project segment is resolved once per run from the codebase identity:owner/repofor a repo with a remote,_local/<basename>for a no-remote local repo,_folder/<slug>for a folder project, and_cwd/<basename>when a run has no registered codebase at all. Folder projects and_cwdprojects have nosource/orworktrees/— they run in place.workspaces/<project>/artifacts/- Run output.$ARTIFACTS_DIRisartifacts/runs/<run-id>/.workspaces/<project>/logs/- One JSONL execution log per run.workspaces/<project>/state/-$STATE_DIR. Cross-run workflow state, shared by every workflow in the project. Survives worktree teardown; never visible to git.worktrees/- Legacy fallback for repos not registered underworkspaces/config.yaml- Non-secret user preferences
Each run also records the project root it resolved in workflow_runs.output_root, so an
old run’s artifacts stay addressable even if the codebase is later renamed.
Repo-Level: .archon/
Section titled “Repo-Level: .archon/”any-repo/.archon/├── commands/ # Custom commands│ ├── plan.md│ └── execute.md├── workflows/ # Workflow definitions (YAML files)│ └── pr-review.yaml├── scripts/ # Named scripts for script: nodes (.ts/.js for bun, .py for uv)└── config.yaml # Repo-specific configurationPurpose:
commands/- Slash commands (auto-loaded on clone)workflows/- YAML workflow definitions in flat, one-level grouped, or exact<pack>/<workflow>/packaged layoutsscripts/- Named scripts referenced byscript:nodesconfig.yaml- Project-specific settings
The repo directory holds source only. Everything a run produces lives under
~/.archon/workspaces/<project>/.
Legacy: .archon/state/
Section titled “Legacy: .archon/state/”.archon/state/ was a prompt-level convention with no engine support — workflows did
mkdir -p .archon/state relative to cwd. It had two problems: inside an isolated run that
path is the worktree, so the “cross-run memory” was destroyed at cleanup; and Archon
never writes a .gitignore, so in a user’s repository the directory was fully stageable.
It is replaced by $STATE_DIR. If Archon finds a legacy
directory when a run starts it logs one warning with the exact move command and moves
nothing:
mv <repo>/.archon/state/* ~/.archon/workspaces/<project>/state/Then replace .archon/state/ with $STATE_DIR/ in the workflow’s prompts and scripts, and
delete any mkdir -p .archon/state — the executor pre-creates $STATE_DIR.
Docker: /.archon/
Section titled “Docker: /.archon/”In Docker containers, the Archon home is fixed at /.archon/ (root level). This is:
- Mounted as a named volume for persistence
- Not overridable by end users (simplifies container setup)
Path Resolution
Section titled “Path Resolution”All path resolution is centralized in packages/paths/src/archon-paths.ts (@archon/paths).
Core Functions
Section titled “Core Functions”// Get the Archon home directorygetArchonHome(): string// Returns: ~/.archon (local) or /.archon (Docker)
// Get workspaces directorygetArchonWorkspacesPath(): string// Returns: ${ARCHON_HOME}/workspaces
// Get global worktrees directory (legacy fallback)getArchonWorktreesPath(): string// Returns: ${ARCHON_HOME}/worktrees
// Get global config pathgetArchonConfigPath(): string// Returns: ${ARCHON_HOME}/config.yaml
// Get cached web UI distribution directory for a given versiongetWebDistDir(version: string): string// Returns: ${ARCHON_HOME}/web-dist/${version}
// Get command folder search paths (priority order)getCommandFolderSearchPaths(configuredFolder?: string): string[]// Returns: ['.archon/commands'] + configuredFolder if specifiedDocker Detection
Section titled “Docker Detection”function isDocker(): boolean { return ( process.env.WORKSPACE_PATH === '/workspace' || (process.env.HOME === '/root' && Boolean(process.env.WORKSPACE_PATH)) || process.env.ARCHON_DOCKER === 'true' );}WSL Detection
Section titled “WSL Detection”function isWSL(): boolean { // Either signal is sufficient: // - WSL_DISTRO_NAME env var is set (always true inside a WSL distro) // - /proc/sys/kernel/osrelease contains "microsoft" (lower-cased) // The /proc read is wrapped in try/catch: on environments without a // readable /proc (macOS, Windows, restricted sandboxes) it conservatively // returns false.}
function getWSLDistroName(): string | undefined { // Returns the WSL_DISTRO_NAME env var if present, otherwise undefined. // Only reads the env var — isWSL() may still be true via the /proc // fallback while this returns undefined.}Used to build Windows-host-friendly vscode://vscode-remote/wsl+<distro>/... IDE URIs when Archon runs inside WSL (surfaced as is_wsl / wsl_distro on /api/health).
Platform-Specific Paths
Section titled “Platform-Specific Paths”| Platform | getArchonHome() |
|---|---|
| macOS | /Users/<username>/.archon |
| Linux | /home/<username>/.archon |
| Windows | C:\Users\<username>\.archon |
| Docker | /.archon |
Configuration System
Section titled “Configuration System”Precedence Chain
Section titled “Precedence Chain”Configuration is resolved in this order (highest to lowest priority):
- Environment Variables - Secrets, deployment-specific
- Global Config (
~/.archon/config.yaml) - User preferences - Repo Config (
.archon/config.yaml) - Project-specific - Built-in Defaults - Hardcoded in
packages/core/src/config/config-types.ts
Config Loading
Section titled “Config Loading”// Load merged config for a repoconst config = await loadConfig(repoPath);
// Load just global configconst globalConfig = await loadGlobalConfig();
// Load just repo configconst repoConfig = await loadRepoConfig(repoPath);Configuration Options
Section titled “Configuration Options”Key configuration options:
| Option | Env Override | Default |
|---|---|---|
ARCHON_HOME | ARCHON_HOME | ~/.archon |
| Default AI Assistant | DEFAULT_AI_ASSISTANT | claude |
| Telegram Streaming | TELEGRAM_STREAMING_MODE | stream |
| Discord Streaming | DISCORD_STREAMING_MODE | batch |
| Slack Streaming | SLACK_STREAMING_MODE | batch |
Command Folders
Section titled “Command Folders”Command detection searches in priority order:
.archon/commands/- Always searched first- Configured folder from
commands.folderin.archon/config.yaml(if specified)
Example configuration:
commands: folder: .claude/commands/archon # Additional folder to searchExtension Points
Section titled “Extension Points”Adding New Paths
Section titled “Adding New Paths”To add a new managed directory:
- Add function to
packages/paths/src/archon-paths.ts:
export function getArchonNewPath(): string { return join(getArchonHome(), 'new-directory');}- Update Docker setup in
Dockerfile - Update volume mounts in
docker-compose.yml - Add tests in
packages/paths/src/archon-paths.test.ts
Adding Config Options
Section titled “Adding Config Options”To add new configuration options:
- Add type to
packages/core/src/config/config-types.ts:
export interface GlobalConfig { // ...existing newFeature?: { enabled?: boolean; setting?: string; };}- Add default in
getDefaults()function - Use via
loadConfig()in your code
Design Decisions
Section titled “Design Decisions”Why ~/.archon/ instead of ~/.config/archon/?
Section titled “Why ~/.archon/ instead of ~/.config/archon/?”- Simpler path (fewer nested directories)
- Follows Claude Code pattern (
~/.claude/) - Cross-platform without XDG complexity
- Easy to find and manage manually
Why YAML for config?
Section titled “Why YAML for config?”- Bun has native support (via
yamlpackage) - Supports comments (unlike JSON)
- Workflow definitions use YAML
- Human-readable and editable
Why fixed Docker paths?
Section titled “Why fixed Docker paths?”- Simplifies container setup
- Predictable volume mounts
- No user confusion about env vars in containers
- Matches convention (apps use fixed paths in containers)
Why config precedence chain?
Section titled “Why config precedence chain?”- Mirrors git config pattern (familiar to developers)
- Secrets stay in env vars (security)
- User preferences in global config (portable)
- Project settings in repo config (version-controlled)
UI Integration
Section titled “UI Integration”The config type system is designed for:
- Web UI configuration
- API-driven config updates
- Real-time config validation