cuenv
Two commands. Type-safe environments. Secrets that never leak. Tasks that run in parallel.
Status: Beta - Core features complete, new capabilities (CI, release management, codegen) in active development
The Problem
You've been here before:
- Secrets in
.envfiles that accidentally get committed, logged, or shared - "Works on my machine" because environment variables differ between developers
- Build scripts that can't run in parallel so your CI takes forever
- Copy-paste task definitions across projects with no validation
cuenv fixes this with two powerful primitives.
Two Primitives, Infinite Possibilities
cuenv exec -- <command>: Run Anything, Securely
Every command runs with:
- Validated environment - CUE constraints ensure
NODE_ENVis actually"development" | "staging" | "production", not a typo - Secrets resolved at runtime - Pulled from 1Password, AWS, GCP, Vault—never stored in files, never in git history
- Environment-specific overrides - Switch from dev to production with
-e production
env: {
NODE_ENV: "development" | "staging" | "production"
PORT: >0 & <65536 & *3000
// Secrets are resolved at runtime, redacted from logs
DB_PASSWORD: schema.#OnePasswordRef & {
ref: "op://vault/database/password"
}
}
Why this matters: Your production credentials are never on disk. They're fetched when needed, used, and forgotten. cuenv env print shows [SECRET] instead of values. Shell exports exclude secrets entirely.
cuenv task <name>: Orchestrated, Parallel, Cached
Every task runs with:
- Automatic dependency resolution -
buildwaits forlintandtestif configured - Parallel execution - Independent subtasks run simultaneously
- Content-aware caching - Skip tasks when inputs haven't changed
- Same secret + environment benefits as
exec
tasks: {
// Parallel: unit, integration, and lint run at the same time
test: {
unit: { command: "npm", args: ["run", "test:unit"] }
integration: { command: "npm", args: ["run", "test:e2e"] }
lint: { command: "npm", args: ["run", "lint"] }
}
// Sequential: each step waits for the previous
deploy: [
{ command: "docker", args: ["build", "-t", "myapp", "."] }
{ command: "docker", args: ["push", "myapp"] }
{ command: "kubectl", args: ["apply", "-f", "k8s/"] }
]
// Dependencies: build won't start until test completes
build: {
command: "npm"
args: ["run", "build"]
dependsOn: ["test"]
inputs: ["src/**/*", "package.json"]
outputs: ["dist/**/*"]
}
}
Why this matters: Your test suite runs in parallel. Your CI is faster. If nothing changed, cached results are used. And every task inherits your validated environment and resolved secrets.
Quick Start
# Install cuenv
# or: cargo install cuenv
# Create configuration
# Run commands with your secure environment
# List available tasks
# Generate CI workflow (optional)
Use Cases
Secure Your Secrets
Stop committing .env files. Define secrets with any provider—they're resolved only when needed:
env: {
// 1Password
DB_PASSWORD: schema.#OnePasswordRef & { ref: "op://vault/db/password" }
// AWS Secrets Manager
API_KEY: schema.#AWSSecretRef & { region: "us-west-2", name: "api-key" }
// HashiCorp Vault
STRIPE_KEY: schema.#VaultRef & { path: "secret/stripe", field: "key" }
// Or define your own resolver for any CLI
CUSTOM_SECRET: schema.#ExecResolver & {
command: "my-secret-tool"
args: ["fetch", "my-secret"]
}
}
Secrets are never written to disk, never exported to your shell, and redacted from logs.
Validate Before You Run
Catch configuration errors before they become runtime failures:
env: {
// Constrained to valid values only
NODE_ENV: "development" | "staging" | "production"
LOG_LEVEL: "debug" | "info" | "warn" | "error"
// Must match patterns
DATABASE_URL: string & =~"^postgresql://"
API_ENDPOINT: string & =~"^https://"
// Numeric bounds
PORT: >0 & <65536
// Defaults that can be overridden
TIMEOUT: string | *"30s"
}
If someone sets NODE_ENV: "prod" instead of "production", cuenv tells them immediately.
Run Tasks in Parallel
Object keys run in parallel. Arrays run sequentially. Dependencies are respected automatically:
tasks: {
// These three run at the same time
lint: {
check: { command: "eslint", args: ["src/"] }
types: { command: "tsc", args: ["--noEmit"] }
format: { command: "prettier", args: ["--check", "."] }
}
// These run one after another
deploy: [
{ command: "npm", args: ["run", "build"] }
{ command: "docker", args: ["build", "-t", "app", "."] }
{ command: "docker", args: ["push", "app"] }
{ command: "kubectl", args: ["rollout", "restart", "deployment/app"] }
]
// This waits for lint to complete first
build: {
command: "npm"
args: ["run", "build"]
dependsOn: ["lint"]
}
}
Share Environments Across a Monorepo
CUE configurations compose naturally. Define once, use everywhere:
myproject/
├── env.cue # Global settings
├── shared/
│ └── database.cue # Shared DB config
├── services/
│ ├── api/
│ │ └── env.cue # Inherits global + adds API-specific
│ └── web/
│ └── env.cue # Inherits global + adds web-specific
// services/api/env.cue
import "github.com/myorg/shared/database"
env: database.#Config & {
SERVICE_NAME: "api"
PORT: 8080
}
Automatic Shell Integration
When you cd into a cuenv project, your shell is configured automatically:
# Add to .zshrc / .bashrc
# Now just cd into your project
# → Environment loaded automatically
# → Nix packages available (if configured)
# → Ready to work
CI Integration
Generate CI workflows from your CUE configuration. cuenv detects affected projects and runs only what's needed:
# Generate GitHub Actions workflow
# Run CI locally
# Preview what would run
cuenv automatically detects your CI provider (GitHub Actions, GitLab CI, etc.) and optimizes pipelines based on which files changed.
Release Management
Manage releases with changesets and automated publishing:
# Add a changeset describing your changes
# Or generate from conventional commits
# Preview version bumps
# Publish packages in dependency order
Changesets integrate with conventional commits and automatically calculate semantic version bumps.
Code Generation (Cubes)
Generate and sync files from CUE templates—configuration files, boilerplate, and more:
# Sync all generated files
# Check if files are in sync (useful in CI)
# Preview changes
Define cubes in your CUE configuration to generate TypeScript configs, Dockerfiles, or any templated content.
Multi-Platform VCS Support
cuenv supports GitHub, GitLab, and Bitbucket for CODEOWNERS and CI integration:
# Sync CODEOWNERS for your platform
# Works with GitHub, GitLab, or Bitbucket
# Platform is auto-detected from your repository
CLI Reference
Core Commands
# Execute commands with validated environment + resolved secrets
# Run named tasks with dependencies, parallelism, caching
Environment Management
# View environment (secrets are redacted)
# Shell integration
Code Generation & Sync
# Sync generated files from CUE configuration
CI & Release Management
# CI integration
# Release management
Security & Utilities
# Security approval for configurations
# Utilities
Global Options
| Option | Description |
|---|---|
--env, -e |
Environment to use (dev, staging, production) |
-p, --path |
Directory with CUE files (default: ".") |
--package |
CUE package name (default: "cuenv") |
--output-format |
Output format (json, env, simple) |
-L, --level |
Log level (trace, debug, info, warn, error) |
How It Compares
| Feature | cuenv | Make | Bazel | Taskfile | direnv |
|---|---|---|---|---|---|
| Type Safety | ✅ CUE constraints | ❌ | ✅ BUILD files | ❌ | ❌ |
| Monorepo Support | ✅ Native | ⚠️ Basic | ✅ Excellent | ⚠️ Basic | ⚠️ Per-directory |
| Environment Management | ✅ Typed + Secrets | ❌ | ❌ | ❌ | ✅ Basic |
| Task Dependencies | ✅ Smart | ✅ | ✅ Advanced | ✅ Basic | ❌ |
| Parallel Execution | ✅ | ⚠️ -j flag | ✅ | ⚠️ Limited | ❌ |
| Caching | ✅ Content-aware | ❌ | ✅ Advanced | ❌ | ❌ |
| CI Integration | ✅ Native | ❌ | ⚠️ Rules | ❌ | ❌ |
| Security Isolation | ✅ Via Dagger | ❌ | ✅ Sandboxing | ❌ | ❌ |
| Shell Integration | ✅ | ❌ | ❌ | ❌ | ✅ |
Status
| Component | Status |
|---|---|
| CUE Evaluation Engine | ✅ Complete |
| CLI + Task Runner | ✅ Complete |
| Secret Management | ✅ Complete |
| Shell Integration | ✅ Complete |
| CI Integration | 🚧 Development |
| Release Management | 🚧 Development |
| Code Generation | 🚧 Development |
| Security Isolation | ✅ Complete |
Contributing
We welcome contributions! cuenv is licensed under AGPL-3.0, ensuring it remains open source.
Development Setup
# Clone the repository
# Enter development environment
# or with direnv: direnv allow
# Project automation (this repo)
Architecture Overview
cuenv/
├── crates/
│ ├── cuengine/ # CUE evaluation engine (Go FFI bridge)
│ ├── core/ # Shared types, task execution, caching
│ ├── cuenv/ # CLI and TUI
│ ├── events/ # Event system for UI frontends
│ ├── workspaces/ # Monorepo and package manager detection
│ ├── ci/ # CI pipeline integration
│ ├── release/ # Version management and publishing
│ ├── cubes/ # CUE-based code generation
│ ├── ignore/ # Ignore file generation
│ ├── codeowners/ # CODEOWNERS generation
│ ├── github/ # GitHub provider
│ ├── gitlab/ # GitLab provider
│ ├── bitbucket/ # Bitbucket provider
│ └── dagger/ # Dagger task execution backend
├── schema/ # CUE schema definitions
├── examples/ # CUE configuration examples
└── docs/ # Documentation
Testing
- Unit tests:
cuenv task test.unit - BDD tests:
cuenv task test.bdd - Coverage:
cuenv task coverage
License
Licensed under the GNU Affero General Public License v3.0.
Why AGPL? We believe in keeping cuenv open source while building a sustainable business. The AGPL ensures that any modifications or hosted services using cuenv remain open source, benefiting the entire community.
Links
- Documentation: cuenv.dev 🚧
- CUE Language: cuelang.org
- Discussion: GitHub Discussions
Built in 🏴 w for the open source community