Composable Docker-based OpenCode assistant container orchestration for wrapper applications.
Project description
Path2Dream AI Assistants
path2dream_ai_assistants is a Python package for applications that need to run an OpenCode-based assistant inside a Docker container.
The main use case is not a standalone end-user app. The intended user is another service, for example a Telegram bot, web backend, or automation worker, that wants to start a prepared OpenCode container and then call it through published local HTTP ports.
Your application chooses which container plugins it needs, starts the container through this package, and then uses the resulting OpenCode/API endpoints as part of its own product.
What This Package Does
The package provides ContainerBuilderService, which builds a Docker image dynamically, starts a Docker container, and applies a list of plugin services in the order provided by the caller.
Plugins can:
- mount a workspace into the container;
- start OpenCode Server or OpenCode Web;
- persist OpenCode auth, chats, skills, agents, and config;
- expose browser login pages for OpenAI provider auth or Google Drive auth;
- expose upload/download endpoints for wrapper applications;
- install selected OpenCode skills and agents before OpenCode starts.
The package does not hide Docker. Docker is part of the runtime contract: the machine running your wrapper application must have Docker installed and the Docker daemon must be available to the Python process.
Installation
After the package is published:
pip install path2dream_ai_assistants
The PyPI distribution name is path2dream_ai_assistants. Public Python imports currently live under assistant_api.
From a local checkout:
pip install -e .
Basic Usage
This example starts an OpenCode Server container for a wrapper application. The wrapper owns the bot/backend logic; this package only prepares and runs the assistant container.
from pathlib import Path
from assistant_api.container_builder import ContainerBuilderService
from assistant_api.container_builder.container_plugin.inbox_upload_plugin import (
InboxUploadPluginService,
)
from assistant_api.container_builder.container_plugin.local_dir_mount_plugin import (
LocalDirMountPluginService,
)
from assistant_api.container_builder.container_plugin.opencode_persistence_plugin import (
OpenCodePersistencePluginService,
)
from assistant_api.container_builder.container_plugin.opencode_server_plugin import (
OpenCodeServerPluginService,
)
from assistant_api.container_builder.container_plugin.outbox_download_plugin import (
OutboxDownloadPluginService,
)
plugins = [
LocalDirMountPluginService(Path("/srv/my-telegram-bot/assistant-workspace")),
OpenCodePersistencePluginService(config_volume="my_app_opencode_config", data_volume="my_app_opencode_data"),
OpenCodeServerPluginService(host_port=4096),
InboxUploadPluginService(host_port=8090),
OutboxDownloadPluginService(host_port=8091),
]
builder = ContainerBuilderService(
plugins=plugins,
container_name="my-telegram-bot-opencode",
)
running_container = builder.build_and_run()
print(running_container.name)
print("OpenCode API: http://127.0.0.1:4096/")
print("Upload endpoint: http://127.0.0.1:8090/api/inbox/upload")
print("Outbox list endpoint: http://127.0.0.1:8091/api/outbox/list")
After build_and_run() returns, the Docker container is running. Your Telegram bot or backend can call the published host ports. For example, it can send requests to OpenCode Server on http://127.0.0.1:4096/, upload user files through the inbox endpoint, or fetch generated files through the outbox endpoint.
Plugin Order
Plugin order matters because plugins coordinate through typed container state.
Common ordering rules:
- mount plugins should come before plugins that need a workspace mount;
- persistence plugins should come before the runtime that uses the persisted state;
- OpenCode runtime plugins should come before plugins that call the OpenCode API;
- auth helper plugins should come after the OpenCode runtime they validate;
- upload/download plugins should come after a mount plugin.
If a required dependency is missing or ordered incorrectly, plugins are expected to fail fast instead of silently falling back.
Available Plugins
LocalDirMountPluginService
Mounts a local host directory into the container. By default it mounts directly to /workspace. Use this when the wrapper app owns a local workspace directory and wants OpenCode to operate on those files.
from assistant_api.container_builder.container_plugin.local_dir_mount_plugin import (
LocalDirMountPluginService,
)
plugin = LocalDirMountPluginService("/srv/my-bot/workspace")
GoogleDriveMountPluginService
Mounts a Google Drive folder into the container through rclone mount. It exposes a browser login/status/logout service on a configured host port and can optionally show a local folder import UI for initial notes import.
This plugin requires GOOGLE_OAUTH_CLIENT_CREDENTIALS_JSON with a Google OAuth Web client JSON value. It requests Google Drive access for a visible app-owned folder, not full-drive access.
from assistant_api.container_builder.container_plugin.google_drive_mount_plugin import (
GoogleDriveMountPluginService,
)
plugin = GoogleDriveMountPluginService(
host_port=4322,
drive_folder_name="notes-assistant",
enable_local_folder_import=True,
)
GoogleDrivePersistencePluginService
Persists Google Drive rclone config and cache state in Docker named volumes. Compose it with GoogleDriveMountPluginService when Google Drive auth should survive container restart, rebuild, and recreate.
from assistant_api.container_builder.container_plugin.google_drive_persistence_plugin import (
GoogleDrivePersistencePluginService,
)
plugin = GoogleDrivePersistencePluginService(
config_volume="my_app_google_drive_config",
cache_volume="my_app_google_drive_cache",
)
OpenCodeServerPluginService
Starts headless opencode serve inside the container and publishes it to a host port. Use this for wrapper apps that need an API-style OpenCode runtime without exposing the OpenCode Web UI as the primary interface.
from assistant_api.container_builder.container_plugin.opencode_server_plugin import (
OpenCodeServerPluginService,
)
plugin = OpenCodeServerPluginService(host_port=4096)
OpenCodeWebServerPluginService
Starts opencode web inside the container and publishes it to a host port. Use this when the wrapper app wants to expose or open the OpenCode Web UI.
from assistant_api.container_builder.container_plugin.opencode_web_server_plugin import (
OpenCodeWebServerPluginService,
)
plugin = OpenCodeWebServerPluginService(host_port=4096)
OpenCodePersistencePluginService
Persists OpenCode state in Docker named volumes. By default it persists provider auth, chat/session history, global OpenCode config artifacts, skills, and agents.
from assistant_api.container_builder.container_plugin.opencode_persistence_plugin import (
OpenCodePersistencePluginService,
)
plugin = OpenCodePersistencePluginService(
config_volume="my_app_opencode_config",
data_volume="my_app_opencode_data",
)
You can disable individual persistence categories through constructor flags such as persist_auth=False, persist_chat_history=False, persist_skills=False, or persist_agents=False.
OpenAIProviderLoginPluginService
Adds a browser login page and status endpoint for OpenCode's OpenAI provider auth flow. It uses the OpenCode API inside the container, so it must be composed after OpenCodeServerPluginService or another plugin that records OpenCode runtime metadata.
from assistant_api.container_builder.container_plugin.openai_provider_login_plugin import (
OpenAIProviderLoginPluginService,
)
plugin = OpenAIProviderLoginPluginService(host_port=4323)
After startup, open http://127.0.0.1:4323/login to complete OpenAI provider login in the browser. The status endpoint is available at http://127.0.0.1:4323/status.
InboxUploadPluginService
Adds an HTTP endpoint for uploading files into <mounted_workspace>/inbox. Wrapper apps can use this to pass user-provided files into the assistant container.
from assistant_api.container_builder.container_plugin.inbox_upload_plugin import (
InboxUploadPluginService,
)
plugin = InboxUploadPluginService(host_port=8090)
Default endpoint: POST /api/inbox/upload with multipart field file.
OutboxDownloadPluginService
Adds HTTP endpoints for listing and downloading files from <mounted_workspace>/outbox. Downloading a file removes it from the outbox after successful transfer.
from assistant_api.container_builder.container_plugin.outbox_download_plugin import (
OutboxDownloadPluginService,
)
plugin = OutboxDownloadPluginService(host_port=8091)
Default endpoints:
GET /api/outbox/list;GET /api/outbox/download/{filename}.
SkillsSyncPluginService
Installs selected OpenCode artifact bundles from an external repository into the container's global OpenCode config directory before OpenCode starts. Use this to preload agents, skills, AGENTS.md, and OpenCode config for the assistant persona your wrapper app needs.
from assistant_api.container_builder.container_plugin.skills_sync_plugin import (
SkillsSyncPluginService,
)
plugin = SkillsSyncPluginService(["yid-notes-assistant"])
Example: Telegram Bot Architecture
A typical Telegram bot integration looks like this:
- The bot process starts.
- The bot creates a plugin list for the assistant container.
- The bot calls
ContainerBuilderService(...).build_and_run(). - The container starts OpenCode and any configured helper endpoints.
- Telegram messages are handled by the bot's own code.
- When the bot needs AI work, it calls the OpenCode host port exposed by the container.
- When users send files, the bot can upload them through the inbox endpoint.
- When OpenCode produces files, the bot can read them from the outbox endpoint and send them back to the user.
In this architecture, this package is the container orchestration layer. It is not the Telegram bot framework, not the user-facing product, and not a replacement for your application logic.
Public API Boundary
Use the documented service imports under assistant_api.container_builder and assistant_api.container_builder.container_plugin.*.
Repository helper commands and local development entrypoints are examples for working in this checkout. They are not the intended public API for applications that install the package.
Development
This repository uses uv for local development.
uv run pytest
Some manual tests require external credentials, browser login, or live third-party state and are excluded from the default pytest run.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file path2dream_ai_assistants-0.3.0.tar.gz.
File metadata
- Download URL: path2dream_ai_assistants-0.3.0.tar.gz
- Upload date:
- Size: 320.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be8eb2ebab5e31e257500bbfe250822cf2fa900dde5ec91f9a189925a22b1d89
|
|
| MD5 |
e4b3119fb14d1f76a04945737c2dbebe
|
|
| BLAKE2b-256 |
dcb7f69bf9560da49a66de6752542e919fc601a8a300e1abc54799cea0da0997
|
Provenance
The following attestation bundles were made for path2dream_ai_assistants-0.3.0.tar.gz:
Publisher:
publish.yml on dimitree54/path2dream_assistants
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
path2dream_ai_assistants-0.3.0.tar.gz -
Subject digest:
be8eb2ebab5e31e257500bbfe250822cf2fa900dde5ec91f9a189925a22b1d89 - Sigstore transparency entry: 1437743920
- Sigstore integration time:
-
Permalink:
dimitree54/path2dream_assistants@7bfb7c14ae8f6cb0a0dc6e4b8a9456e410af1ad4 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/dimitree54
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7bfb7c14ae8f6cb0a0dc6e4b8a9456e410af1ad4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file path2dream_ai_assistants-0.3.0-py3-none-any.whl.
File metadata
- Download URL: path2dream_ai_assistants-0.3.0-py3-none-any.whl
- Upload date:
- Size: 247.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f498857105cca9b7f87589c77403ca3a796b32cb00fec8e3a0c470a7930af982
|
|
| MD5 |
619a0ba50520a3ec9ecfb8967ae5e50b
|
|
| BLAKE2b-256 |
dc1ccc339cad777594ccc17af6e435d5edb9f7b861e67c049e117ff1651b5ab1
|
Provenance
The following attestation bundles were made for path2dream_ai_assistants-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on dimitree54/path2dream_assistants
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
path2dream_ai_assistants-0.3.0-py3-none-any.whl -
Subject digest:
f498857105cca9b7f87589c77403ca3a796b32cb00fec8e3a0c470a7930af982 - Sigstore transparency entry: 1437743924
- Sigstore integration time:
-
Permalink:
dimitree54/path2dream_assistants@7bfb7c14ae8f6cb0a0dc6e4b8a9456e410af1ad4 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/dimitree54
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7bfb7c14ae8f6cb0a0dc6e4b8a9456e410af1ad4 -
Trigger Event:
push
-
Statement type: