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β β β βββ .archon/node-output-spills/ # engine-owned oversized shell handoffsβ β β β βββ *.nodeoutputβ β β βββ 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βββ temp/ # Ephemeral scratch (per-simulation dry-run dirs; removed when the run ends)βββ 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)βββ install.json # Last compiled CLI path and version (discovery hint)βββ 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>/. Oversized values passed to shell nodes are retained in the engine-owned.archon/node-output-spills/child so concurrent runs never share the deferred read and workflow-authored root files remain untouched. Archon currently retains filesystem run artifacts until the operator removes them;archon workflow cleanupdeletes old database run records, not these directories.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/install.json- Discovery metadata for the last compiled Archon invoked. GUI and service consumers may use its absolutebinarypath when the user has not configured one explicitly. Source/Bun runs do not write this file.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 the compiled CLI discovery manifest pathgetInstallManifestPath(): string// Returns: ${ARCHON_HOME}/install.json
// 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