-
-
Save rawkode/64fb139c197cd803bdd88d73c7075cc1 to your computer and use it in GitHub Desktop.
cuenv --llms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # cuenv | |
| > A modern application build toolchain with typed environments and CUE-powered task orchestration. | |
| cuenv provides two core primitives for secure, validated development environments: | |
| ## Core Primitives | |
| ### `cuenv exec -- <command>` | |
| Run any command with a validated environment and runtime-resolved secrets: | |
| ```bash | |
| cuenv exec -- npm start | |
| cuenv exec -e production -- ./deploy.sh | |
| ``` | |
| - Environment variables are validated against CUE constraints | |
| - Secrets are resolved at runtime from providers (1Password, AWS, GCP, Vault) | |
| - Secrets are never written to disk or exported to shell history | |
| ### `cuenv task <name>` | |
| Execute orchestrated tasks with dependencies, parallelism, and caching: | |
| ```bash | |
| cuenv task build | |
| cuenv task -e staging test | |
| ``` | |
| - Tasks can run in parallel (object syntax) or sequentially (array syntax) | |
| - Automatic dependency resolution via `dependsOn` | |
| - Content-aware caching based on declared `inputs` and `outputs` | |
| - Hermetic execution ensures reproducibility | |
| ## Configuration | |
| cuenv uses CUE for type-safe configuration. Create an `env.cue` file: | |
| ```cue | |
| package cuenv | |
| import "github.com/cuenv/cuenv/schema" | |
| schema.#Cuenv | |
| env: { | |
| NODE_ENV: "development" | "staging" | "production" | |
| API_KEY: schema.#Secret & { command: "op", args: ["read", "op://vault/api/key"] } | |
| } | |
| tasks: { | |
| build: { | |
| command: "npm" | |
| args: ["run", "build"] | |
| inputs: ["src/**/*", "package.json"] | |
| outputs: ["dist/**/*"] | |
| } | |
| test: { | |
| unit: { command: "npm", args: ["test"] } | |
| integration: { command: "npm", args: ["test:e2e"] } | |
| } | |
| } | |
| ``` | |
| ## Key Concepts | |
| - **Type Safety**: CUE constraints validate environment variables before execution | |
| - **Secret Management**: Secrets resolved at runtime, redacted from logs, never persisted | |
| - **Parallel Execution**: Object keys in task groups run concurrently | |
| - **Sequential Execution**: Array elements in task groups run in order | |
| - **Caching**: Tasks with declared inputs/outputs are cached by content hash | |
| - **Hermetic Builds**: Tasks run in isolated directories with only declared inputs | |
| ## CLI Reference | |
| ``` | |
| cuenv exec -- <command> Execute command with validated environment | |
| cuenv task <name> Run a named task | |
| cuenv env print Show environment variables (secrets redacted) | |
| cuenv env list List available environments | |
| cuenv allow Approve configuration for hook execution | |
| cuenv shell init <shell> Generate shell integration script | |
| ``` | |
| ## Links | |
| - Repository: https://github.com/cuenv/cuenv | |
| - CUE Language: https://cuelang.org | |
| ## CUE Schema Reference | |
| ### ci.cue | |
| ```cue | |
| package schema | |
| #PipelineCondition: { | |
| pullRequest?: bool | |
| branch?: string | [...string] | |
| tag?: string | [...string] | |
| defaultBranch?: bool | |
| scheduled?: bool | |
| manual?: bool | |
| } | |
| #Pipeline: { | |
| name: string | |
| when?: #PipelineCondition | |
| tasks: [...string] | |
| } | |
| #CI: { | |
| pipelines: [...#Pipeline] | |
| } | |
| ``` | |
| ### config.cue | |
| ```cue | |
| package schema | |
| #Config: { | |
| // Task output format | |
| outputFormat?: "tui" | "spinner" | "simple" | "tree" | "json" | |
| } | |
| ``` | |
| ### cuenv.cue | |
| ```cue | |
| package schema | |
| #Cuenv: { | |
| name?: string | |
| config?: #Config | |
| env?: #Env | |
| hooks?: #Hooks | |
| workspaces?: #Workspaces | |
| ci?: #CI | |
| release?: #Release | |
| tasks: [string]: #Tasks | *{} | |
| } | |
| #Workspaces: [string]: #WorkspaceConfig | |
| #WorkspaceConfig: { | |
| enabled: bool | *true | |
| package_manager?: "npm" | "pnpm" | "yarn" | "yarn-classic" | "bun" | "cargo" | |
| root?: string | |
| } | |
| ``` | |
| ### devenv.cue | |
| ```cue | |
| package schema | |
| #Devenv: #ExecHook & { | |
| order: 10 | |
| propagate: false | |
| command: "devenv" | |
| args: ["print-dev-env"] | |
| source: true | |
| inputs: ["devenv.nix", "devenv.lock", "devenv.yaml"] | |
| } | |
| ``` | |
| ### env.cue | |
| ```cue | |
| package schema | |
| // Environment variable value with optional policies | |
| // Closed to avoid ambiguity with direct #Secret usage in #EnvironmentVariable | |
| #EnvironmentVariableWithPolicies: close({ | |
| value: string | int | bool | #Secret | |
| policies?: [...#Policy] | |
| }) | |
| // Environment variable can be a simple value or a value with policies | |
| #EnvironmentVariable: string | int | bool | #Secret | #EnvironmentVariableWithPolicies | |
| // We support non-string types for constraints | |
| // but when exported to the actual environment, | |
| // these will always be strings. | |
| #Environment: { | |
| [=~"^[A-Z][A-Z0-9_]*$"]: #EnvironmentVariable | |
| } | |
| // #Env defines the structure for environment variable configuration | |
| #Env: #Environment & { | |
| // Environment-specific overrides | |
| environment?: [string]: #Environment | |
| } | |
| ``` | |
| ### gcp.cue | |
| ```cue | |
| package schema | |
| #GcpSecret: close({ | |
| project: string | |
| secret: string | |
| version: string | *"latest" | |
| ref: "gcp://\(project)/\(secret)/\(version)" | |
| resolver: "exec" | |
| command: "gcloud" | |
| args: ["secrets", "versions", "access", version, "--secret", secret, "--project", project] | |
| }) | |
| ``` | |
| ### hooks.cue | |
| ```cue | |
| package schema | |
| #Hooks: { | |
| onEnter?: [string]: #Hook | |
| onExit?: [string]: #Hook | |
| } | |
| #Hook: #ExecHook | |
| #ExecHook: { | |
| order?: int | *100 | |
| propagate?: bool | *false | |
| command!: string | |
| args?: [...string] | |
| dir?: string | *"." | |
| inputs?: [...string] | |
| source?: bool | |
| // To be extended | |
| ... | |
| } | |
| ``` | |
| ### nix.cue | |
| ```cue | |
| package schema | |
| #NixFlake: #ExecHook & { | |
| order: 10 | |
| propagate: false | |
| command: "nix" | |
| args: ["print-dev-env"] | |
| source: true | |
| inputs: ["flake.nix", "flake.lock"] | |
| } | |
| ``` | |
| ### onepassword.cue | |
| ```cue | |
| package schema | |
| #OnePasswordRef: close({ | |
| resolver: "exec" | |
| ref: string | |
| command: "op" | |
| args: ["read", ref] | |
| }) | |
| ``` | |
| ### policy.cue | |
| ```cue | |
| package schema | |
| // #Policy defines access control for environment variables | |
| #Policy: { | |
| // Allowlist of task names that can access this variable | |
| allowTasks?: [...string] | |
| // Allowlist of exec commands that can access this variable | |
| allowExec?: [...string] | |
| } | |
| ``` | |
| ### release.cue | |
| ```cue | |
| package schema | |
| // #Release defines the release management configuration for cuenv. | |
| // This enables native release workflows including versioning, changelogs, and publishing. | |
| #Release: { | |
| // Git configuration for release management | |
| git?: #ReleaseGit | |
| // Package grouping configuration | |
| packages?: #ReleasePackages | |
| // CHANGELOG generation configuration | |
| changelog?: #ChangelogConfig | |
| } | |
| // #ReleaseGit defines git-related release settings | |
| #ReleaseGit: { | |
| // Default branch for releases (e.g., "main", "master") | |
| defaultBranch?: string | *"main" | |
| // Tag format template. Supports ${package} and ${version} placeholders. | |
| // Examples: | |
| // - "v${version}" for single-package repos | |
| // - "${package}-v${version}" for monorepos | |
| tagFormat?: string | *"v${version}" | |
| // Whether to create tags during release | |
| createTags?: bool | *true | |
| // Whether to push tags to remote | |
| pushTags?: bool | *true | |
| } | |
| // #ReleasePackages defines package grouping for version management | |
| #ReleasePackages: { | |
| // Fixed groups: packages that share the same version (lockstep versioning) | |
| // All packages in a group are bumped together with the highest bump level. | |
| // Example: [["crates/cuenv-core", "crates/cuenv-cli"]] | |
| fixed?: [...[...string]] | |
| // Linked groups: packages that have their versions updated together when | |
| // any one of them has a change. Unlike fixed, versions can differ. | |
| // Example: [["crates/*"]] | |
| linked?: [...[...string]] | |
| // Independent packages: not part of any group, versioned independently | |
| // This is implicit - packages not in fixed or linked are independent | |
| } | |
| // #ChangelogConfig defines CHANGELOG generation settings | |
| #ChangelogConfig: { | |
| // Path to the CHANGELOG file relative to project/package root | |
| path?: string | *"CHANGELOG.md" | |
| // Whether to generate changelogs for each package | |
| perPackage?: bool | *true | |
| // Whether to generate a root changelog for the entire workspace | |
| workspace?: bool | *true | |
| // Categories for organizing changelog entries | |
| categories?: [...#ChangelogCategory] | |
| } | |
| // #ChangelogCategory defines a category for changelog entries | |
| #ChangelogCategory: { | |
| // Title for the category in the changelog | |
| title: string | |
| // Changeset types that belong to this category | |
| types: [...#ChangesetType] | |
| } | |
| // #ChangesetType defines the type of change in a changeset | |
| #ChangesetType: "major" | "minor" | "patch" | "none" | |
| // #Changeset represents a single changeset entry | |
| #Changeset: { | |
| // Unique identifier for the changeset | |
| id: string | |
| // Summary of the change | |
| summary: string | |
| // Packages affected by this change | |
| packages: [...#PackageChange] | |
| // Optional longer description | |
| description?: string | |
| } | |
| // #PackageChange represents a version bump for a specific package | |
| #PackageChange: { | |
| // Package name or path | |
| name: string | |
| // Type of version bump | |
| bump: #ChangesetType | |
| } | |
| ``` | |
| ### rust.cue | |
| ```cue | |
| package schema | |
| // #Rust provides a collection of reusable tasks for Rust projects. | |
| // It includes standard commands for building, testing, and linting. | |
| // | |
| // Usage: | |
| // | |
| // import "github.com/cuenv/cuenv/schema" | |
| // | |
| // tasks: { | |
| // build: schema.#Rust.#Build & { | |
| // inputs: ["Cargo.toml", "src"] | |
| // } | |
| // } | |
| #Rust: { | |
| // Common inputs used across most Rust tasks | |
| // Users should override this to match their project structure | |
| #BaseInputs: [...string] | *["Cargo.toml", "Cargo.lock", "src"] | |
| // #Build runs 'cargo build' | |
| #Build: #Task & { | |
| command: "cargo" | |
| args: ["build", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // #Test runs 'cargo test' | |
| #Test: #Task & { | |
| command: "cargo" | |
| args: ["test", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // #Clippy runs 'cargo clippy' | |
| #Clippy: #Task & { | |
| command: "cargo" | |
| args: ["clippy", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // #Fmt runs 'cargo fmt' | |
| #Fmt: #Task & { | |
| command: "cargo" | |
| args: ["fmt", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // #Check runs 'cargo check' (faster than build) | |
| #Check: #Task & { | |
| command: "cargo" | |
| args: ["check", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // #Doc runs 'cargo doc' | |
| #Doc: #Task & { | |
| command: "cargo" | |
| args: ["doc", ...string] | |
| inputs: #BaseInputs | |
| } | |
| // Default tasks exposed by this module | |
| // Note: fmt and test are not exposed to avoid conflicts with common | |
| // monorepo setups (treefmt, test groups). | |
| build: #Build | |
| check: #Check | |
| clippy: #Clippy | |
| doc: #Doc | |
| ... | |
| } | |
| ``` | |
| ### secrets.cue | |
| ```cue | |
| package schema | |
| // Base secret type with exec resolver | |
| #Secret: { | |
| resolver: "exec" | |
| command: string | |
| args?: [...string] | |
| ... | |
| } | |
| // For backward compatibility and structured types | |
| #ExecResolver: { | |
| command: string | |
| args?: [...string] | |
| } | |
| ``` | |
| ### shell.cue | |
| ```cue | |
| package schema | |
| #Shell: { | |
| command: string // Shell executable name (e.g., "bash", "fish", "zsh") | |
| flag: string // Flag for command execution (e.g., "-c", "--command") | |
| } | |
| #Bash: #Shell & { | |
| command: "bash" | |
| flag: "-c" | |
| } | |
| #Fish: #Shell & { | |
| command: "fish" | |
| flag: "-c" | |
| } | |
| #Zsh: #Shell & { | |
| command: "zsh" | |
| flag: "-c" | |
| } | |
| #Sh: #Shell & { | |
| command: "sh" | |
| flag: "-c" | |
| } | |
| #Cmd: #Shell & { | |
| command: "cmd" | |
| flag: "/C" | |
| } | |
| #PowerShell: #Shell & { | |
| command: "powershell" | |
| flag: "-Command" | |
| } | |
| ``` | |
| ### tasks.cue | |
| ```cue | |
| package schema | |
| // #Tasks can represent either a single task or a group of tasks. | |
| // Use a single #Task when you have an isolated command to run. | |
| // Use a #TaskGroup when you need to define multiple tasks that should be executed | |
| // either sequentially (as an array) or in parallel with dependencies (as an object). | |
| // Choose the structure based on your workflow requirements: | |
| // - Single #Task: Simple, standalone execution. | |
| // - #TaskGroup: Complex workflows involving multiple tasks and dependencies. | |
| #Tasks: #Task | #TaskGroup | |
| #Task: { | |
| shell?: #Shell | |
| // Command to execute. Required unless 'script' is provided. | |
| command?: string | |
| // Inline script to execute (alternative to command). | |
| // When script is provided, shell defaults to bash if not specified. | |
| // Supports multiline strings and shebang lines for polyglot scripts. | |
| // Example: | |
| // script: """ | |
| // #!/bin/bash | |
| // set -euo pipefail | |
| // echo "Building..." | |
| // cargo build --release | |
| // """ | |
| script?: string | |
| // Validation: exactly one of command or script must be provided | |
| _hasCommand: command != _|_ | |
| _hasScript: script != _|_ | |
| _validTask: true & ((_hasCommand & !_hasScript) | (!_hasCommand & _hasScript)) | |
| args?: [...string] | |
| env?: [string]: #EnvironmentVariable | |
| // When true (default), task runs in an isolated hermetic directory with only | |
| // declared inputs available. When false, task runs directly in the workspace | |
| // root (if workspaces specified) or project root. Non-hermetic tasks are useful | |
| // for install commands that need to write to the real filesystem. | |
| hermetic?: bool | *true | |
| dependsOn?: [...string] | |
| // Inputs accepted: | |
| // - File paths relative to the env.cue root, e.g. "src/index.ts" | |
| // - Directories (recursively included), e.g. "src" or "src/lib" | |
| // - Glob patterns (first-class), e.g. "src/**/*.ts", "assets/**/*.{png,jpg}" | |
| // - Project references that pull outputs from another task in the repo | |
| // All inputs are resolved relative to the project root and are the ONLY files | |
| // made available inside the hermetic working directory when executing the task. | |
| inputs?: [...#Input] | |
| // Outputs accepted (same syntax as inputs): files, directories, and globs relative | |
| // to the project root. Only declared outputs are indexed and persisted to the | |
| // cache for later materialization. Writes to undeclared paths are allowed but | |
| // will be warned about and are not indexed. | |
| outputs?: [...string] | |
| // Consume cached outputs from other tasks in the same project. | |
| // The referenced task's outputs are materialized into this task's hermetic workspace. | |
| inputsFrom?: [...#TaskOutput] | |
| // Workspaces to mount/enable for this task | |
| workspaces?: [...string] | |
| description?: string | |
| // Dagger-specific configuration for running this task in a container | |
| dagger?: #DaggerConfig | |
| // Task parameter definitions for CLI arguments | |
| // Allows tasks to accept positional and named arguments: | |
| // cuenv task import.youtube VIDEO_ID --quality 1080p | |
| params?: #TaskParams | |
| } | |
| // Task parameter definitions | |
| #TaskParams: { | |
| // Positional arguments (order matters, consumed left-to-right) | |
| // Referenced in args as {{0}}, {{1}}, etc. | |
| positional?: [...#Param] | |
| // Named arguments are declared as direct fields (--flag style) | |
| // Referenced in args as {{name}} where name matches the field name | |
| // Example: thumbnailUrl: { description: "URL", required: false } | |
| [!~"^positional$"]: #Param | |
| } | |
| // Parameter definition for task arguments | |
| #Param: { | |
| // Human-readable description shown in --help | |
| description?: string | |
| // Whether the argument must be provided (default: false) | |
| required?: bool | *false | |
| // Default value if not provided | |
| default?: string | |
| // Type hint for validation (default: "string") | |
| type?: "string" | "bool" | "int" | *"string" | |
| // Short flag (single character, e.g., "t" for -t) | |
| short?: =~"^[a-zA-Z]$" | |
| } | |
| // Accepted task inputs: | |
| // - string: File path, directory, or glob pattern | |
| // - #ProjectReference: Cross-project task outputs | |
| // - #TaskOutput: Same-project task outputs | |
| #Input: string | #ProjectReference | #TaskOutput | |
| // Reference to another project's task within the same Git root | |
| #ProjectReference: { | |
| // Path to external project root. May be absolute-from-repo-root (prefix "/") | |
| // or relative to the env.cue declaring this dependency. | |
| project: string | |
| // Name of the external task in that project | |
| task: string | |
| // Explicit selection and mapping of outputs to this task's hermetic workspace | |
| map: [...#Mapping] | |
| } | |
| #Mapping: { | |
| // Path of a declared output (file or directory) from the external task, | |
| // relative to the external project's root. Directories map recursively. | |
| from: string | |
| // Destination path inside the dependent task's hermetic workspace where the | |
| // selected file/dir will be materialized. Must be unique per mapping. | |
| to: string | |
| } | |
| // Notes: | |
| // - 'from' values must be among the external task's declared outputs | |
| // - Directories in 'from' map recursively | |
| // - Each 'to' destination must be unique; collisions are disallowed | |
| // - External tasks run with their own environment; no env injection from dependents | |
| // Reference to another task's outputs within the same project | |
| #TaskOutput: { | |
| // Name of the task whose cached outputs to consume (e.g. "docs.build") | |
| task: string | |
| // Optional explicit mapping of outputs. If omitted, all outputs are | |
| // materialized at their original paths in the hermetic workspace. | |
| map?: [...#Mapping] | |
| } | |
| // TaskGroup uses structure to determine execution mode: | |
| // - Array of tasks: Sequential execution (order preserved) | |
| // - Object of named tasks: Parallel execution with dependencies | |
| #TaskGroup: [...#Tasks] | {[string]: #Tasks} | |
| // Dagger-specific task configuration for containerized execution | |
| #DaggerConfig: { | |
| // Base container image (e.g., "node:20-alpine", "rust:1.75-slim") | |
| // Required unless 'from' is specified | |
| image?: string | |
| // Use container from a previous task as base instead of an image. | |
| // The referenced task must have run and produced a container. | |
| // Example: from: "deps" continues from the "deps" task's container | |
| from?: string | |
| // Secrets to mount or expose as environment variables. | |
| // Secrets are resolved using cuenv's secret resolvers (exec, 1Password, etc.) | |
| // and securely passed to Dagger without exposing plaintext in logs. | |
| secrets?: [...#DaggerSecret] | |
| // Cache volumes to mount for persistent build caching. | |
| // Cache volumes persist across task runs and speed up builds. | |
| cache?: [...#DaggerCacheMount] | |
| } | |
| // Secret configuration for Dagger containers | |
| #DaggerSecret: { | |
| // Name identifier for the secret in Dagger | |
| name: string | |
| // Mount secret as a file at this path (e.g., "/root/.npmrc") | |
| path?: string | |
| // Expose secret as an environment variable with this name | |
| envVar?: string | |
| // Secret resolver - uses existing cuenv secret types (#Secret, #OnePasswordRef, etc.) | |
| resolver: #Secret | |
| } | |
| // Cache volume mount configuration | |
| #DaggerCacheMount: { | |
| // Path inside the container to mount the cache (e.g., "/root/.npm", "/root/.cargo/registry") | |
| path: string | |
| // Unique name for the cache volume. Volumes with the same name share data. | |
| name: string | |
| } | |
| ``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment