v0.6.0: WebSocket API, Docker host mounts, DRY refactor
ductor v0.6.0
WebSocket API server for direct app connections, Docker host directory mounts, fire-and-forget background tasks, and a major DRY refactor across the entire codebase.
WebSocket API server (beta)
New direct connection transport alongside Telegram — designed for the upcoming ductor mobile app.
- E2E encryption: NaCl Box (Curve25519 + XSalsa20-Poly1305) with ephemeral keypairs per connection. Forward secrecy by design.
- Bearer-auth HTTP endpoints:
/files(list),/files/<path>(download),/upload(multipart). - Gated behind explicit opt-in:
ductor api enablegenerates a token and writes theapisection to config.ductor api disableremoves it. PyNaCl is an optional dependency (pip install ductor[api]). - Zero coupling: The
api/module never imports frombot/— both transports share the orchestrator independently. - Config not auto-injected: The
apisection is excluded from deep-merge, so existing configs are never modified without explicit user action.
ductor api enable # generates token, installs PyNaCl hint
ductor api disable # removes API configDocker host directory mounts
Mount host project directories into the Docker sandbox so the LLM can work on your code. (#12)
- Config:
docker.mountslist inconfig.json— paths are resolved, deduplicated, and mounted at/mnt/<basename>. - CLI commands:
ductor docker mount <path>,ductor docker unmount <path>,ductor docker mounts. - Cross-platform:
~and$ENV_VARSare expanded. Windows-unsafe characters are stripped from container-side names. - Collision handling: Duplicate basenames get automatic suffixes (
proj,proj_2,proj_3). - Non-existent paths in config are silently skipped at container start (no crash).
ductor docker mount ~/projects/myapp # -> /mnt/myapp inside container
ductor docker mount ~/projects/api # -> /mnt/api inside container
ductor docker mounts # list all mounts with status
ductor docker unmount myapp # remove by basename or full pathFiles module
Shared file handling extracted from bot/ for reuse by both Telegram and API transports.
- Magic-bytes MIME detection via
filetypelibrary (new core dependency) with extension fallback. guess_mime(): Single entry point for MIME detection — magic bytes first, then extension table.allowed_roots(): Centralized file access policy based onfile_accessconfig (all,workspace,none).- Video/audio native upload: Telegram sends video and audio files natively with fallback to document.
- Windows-safe filename sanitization: Strips
<>:"|?*from filenames.
Background tasks
New /bg command for fire-and-forget tasks that run alongside the conversation.
BackgroundObserver: Manages concurrent background tasks with unique IDs.- Notification delivery: Task results are sent back to the chat when complete.
- Active task listing:
/statusshows running background tasks.
Upgrade pipeline
/upgrade is now more reliable with retry logic and version verification. (#8)
perform_upgrade_pipeline()replaces inline subprocess upgrade logic.- PyPI cache-busting (
fresh=True) reduces CDN staleness on version checks. - Retry with verification: After pip reports success, the installed version is polled before restarting.
Abort word expansion
Added missing stop words for more responsive abort detection:
- English:
esc,hold - German:
aufhören
DRY refactor
8 new shared modules extracted from duplicated patterns across the codebase. 2317 tests passing.
| Module | Purpose |
|---|---|
text/response_format |
Neutral formatting (moved from bot/) |
infra/file_watcher |
Mtime-based file polling |
infra/task_runner |
One-shot CLI execution |
infra/json_store |
Atomic JSON persistence |
infra/service_base |
Service backend helpers |
infra/base_observer |
Observer lifecycle ABC |
cli/model_cache |
Cache base classes |
cli/executor |
Subprocess execution |
Additional cleanup:
CLAUDE_MODELSconstant made public (was_CLAUDE_MODELS)._log_task_crashadded to cache observers.- Orphaned
service_common.pyremoved. - Recursive cleanup for date-based subdirectories (
api_files,telegram_files).
GitHub issue templates
Structured YAML issue forms for bug reports and feature requests with validation, dropdowns, and required fields.
Other fixes
- Fail-closed
file_access: Unknown config values now deny access instead of allowing it. /stop@botnamesupport in group chats.- CancelledError propagation fix in TypingContext.
- Shutdown kills active CLI processes before cleanup.
- Async stdin feed for CLI providers (fixes Windows ProactorEventLoop edge cases).
- mypy fixes: Removed stale
type: ignorein model cache, fixed variable shadowing in commands.
Backward compatible
No breaking config changes. docker.mounts defaults to []. The api section is never auto-written. filetype is pulled in automatically by pip install --upgrade ductor. All existing session, cron, and webhook data loads without modification.
Upgrade
ductor upgrade
# or
pip install --upgrade ductor