Skip to content

v0.6.0: WebSocket API, Docker host mounts, DRY refactor

Choose a tag to compare

@PleasePrompto PleasePrompto released this 26 Feb 04:52
· 332 commits to main since this release

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 enable generates a token and writes the api section to config. ductor api disable removes it. PyNaCl is an optional dependency (pip install ductor[api]).
  • Zero coupling: The api/ module never imports from bot/ — both transports share the orchestrator independently.
  • Config not auto-injected: The api section 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 config

Docker host directory mounts

Mount host project directories into the Docker sandbox so the LLM can work on your code. (#12)

  • Config: docker.mounts list in config.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_VARS are 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 path

Files module

Shared file handling extracted from bot/ for reuse by both Telegram and API transports.

  • Magic-bytes MIME detection via filetype library (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 on file_access config (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: /status shows 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_MODELS constant made public (was _CLAUDE_MODELS).
  • _log_task_crash added to cache observers.
  • Orphaned service_common.py removed.
  • 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@botname support 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: ignore in 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