Skip to main content

Framework-agnostic Python agent containerization CLI for Dank Cloud

Project description

dank-py hero

dank-py

🐍   📦   🌐   📡

Framework-agnostic Python CLI for turning existing agent code into Dockerized HTTP microservices with a consistent runtime contract.

PyPI Dank Cloud

Python Runtime License API Observability

PyPI   •   Dank Cloud

Turn existing Python agents into production-ready microservices in two commands, with no agent-code rewrites.

  • ⚡ no code rewrites required
  • 🌐 standardized HTTP runtime contract
  • 🧪 repeatable dependency locking + validation
  • 📡 built-in observability (status, metrics, logs, traces)
  • 📦 optional multi-agent bundling for runtime efficiency

[!NOTE] ☁️ If you want managed infrastructure instead of self-hosting containers, use Dank Cloud.
Dank Cloud can onboard directly from your GitHub repo and handles packaging, deploys, scaling, auth, logging/tracing & monitoring, and supporting infra (like hosted vector DB + MCP) for you.

  • 🛠️ dank-py: local/self-hosted packaging and runtime control.
  • 🚀 Dank Cloud: managed microservice deployment and operations, built on top of dank-py.

🗂️ Table of Contents

🧩 Why dank-py

  • 🧩 Works with existing agent code
    • Framework-agnostic support across LangChain, LangGraph, CrewAI, PydanticAI, LlamaIndex, or custom OpenAI/SDK implementations.
    • Auto-inspects entrypoints and I/O hints to bootstrap dank.config.json.
  • 🛡️ Production-ready runtime out of the box
    • Consistent endpoints (/health, /prompt, /status, /metrics, /logs, /traces).
    • Input/output contract validation and strict output enforcement.
    • Native async/sync invocation handling for agent callables and methods.
    • Request tracing with trace IDs, per-agent log streams, and trace retrieval endpoints.
  • 🧪 Reliable build and dependency flow
    • Resolver-based lock generation (requirements.lock.txt).
    • Isolated validation in temporary virtual environments before build/run.
    • Build and production build workflows for local iteration and release pipelines.
  • 📦 Flexible multi-agent deployment
    • Run each agent in its own container, or bundle agents into one container with header-based routing.
    • Reduce footprint for compatible agents while keeping per-agent observability.

⚡ In 2 Commands

dank-py auto-init --strict
dank-py run

That flow will:

  1. inspect your project and generate dank.config.json,
  2. infer and lock dependencies,
  3. validate agents in an isolated environment,
  4. build and run containerized agent service(s).

🏗️ Architecture

flowchart LR
    A["Existing Python Agent Code"] --> B["dank-py auto-init"]
    B --> C["dank.config.json + requirements.lock.txt"]
    C --> D["dank-py run / build"]
    D --> E["Containerized Agent Microservice(s)"]
    E --> F["/prompt /health /status /metrics /logs /traces"]
    E --> G["Run locally or self-host (Docker/K8s)"]

📥 Install

Requirements

  • Python >=3.11 (supported host range)
  • Python 3.12 is the target runtime/lock version
  • Docker CLI + running Docker daemon

Install from PyPI

pip install dank-py

Editable install (local development)

pip install -e /absolute/path/to/dank-py

Both command names are available:

  • dank
  • dank-py

🚀 Quick Start

# 1) Scaffold config and ignore files
dank-py init

# 2) Inspect project and apply candidates
dank-py inspect

# 3) Resolve dependency lock
dank-py deps

# 4) Build and run
dank-py run

One command setup:

dank-py auto-init

Strict setup (includes full isolated validation):

dank-py auto-init --strict

🛠️ Command Reference

Version

Quick version check:

dank-py -v
# or
dank-py --version
# or
dank-py version

What it shows:

  • installed dank-py CLI version
  • configured default base image reference
  • Docker availability status
  • installed local dank-py-base image tags (if any)

Flags for dank-py version:

Flag What it does
--json Outputs version/base-image details as JSON for tooling/scripts.

dank-py init

Scaffold dank.config.json and .dankignore.

dank-py init [name] [--force]
Arg/Flag What it does
name Optional target directory. If omitted, uses current directory.
--force Overwrites existing scaffold files instead of leaving them untouched.

dank-py auto-init

Runs init + inspect apply + deps in one flow.

dank-py auto-init [name] [flags]
Arg/Flag What it does
name Optional target directory for scaffolding.
--force Overwrites existing scaffold files.
--validate-dry Runs isolated non-live validation after lock creation.
--validate-full Runs isolated live validation (real env vars and non-mock outputs expected).
--strict Alias for --validate-full.
--fallback-freeze Allows lock fallback via pip freeze when resolver lock cannot be produced.
--no-discover-imports Disables import discovery when no dependency metadata exists.
--install-tools Auto-installs missing resolver tooling (pip-tools) in the active environment.
--no-install-prompt Disables interactive prompts for tool installation.
--lock-python-version <ver> Sets lock target Python version (default 3.12).
--include-lock-comments Keeps resolver metadata comments in requirements.lock.txt.
--no-refresh-lock Reuses existing lock file instead of regenerating it.

dank-py deps

Generates or refreshes requirements.lock.txt, optionally validates agents.

dank-py deps [flags]
Flag What it does
--project-dir <dir> Uses a specific project directory (defaults to current directory).
-c, --config <path> Path to dank.config.json for validation modes.
--validate-dry Runs isolated non-live validation.
--validate-full Runs isolated live validation.
--fallback-freeze Allows pip freeze fallback when resolver lock fails.
--no-discover-imports Disables import-based dependency discovery.
--install-tools Auto-installs pip-tools if missing.
--no-install-prompt Disables prompt asking to install missing tools.
--lock-python-version <ver> Sets lock target Python version (default 3.12).
--include-lock-comments Keeps resolver metadata comments in lock output.
--no-refresh-lock Reuses existing lock instead of regenerating.

dank-py inspect

Scans project files for likely agent entrypoints and model/schema hints.

dank-py inspect [flags]
Flag What it does
--project-dir <dir> Uses a specific project directory.
--json Prints machine-readable inspect output only (no interactive prompts).
--interactive Explicitly runs interactive apply flow (default behavior when not using --json).
--apply Applies selected candidate(s) directly to config.
--candidate-index <N> Chooses a specific 1-based candidate index when applying.
-c, --config <path> Path to target dank.config.json.

dank-py build

Builds local target image(s).

dank-py build [selector] [flags]

Selectors (mutually exclusive):

Selector What it does
--agent <id-or-name> Builds one standalone agent target.
--bundle <bundle-name> Builds one configured bundle target.
--bundle-agents <csv|all> Builds one ad-hoc bundle from agent list or all agents.

Build flags:

Flag What it does
-c, --config <path> Path to dank.config.json.
--bundle-name <name> Names an ad-hoc bundle created with --bundle-agents.
--prompt-routing required|default Overrides bundle prompt routing mode.
--default-agent <id-or-name> Sets default routed agent when using prompt-routing=default.
--tag <tag> Sets output image tag (single target).
--base-image <image> Overrides base image reference.
--pull-base Forces pull of base image before target build.
--no-base-build Skips local base-image build fallback if pull fails.
--force-base Forces base image rebuild/pull path.
--verbose Streams raw Docker build output.
--json Returns structured JSON result.

Default behavior with no selector:

  • no bundles configured: builds all agents separately
  • bundles configured: builds configured bundles + unbundled agents separately

dank-py build:prod

Buildx-based production build flow.

dank-py build:prod [selector] [flags]

Selector flags are the same as build.

Production flags:

Flag What it does
-c, --config <path> Path to dank.config.json.
--bundle-name <name> Names ad-hoc bundle from --bundle-agents.
--prompt-routing required|default Bundle prompt routing override.
--default-agent <id-or-name> Default agent for bundle prompt fallback.
--tag <tag> Image tag (default latest).
--registry <host> Registry host for push targets.
--namespace <prefix> Repository namespace/prefix.
--tag-by-agent Uses agent name as tag with shared namespace repo strategy.
--platform <platform|auto> Buildx platform(s); auto chooses based on push/load mode.
--push / --no-push Enables/disables push output explicitly.
--load / --no-load Enables/disables local Docker load output explicitly.
--no-cache Disables build cache.
--base-image <image> Base image override.
--pull-base Pulls base image before production build.
--force-base Forces base image rebuild/pull path.
--output-metadata <file> Writes build metadata JSON file.
--verbose Streams raw buildx output.
--json Returns structured JSON build result.

dank-py run

Builds (unless --no-build) and runs selected target container(s).

dank-py run [selector] [flags]

Selector flags are the same as build.

Run flags:

Flag What it does
-c, --config <path> Path to dank.config.json.
--bundle-name <name> Names ad-hoc bundle from --bundle-agents.
--prompt-routing required|default Bundle prompt routing override.
--default-agent <id-or-name> Default bundle target when prompt header is omitted in default mode.
--tag <tag> Uses specific image tag for build/run.
--base-image <image> Base image override.
--pull-base Pulls base image before building.
--no-build Runs existing image without rebuilding.
-d, --detached Starts container(s) in detached mode.
--foreground Forces foreground attach mode.
--port <host-port> Starting host port mapping (auto-increments to avoid collisions).
--force-base Forces local base rebuild path.
--keep-build-context Leaves generated .dank-py build context on disk for debugging.
--verbose Streams raw Docker build logs.
--quiet Reduces runtime request/startup logging.
--env-file <path> Injects env file at runtime (repeatable).
-e, --env KEY=VALUE|KEY Injects explicit env var (repeatable).
--no-auto-env-file Disables automatic loading of project .env.
--json Returns structured run result.

Run defaults:

  • single target: foreground monitor mode
  • multi-target: detached mode

dank-py logs

Reads logs from container targets and bundled agent runtime streams.

dank-py logs [target] [flags]
Arg/Flag What it does
target Container name, bundle name, or agent id/name.
-f, --follow Follows logs live (streaming mode).
-t, --tail <N> Number of lines/events to show (default 100).
--since <timestamp-or-duration> Shows logs only since provided time point/window.

Routing behavior:

  • bundled agent target + --follow uses websocket stream
  • bundled agent target (non-follow) queries runtime logs endpoint
  • container target uses Docker logs

dank-py stop

Stops running dank-py containers.

dank-py stop [selector] [flags]
Flag What it does
-c, --config <path> Path to dank.config.json.
--agent <id-or-name> Stops one standalone agent target.
--bundle <bundle-name> Stops one configured/named bundle container.
--bundle-agents <csv|all> Stops one ad-hoc bundle computed from those agents.
--bundle-name <name> Specifies ad-hoc bundle name when used with --bundle-agents.
--all Stops all running dank-py containers.
--keep Stops containers without removing them.

If no selector is provided, it stops all running dank-py containers.

dank-py status

Displays running/stopped container status and available agent images.

dank-py status [--json]
Flag What it does
--json Prints status payload as JSON for tooling.

dank-py clean

Removes generated resources.

dank-py clean [flags]
Flag What it does
--project-dir <dir> Project path used for .dank-py build-context cleanup.
--all Cleans containers, images, and build contexts.
--containers Cleans only dank-py containers.
--images Cleans only dank-py agent images.
--build-contexts Cleans only .dank-py build context directories.
--include-base Also removes local base image when cleaning images.

⚙️ Configuration Reference (dank.config.json)

Top-level fields

Field Type Required Notes
name string | null no Project label.
version string no Defaults to "1".
agents AgentConfig[] yes Must contain at least one agent.
bundles BundleConfig[] no Defaults to empty list.

Validation rules:

  • unknown top-level fields are rejected
  • agent.name and agent.id must be unique
  • missing agent.id is auto-derived from normalized agent.name

AgentConfig

Field Type Required Notes
name string yes Human-readable agent name.
id string | null no Stable routing identity; defaults from name.
entry EntryConfig yes Runtime invocation target.
io IOConfig no Input/output contract definitions.

EntryConfig

Field Type Notes
file string Python file path.
symbol string Exported function/class/object.
method string | null Method name for object/class entry styles.
call_type auto | callable | method Invocation target resolution strategy.
call_style auto | single_arg | kwargs Request payload passing strategy.

IOConfig

Field Type Notes
input.model module:Symbol | null Optional typed input model reference.
input.schema object | null Optional JSON Schema input contract.
output.model module:Symbol | null Optional typed output model reference.
output.schema object | null Optional JSON Schema output contract.
strict_output boolean Defaults to true.

Runtime error classes:

  • input contract failure: 422
  • invocation parameter mismatch: 400
  • invocation failure: 500
  • strict output contract failure: 500

BundleConfig

Field Type Required Notes
name string yes Unique bundle identifier.
agents string[] yes Included members by id or name.
prompt_routing required | default no Defaults to required.
default_agent string | null no Only valid with prompt_routing: default.

Rules:

  • bundle names must be unique
  • all agents[] references must exist
  • default_agent must belong to its bundle

Example: Partial bundle + leftover separate agent

{
  "name": "multi-project",
  "version": "1",
  "agents": [
    { "name": "langchain-agent", "id": "langchain-agent", "entry": { "file": "a.py", "symbol": "run" } },
    { "name": "langgraph-agent", "id": "langgraph-agent", "entry": { "file": "b.py", "symbol": "run" } },
    { "name": "custom-agent", "id": "custom-agent", "entry": { "file": "c.py", "symbol": "run" } }
  ],
  "bundles": [
    {
      "name": "lang-bundle",
      "agents": ["langchain-agent", "langgraph-agent"],
      "prompt_routing": "default",
      "default_agent": "langchain-agent"
    }
  ]
}

Default dank-py run behavior for this config:

  • one container for lang-bundle
  • one separate container for custom-agent

🌐 Runtime API Contract

All runtime containers expose:

Endpoint Purpose
GET /health Container health and runtime mode metadata.
POST /prompt Agent invocation endpoint (single or bundled routing).
GET /status Container/runtime status summary.
GET /status/{agent_id} Per-agent status in multi-agent runtime.
GET /metrics Process/system metrics snapshot.
GET /logs Buffered logs query.
GET /logs/stats Log buffer stats.
WS /logs/stream Live log stream.

Trace endpoints:

  • GET /traces (default/only agent traces)
  • GET /traces/stats (default/only agent trace stats)
  • GET /traces/{agent_id}
  • GET /traces/stats/{agent_id}
  • GET /trace/{trace_id}

Query filters:

  • GET /logs: startTime, endTime, minutesAgo, limit, offset, stream
  • GET /traces, GET /traces/{agent_id}: startTime, endTime, minutesAgo, limit, offset
  • GET /traces/stats, GET /traces/stats/{agent_id}: startTime, endTime, minutesAgo
  • GET /logs/stats, GET /trace/{trace_id}: no query filters

Pagination defaults:

  • trace list endpoints default to limit=100, offset=0
  • use hasMore=true with offset to fetch additional pages

Per-agent live log stream:

  • WS /logs/stream/{agent_id}

Bundle prompt routing

Header: x-dank-agent-id

  • prompt_routing=required: header is required.
  • prompt_routing=default: header is optional; runtime routes to default agent.

Single-agent containers:

  • header optional
  • mismatched header returns 400

Trace headers

  • x-dank-trace-id
    • Optional request header.
    • If omitted, runtime generates one.
    • Always returned in /prompt response header and metadata.trace_id.
    • If provided and already present in in-memory trace/log history, runtime returns 409.
  • x-dank-include-trace
    • Optional request header (true|1|yes|on).
    • When enabled, /prompt includes full grouped trace payload in metadata.trace.

📡 Logging and Observability

Runtime keeps an in-memory log buffer and supports:

  • query endpoints (/logs, /logs/stats)
  • websocket streaming (/logs/stream)
  • grouped trace retrieval (/traces*)
  • bounded retention (DANK_LOG_BUFFER_MAX_SIZE, DANK_LOG_BUFFER_MAX_AGE_MS, DANK_LOG_BUFFER_MAX_BYTES)

/logs/stats includes both:

  • bufferSize (entry count)
  • bufferBytes (approx current bytes)

CLI support:

  • dank-py logs
  • dank-py logs --follow <target>

🔐 Environment and Secrets

Runtime env injection (recommended)

dank-py run --env-file .env
# or
dank-py run -e OPENAI_API_KEY=... -e OPENAI_MODEL=gpt-4o-mini

By default, run auto-loads project .env when --env-file is not explicitly provided. Use --no-auto-env-file to disable that behavior.

Build context safety

Use .dankignore to keep secrets out of image build context.

Recommended:

  • keep .env and .env.* ignored
  • inject secrets at runtime with --env-file / -e

🏭 Build vs Build:Prod

  • build
    • local Docker image build
    • best for local development and quick iteration
  • build:prod
    • buildx workflow for production tagging/loading/pushing
    • suited for CI/CD and registry publish workflows

If you only need local execution, use run (or build + run --no-build).

🧪 Agent Examples

See agent-examples/ for framework-diverse templates:

🧯 Troubleshooting

Docker not installed/running

docker version
docker info

dank-py run/build includes Docker availability checks and remediation prompts.

Platform mismatch on build:prod

Error like no match for platform in manifest usually means base image architecture mismatch.

Fixes:

  • publish multi-arch base image (linux/amd64,linux/arm64), or
  • set explicit compatible --platform.

Missing pip-tools

python -m pip install pip-tools
# or
dank-py deps --install-tools

Ambiguous logs target

Use exact container name from dank-py status.

📦 Release

Release and publish workflow:

⚖️ License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dank_py-1.0.1.tar.gz (97.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dank_py-1.0.1-py3-none-any.whl (91.8 kB view details)

Uploaded Python 3

File details

Details for the file dank_py-1.0.1.tar.gz.

File metadata

  • Download URL: dank_py-1.0.1.tar.gz
  • Upload date:
  • Size: 97.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for dank_py-1.0.1.tar.gz
Algorithm Hash digest
SHA256 43ab9e795f251fd945ecc682a4a8507e478498ace08bbc83a83ef17aaa75a97b
MD5 6d7f391ca6b50346c83e01a4acec4236
BLAKE2b-256 973da6b3b744155c0d84adb654e7219d84ad0a4864830f4f6e7f0c99572ff054

See more details on using hashes here.

File details

Details for the file dank_py-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: dank_py-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 91.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for dank_py-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5a911ef9113a57c22da65b4b6e500cc821c1de356a6c7921a81150c55a33185e
MD5 9d3038b4afde90e8783bfd254cd08d11
BLAKE2b-256 64609ebcbc719fe5f8fbac94305c2916a2e4ecd4974fcc8413023c71ca3e6240

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page