workspace/
June 12, 2026 ยท View on GitHub
Workspace/home-directory management for ~/.ductor.
Files
paths.py: immutableDuctorPaths+resolve_paths()init.py: workspace init pipeline, zone copy rules, rule sync, runtime notice injectionrules_selector.py: auth-aware RULES template selection/deployment + stale file cleanupcron_tasks.py: create/list/delete cron-task foldersskill_sync.py: cross-tool skill sync and bundled-skill syncloader.py: safe file readers
DuctorPaths
Important runtime paths:
ductor_home:~/.ductor(default)workspace:~/.ductor/workspaceconfig_path:~/.ductor/config/config.jsonsessions_path:~/.ductor/sessions.jsonnamed_sessions_path:~/.ductor/named_sessions.jsonenv_file:~/.ductor/.envtasks_registry_path:~/.ductor/tasks.jsonchat_activity_path:~/.ductor/chat_activity.jsonstartup_state_path:~/.ductor/startup_state.jsoninflight_turns_path:~/.ductor/inflight_turns.jsoncron_jobs_path:~/.ductor/cron_jobs.jsonwebhooks_path:~/.ductor/webhooks.jsonlogs_dir:~/.ductor/logscron_tasks_dir:~/.ductor/workspace/cron_taskstasks_dir:~/.ductor/workspace/tasksapi_files_dir:~/.ductor/workspace/api_filesskills_dir:~/.ductor/workspace/skillsbundled_skills_dir: package_home_defaults/workspace/skills
init_workspace() order
- migrate legacy
workspace/tasks -> workspace/cron_tasks sync_bundled_skills(paths)_sync_home_defaults(paths)- ensure required directories
RulesSelector(paths).deploy_rules()ensure_task_rule_files(paths.cron_tasks_dir)sync_rule_files(paths.workspace)_smart_merge_config(paths)_clean_orphan_symlinks(paths)sync_skills(paths)
Idempotent by design (called from multiple startup paths).
Directory creation note:
workspace/api_files/is not in_REQUIRED_DIRS; it is created lazily on first API upload viaprepare_destination(...).workspace/tasks/is part of_REQUIRED_DIRSand always created (used by sharedTaskHubtask folders).- sub-agent homes do not create
logs/by default; all agents write to the main home log file~/.ductor/logs/agent.log.
Zone copy rules (_walk_and_copy)
Zone 2 (always overwritten)
CLAUDE.md,AGENTS.md,GEMINI.md.pyfiles in:workspace/tools/cron_tools/workspace/tools/webhook_tools/workspace/tools/agent_tools/workspace/tools/task_tools/
Special case:
- when copying a template
CLAUDE.md, init also writes mirroredAGENTS.mdandGEMINI.mdin same target dir.
Zone 3 (seed once)
- all other files: copied only when missing.
Skipped template files (handled by RulesSelector):
RULES.mdRULES-claude-only.mdRULES-codex-only.mdRULES-gemini-only.mdRULES-all-clis.md
RULES deployment (rules_selector.py)
Template variants:
RULES.mdRULES-claude-only.mdRULES-codex-only.mdRULES-gemini-only.mdRULES-all-clis.md
Variant selection:
all-cliswhen 2+ providers are authenticatedcodex-onlywhen only Codexgemini-onlywhen only Gemini- otherwise
claude-only
Deployment outputs per authenticated provider:
- Claude ->
CLAUDE.md - Codex ->
AGENTS.md - Gemini ->
GEMINI.md
Antigravity is a CLI provider, but workspace rule deployment has no dedicated Antigravity rule-file target; it still deploys only the Claude, Codex, and Gemini rule-file names above.
Cleanup removes stale provider files for unauthenticated providers, except inside workspace/cron_tasks/ (user-owned task rules).
Rule sync (sync_rule_files)
Recursive mtime-based sync for:
CLAUDE.mdAGENTS.mdGEMINI.md
Per directory:
- pick newest existing file
- copy to outdated existing siblings
- missing siblings are generally not created, except task-folder backfill via
ensure_task_rule_files(...)
Background watcher: watch_rule_files(workspace, interval=10s).
Watcher detail per cycle:
ensure_task_rule_files(cron_tasks_dir)backfills missing provider rule files in existing task folders.sync_rule_files(workspace)propagates newest content to older sibling rule files.
Runtime environment injection
inject_runtime_environment(paths, docker_container=...) appends two sections to each existing workspace rule file (CLAUDE.md, AGENTS.md, GEMINI.md):
## Multi-Agent Identity(main/sub-agent context + communication hints)- Docker mode notice (
/ductormount) - host mode warning (no sandbox)
Duplicate prevention: injection is skipped when either marker already exists (## Multi-Agent Identity or ## Runtime Environment).
Cron task folders (cron_tasks.py)
create_cron_task(...) creates:
cron_tasks/<safe_name>/
CLAUDE.md # only if Claude authenticated
AGENTS.md # only if Codex authenticated
GEMINI.md # only if Gemini authenticated
TASK_DESCRIPTION.md
<safe_name>_MEMORY.md
scripts/
Rule file selection is based on which provider rule files exist in the parent cron_tasks/ directory (deployed by RulesSelector during workspace init). Falls back to CLAUDE.md when no parent rule files are found.
Path traversal protection is enforced for create/delete operations.
sync_rule_files() itself only updates already-existing rule files by mtime. Missing task-folder rule files are created by ensure_task_rule_files(...) in init and watcher cycles.
Skill sync summary
sync_skills() syncs between:
~/.ductor/workspace/skills~/.claude/skills~/.codex/skills~/.gemini/skills
Default mode uses symlinks/junctions. Docker mode uses managed directory copies (.ductor_managed) so paths resolve inside container namespace.
See docs/modules/skill_system.md.
Loader helpers
read_file(path) -> str | Noneread_mainmemory(paths) -> str