Reusable environment detection, activation, and wrapper tooling for developer CLIs.
Project description
dekk
Make project CLIs runnable with one config and zero manual activation.
dekk turns project setup into a reusable runtime layer. Declare the
environment once in .dekk.toml, then use dekk to detect tools,
activate the environment, install wrappers, and make project commands
work on fresh machines without hand-written setup steps.
Install And Start
Recommended for end users:
pipx install dekk
Fallback if you already manage Python packages directly:
python -m pip install --upgrade dekk
After installation:
- Use
dekkfor the CLI. - Use
python -m dekkas a fallback if your scripts directory is not onPATHyet.
The Problem
Every project needs environment setup: conda environments, PATH entries, environment variables, tool versions. Developers manually activate things. AI agents waste thousands of tokens describing setup steps. CI pipelines duplicate configuration.
The Solution
Declare your environment once in .dekk.toml. dekk handles detection,
activation, wrapper generation, and installed command setup from that
single source of truth.
[project]
name = "myapp"
[conda]
name = "myapp"
file = "environment.yaml"
[tools]
python = { command = "python", version = ">=3.10" }
cmake = { command = "cmake", version = ">=3.20" }
cargo = { command = "cargo" }
[env]
MLIR_DIR = "{conda}/lib/cmake/mlir"
[paths]
bin = ["{project}/bin"]
Three Pillars
1. Detect
Zero-dependency detection of your entire development environment:
- Platform: OS, architecture, Linux distro, WSL, containers
- Package managers: conda/mamba, with environment validation
- Build systems: 25+ (Cargo, CMake, npm, Poetry, Maven, Gradle, ...)
- Compilers: GCC, Clang, Rust, Go with versions and targets
- CI providers: 14 (GitHub Actions, GitLab CI, Jenkins, ...)
- Shells: 9 types (bash, zsh, fish, tcsh, PowerShell, ...)
- Workspaces: Monorepo detection with dependency graphs
from dekk import PlatformDetector, CondaDetector, BuildSystemDetector
platform = PlatformDetector().detect()
# PlatformInfo(os='Linux', arch='x86_64', distro='ubuntu', ...)
conda = CondaDetector().find_environment("myenv")
# CondaEnvironment(name='myenv', prefix=Path('/opt/conda/envs/myenv'))
builds = BuildSystemDetector().detect(Path("."))
# [BuildSystemInfo(system=BuildSystem.CARGO, root=Path("."), ...)]
2. Activate
Read .dekk.toml, resolve conda paths, set environment variables, validate tools:
from dekk import EnvironmentActivator
activator = EnvironmentActivator.from_cwd()
result = activator.activate()
# ActivationResult(env_vars={'CONDA_PREFIX': '...', 'MLIR_DIR': '...'}, ...)
Or from the CLI:
$ eval "$(dekk activate --shell bash)"
On Windows PowerShell:
PS> Invoke-Expression (& dekk activate --shell powershell | Out-String)
3. Wrap
Generate a self-contained launcher that bakes in the full environment. This is what makes dekk zero-friction.
$ dekk wrap myapp ./bin/myapp
Generated myapp -> /path/to/project/.install/myapp
$ myapp doctor # just works -- no activation needed
On POSIX, the wrapper is a simple shell script with hardcoded paths:
#!/bin/sh
export CONDA_PREFIX="/home/user/miniforge3/envs/myapp"
export PATH="/home/user/miniforge3/envs/myapp/bin:$PATH"
export MLIR_DIR="/home/user/miniforge3/envs/myapp/lib/cmake/mlir"
exec "/home/user/miniforge3/envs/myapp/bin/python3" \
"/home/user/projects/myapp/tools/cli.py" "$@"
On Windows, dekk installs a .cmd launcher in the project's .install
directory so the command works from both Command Prompt and PowerShell
without requiring Activate.ps1.
From Python:
from dekk import WrapperGenerator
result = WrapperGenerator.install_from_spec(
spec_file=Path(".dekk.toml"),
target=Path("tools/cli.py"),
python=Path("/opt/conda/envs/myapp/bin/python3"),
name="myapp",
)
Installation
pipx install dekk
python -m pip install --upgrade dekk
python -m pip install --upgrade "dekk[tracking]"
python -m pip install --upgrade "dekk[all]"
First Run
The default path should be simple:
dekk --help
dekk doctor
dekk init --example quickstart
That gives you a working CLI immediately, a system check, and a starter
.dekk.toml in the current directory.
If dekk is not found yet, use python -m dekk --help immediately.
If you want a built-in starter without writing files yet:
dekk example quickstart
dekk example conda --output .dekk.toml
Built-in templates live in examples/.dekk.toml.quickstart, examples/.dekk.toml.minimal, and examples/.dekk.toml.conda.
Typical next steps:
# Python CLI from a repo with pyproject.toml
dekk install ./tools/cli.py
# POSIX shells
eval "$(dekk activate --shell bash)"
# Install a launcher after your project builds a target
dekk install ./bin/myapp --name myapp
# Remove a launcher again
dekk uninstall myapp
For Python scripts, dekk install ./tools/cli.py uses pyproject.toml to
create or refresh .venv automatically on first run. For binaries and
conda-backed projects, dekk install uses .dekk.toml to bake the
required environment into the installed command. When the install directory is
not already on PATH, dekk also appends the project's .install directory to
the active shell config when it can, then asks for a shell restart once.
Use dekk uninstall <name> to remove an installed launcher. Pass
--remove-path when you also want dekk to remove that project's PATH export
from the shell config.
# PowerShell
Invoke-Expression (& dekk activate --shell powershell | Out-String)
dekk install .\dist\myapp.exe --name myapp
Naming Conventions
dekk uses one name per surface area:
- PyPI package:
dekk - Python import:
dekk - CLI command:
dekk - Project config file:
.dekk.toml - Default wrapper location:
.install/in the current project
That keeps installation, imports, command usage, and project setup distinct and predictable.
CLI Framework
dekk includes a production-quality CLI framework built on Rich and Typer. Use it as the foundation for your own CLI tools:
from dekk import Typer, Option
app = Typer(
name="myapp",
auto_activate=True, # auto-setup from .dekk.toml
add_doctor_command=True, # built-in health check
add_version_command=True, # built-in version info
)
@app.command()
def build(release: bool = Option(True, "--release/--debug")):
"""Build the project."""
...
if __name__ == "__main__":
app()
Styled output
from dekk import print_success, print_error, print_warning, print_info
from dekk import print_header, print_step, print_table
print_header("Building MyApp")
print_step("Compiling...")
print_success("Build complete!")
print_warning("Debug symbols not stripped")
Progress indicators
from dekk import spinner, progress_bar
with spinner("Installing dependencies..."):
install_deps()
with progress_bar("Processing", total=100) as bar:
for item in items:
process(item)
bar.advance()
Structured errors
from dekk import NotFoundError, DependencyError
raise NotFoundError(
"Compiler not found",
hint="Install the required toolchain for this project",
)
# Displays styled error with hint, exits with code 3
Multi-format output
from dekk import OutputFormatter, OutputFormat
fmt = OutputFormatter(format=OutputFormat.JSON)
fmt.print_result({"status": "ok", "version": "1.0"})
LLM-friendly subprocess runner
from dekk import run_logged
result = run_logged(
["cargo", "build", "--release"],
log_path=Path(".logs/build.log"),
spinner_text="Building...",
)
# Shows spinner, captures output to log, prints path for agents to read
.dekk.toml Reference
[project] -- required
[project]
name = "myapp"
description = "Optional description"
[conda] -- conda/mamba environment
[conda]
name = "myapp"
file = "environment.yaml"
[tools] -- required CLI tools
[tools]
python = { command = "python", version = ">=3.10" }
cmake = { command = "cmake", version = ">=3.20" }
ninja = { command = "ninja" }
cargo = { command = "cargo", optional = true }
[env] -- environment variables
[env]
MLIR_DIR = "{conda}/lib/cmake/mlir"
LLVM_DIR = "{conda}/lib/cmake/llvm"
MY_HOME = "{project}"
Placeholders: {project} (project root), {conda} (conda prefix), {home} (user home)
[paths] -- PATH prepends
[paths]
bin = ["{project}/bin", "{project}/target/release"]
Examples by Language
Python + Conda
[project]
name = "ml-pipeline"
[conda]
name = "ml-pipeline"
file = "environment.yaml"
[tools]
python = { command = "python", version = ">=3.10" }
jupyter = { command = "jupyter" }
[env]
PYTHONPATH = "{project}/src"
Rust
[project]
name = "my-rust-app"
[tools]
cargo = { command = "cargo", version = ">=1.70" }
rustc = { command = "rustc" }
[paths]
bin = ["{project}/target/release"]
C++ with CMake
[project]
name = "physics-sim"
[conda]
name = "physics-sim"
file = "environment.yaml"
[tools]
cmake = { command = "cmake", version = ">=3.20" }
ninja = { command = "ninja" }
clang = { command = "clang", version = ">=17" }
[env]
CMAKE_PREFIX_PATH = "{conda}"
Node.js
[project]
name = "web-app"
[tools]
node = { command = "node", version = ">=18" }
npm = { command = "npm" }
[env]
NODE_ENV = "development"
Go
[project]
name = "api-server"
[tools]
go = { command = "go", version = ">=1.21" }
[env]
GOPATH = "{home}/go"
[paths]
bin = ["{home}/go/bin"]
For AI Agents
dekk reduces environment setup from 2000-5000 tokens to ~150 tokens:
Before (what agents had to explain):
Check if conda is installed. If not, install miniforge. Create environment with
conda env create -f environment.yaml. Activate withconda activate myenv. Set MLIR_DIR to the conda prefix. Export LD_LIBRARY_PATH...
After:
Run
myapp install. The wrapper handles everything.
Detection API Summary
| Module | What it detects |
|---|---|
PlatformDetector |
OS, arch, distro, WSL, containers, package manager |
CondaDetector |
Conda/mamba environments, packages, validation |
BuildSystemDetector |
25+ build systems with targets and workspaces |
CompilerDetector |
GCC, Clang, Rust, Go with versions and targets |
CIDetector |
14 CI providers with git metadata and runner info |
ShellDetector |
9 shell types with config files and capabilities |
WorkspaceDetector |
Monorepos with dependency graphs and build order |
DependencyChecker |
CLI tool versions against constraints |
VersionManagerDetector |
pyenv, nvm, asdf, rbenv, rustup |
LockfileParser |
7 lockfile formats across ecosystems |
Architecture
dekk is organized in three tiers:
- Tier 1 (Core): Foundational detection and config modules. Platform, conda, deps, workspace, config, remediation.
- Tier 2 (Extended): Paths, build systems, compilers, shells, toolchains, versions, CI.
- Tier 3 (Frameworks): Diagnostics, commands, scaffolding.
The CLI framework ships in the base dekk install.
Documentation
- Getting Started
- Architecture
- .dekk.toml Specification
- Wrapper Generation
- Examples by Language
- Contributing
License
MIT
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 dekk-1.1.0.tar.gz.
File metadata
- Download URL: dekk-1.1.0.tar.gz
- Upload date:
- Size: 201.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c1dcc678d9b4316e7060595e34879baed368b872231f3f19f63cd709bbc5631
|
|
| MD5 |
af6f93733e56ba7c58425790729cfa50
|
|
| BLAKE2b-256 |
b02c5cc9587cd92c3e370e3be3c3faf85a8764fcfa6a203dc28f24972be5e10d
|
Provenance
The following attestation bundles were made for dekk-1.1.0.tar.gz:
Publisher:
python-publish.yml on randreshg/dekk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dekk-1.1.0.tar.gz -
Subject digest:
3c1dcc678d9b4316e7060595e34879baed368b872231f3f19f63cd709bbc5631 - Sigstore transparency entry: 1150014853
- Sigstore integration time:
-
Permalink:
randreshg/dekk@d914a3ccd2b96ed542e3d58cf71ee2e579b183b8 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/randreshg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d914a3ccd2b96ed542e3d58cf71ee2e579b183b8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dekk-1.1.0-py3-none-any.whl.
File metadata
- Download URL: dekk-1.1.0-py3-none-any.whl
- Upload date:
- Size: 137.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa95e97191e54b0301fece63c25b9439aa14d4a80a88a74cd8318bc1a44aa32f
|
|
| MD5 |
cc33c3e54099118c92e9a78c3ca8c2f6
|
|
| BLAKE2b-256 |
6b87e15fd6b8749e7b439b969b6ab56860d344330855bfc4a08c2fa1e99021fd
|
Provenance
The following attestation bundles were made for dekk-1.1.0-py3-none-any.whl:
Publisher:
python-publish.yml on randreshg/dekk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dekk-1.1.0-py3-none-any.whl -
Subject digest:
aa95e97191e54b0301fece63c25b9439aa14d4a80a88a74cd8318bc1a44aa32f - Sigstore transparency entry: 1150014893
- Sigstore integration time:
-
Permalink:
randreshg/dekk@d914a3ccd2b96ed542e3d58cf71ee2e579b183b8 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/randreshg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d914a3ccd2b96ed542e3d58cf71ee2e579b183b8 -
Trigger Event:
release
-
Statement type: