Stack is a Nix-based development environment framework and studio UI for managing multi-app monorepos. It provides deterministic dev environments, service orchestration, secrets management, IDE integration, and a web-based studio for visualizing and controlling everything.
The system has three runtime planes:
- Nix plane -- Evaluates configuration, computes ports, provisions the devshell, generates files. Runs once on shell entry.
- Go agent plane -- A localhost HTTP server (default port 9876) that bridges the web UI to the local Nix environment. Provides REST + Connect-RPC APIs, SSE events, file watching, and process management.
- Web plane -- A React (TanStack Start) application that serves as the studio UI. Communicates with the cloud API via tRPC and with the local Go agent via HTTP REST + Connect-RPC.
Browser (Studio UI)
|
|-- tRPC --> Cloud API (Hono on Cloudflare Workers)
| |-- Better Auth (sessions, Polar payments)
| |-- Drizzle ORM --> Neon PostgreSQL
|
|-- HTTP/Connect-RPC --> Go Agent (localhost:9876)
|-- nix eval (config, options, packages)
|-- process-compose (service lifecycle)
|-- file system (secrets, config, code)
|-- Caddy (reverse proxy, TLS)
|-- Step CA (certificates)
All stack logic lives in nix/stack/ and has zero dependency on devenv, NixOS, or any other module system. Adapters translate the core outputs to their target:
nix/flake/default.nix-- flake-parts adapter:lib.evalModuleswith core, thenpkgs.mkShellnix/flake/modules/devenv.nix-- devenv adapter: mapsstack.devshell.*to devenv's outputsnix/flake/devenv.nix-- standalone devenv adapter
User's flake.nix
-> imports flakeModules.default (nix/flake/default.nix)
-> auto-loads .stack/_internal.nix (merges config.nix + data/*.nix + overrides)
-> lib.evalModules with nix/stack/ (the core)
-> optionally imports .stack/devenv.nix into devenv.shells.default
-> creates devShells.default via pkgs.mkShell
All options are under options.stack.*:
| Namespace | Purpose |
|---|---|
stack.{enable, name, root, dirs} |
Project identity and paths |
stack.apps / stack.appsComputed |
App definitions and computed ports/URLs |
stack.ports |
Deterministic port computation config |
stack.services |
Canonical service type system |
stack.globalServices |
Convenience service definitions (postgres, redis, minio) |
stack.devshell |
Shell environment (packages, hooks, env, files) |
stack.scripts |
Shell commands |
stack.modules |
Extension module registry |
stack.secrets |
Master-key secrets management |
stack.ide |
VS Code and Zed integration |
stack.theme |
Starship prompt theming |
stack.step-ca |
Certificate management |
stack.aws |
AWS Roles Anywhere |
stack.process-compose |
Process orchestration |
nix/stack/
core/ # Options definitions (30+ files), CLI invocation, state, utilities
core/options/ # ALL option definitions (the schema)
core/services/ # Service computation (mkGlobalServices)
devshell/ # Shell subsystem (scripts, files, codegen, bin wrappers)
network/ # Step CA certificates, port env vars
services/ # Service implementations (postgres, redis, caddy, aws, binary-cache)
secrets/ # Master-key encryption (agenix, SOPS, combined)
ide/ # VS Code and Zed file generation
modules/ # Auto-discovered directory modules (process-compose, go, bun, oxlint, turbo, git-hooks)
db/ # Proto-based schema system (.proto.nix -> Nix options + Go/TS types)
lib/ # Pure library functions (ports, IDE, theme, serialization, service helpers)
apps/ # App-level features and CI
tui/ # Terminal UI theme
packages/ # Nix package definitions (stack-cli)
- appModules: Modules inject per-app options. Go module adds
app.go.*, process-compose addsapp.process-compose.*, OxLint addsapp.linting.oxlint.*. - serviceModules: Modules inject per-service options. Process-compose adds readiness probes, namespaces.
- Directory modules (
nix/stack/modules/): Auto-discovered. Each hasmeta.nix(pure data),module.nix(options + config),ui.nix(UI panel definitions).
.proto.nix files in nix/stack/db/schemas/ serve as single source of truth. They generate: Nix module options, Go types (protobuf), TypeScript types, and JSON schemas from one definition.
Ports are computed from the project name hash, ensuring identical ports across all team members without manual configuration:
- Hash project name with MD5
- Convert first 8 hex chars to decimal
- Constrain to range
[3000, 65000), round to nearest 100 - Apps get sequential ports at
base + 0-9 - Services get stable ports via
hash(projectName + serviceName)within the project's port range
Environment variables: STACKPANEL_<KEY>_PORT (e.g., STACKPANEL_POSTGRES_PORT=6410).
- Framework: TanStack Start (SSR-capable React) + Vite + Cloudflare Workers
- Router: TanStack Router with file-based routing
- State: TanStack Query with SuperJSON serialization
- Cloud API: tRPC via
@stack/api-- server useslocalLink(in-process), client useshttpBatchStreamLink - Agent API: Dual protocol -- HTTP REST (
AgentHttpClient, 1244 lines) and Connect-RPC (proto-generated hooks, 1499 lines) - Auth: Better-Auth client with JWT session management
- UI: Radix UI primitives + shadcn components + Tailwind CSS v4
Key routes:
/-- Landing page/login-- Auth (Better-Auth)/dashboard-- Authenticated dashboard/studio/*-- Main app (20+ sub-routes): wraps inAgentProvider > AgentSSEProvider > ProjectProvider > SidebarProvider
Agent connection pattern:
AgentProvidermanages JWT pairing via popup, stores token in localStorage, polls healthAgentSSEProvidermaintains EventSource to/api/eventsfor real-time config changesProjectProvidermanages multi-project selection withX-Stack-Projectheader
Single Go binary with two modes:
CLI (Cobra commands):
stack-- Interactive TUI navigator (default)stack services {start,stop,status,restart,logs}-- Service managementstack caddy {start,stop,status,add,remove}-- Reverse proxystack status-- Status dashboardstack agent-- Start the HTTP agent serverstack init-- Initialize from Nix config (called by Nix shell entry)stack commands,users,env,vars,ports,scaffold,motd,gendocs,logs,project
Agent (localhost HTTP server, port 9876):
- JWT auth via popup pairing flow
- CORS middleware for web UI
- SSE event broadcasting on config changes
- File watching (fsnotify) + FlakeWatcher (
.#stackpanelConfig) - ShellManager for devshell state tracking
- 60+ REST API endpoints organized by domain: project, nix, files, secrets, security, nixpkgs, SST, process-compose, modules, registry
- Connect-RPC service endpoint for proto-generated typed API
TUI: Charmbracelet stack (Bubble Tea, Lip Gloss, Glamour)
- Framework: Next.js 16 with Fumadocs (static export for Cloudflare)
- Content: MDX in
content/docs/-- guides, reference (auto-generated from Nix options), CLI docs (auto-generated) - Auto-generation: Go CLI
gendocscommand evaluates Nix options and Cobra commands to produce MDX
Early-stage React-based terminal UI using OpenTUI. Separate from the Go Charmbracelet TUI.
apps/web
-> @stack/api (tRPC routers + types)
-> @stack/auth (Better Auth + Polar payments)
-> @stack/db (Drizzle ORM + Neon PostgreSQL)
-> @gen/env (generated env package)
-> @stack/db
-> @stack/agent-client -> @stack/proto (Connect-RPC types)
-> @stack/ui -> @stack/ui-web -> @stack/ui-core + @stack/ui-primitives (Radix)
| Package | Purpose |
|---|---|
@stack/api |
tRPC routers (agent, github). Creates context with { authApi, session, db }. Defines publicProcedure and protectedProcedure. |
@stack/auth |
Better Auth with Drizzle adapter, email/password, Polar payments plugin. |
@stack/db |
Drizzle ORM with Neon serverless PostgreSQL. Auth schema (user, session, account, verification). |
@gen/env |
Generated, type-safe env package. Per-app/per-env codegen from Nix with app exports like @gen/env/web, a runtime loader under src/entrypoints/, and embedded encrypted payloads in src/embedded-data.ts. |
@stack/proto |
23+ protobuf modules for agent communication. Generated Go + TypeScript types. |
@stack/agent-client |
Connect-RPC client factory with JWT interceptor. |
@stack/ui |
Facade: re-exports ui-web (or ui-native) + ui-core utilities. |
@stack/ui-web |
16 shadcn-style components (Button, Card, Dialog, etc.) using Radix + Tailwind. |
@stack/ui-primitives |
Thin re-export of 27 Radix UI packages. |
@stack/ui-core |
cn() utility, cva, clsx, twMerge, Logo component. |
@stack/scripts |
Shell scripts for app orchestration: entrypoint.sh, devshell detection, secret loading (AGE + vals + chamber). |
@stack/docs-content |
Raw MDX guide content, importable as strings. |
@stack/infra |
SST IaC: GitHub OIDC, IAM roles, KMS keys for secrets. |
znv |
Vendored Zod-based env parser (parseEnv()). |
All packages use the exports field with . and ./* patterns. Source TypeScript is exported directly (no build step) -- bundlers handle transpilation. Internal dependencies use workspace:*.
Two-layer system:
- Local AGE identity: Auto-generated on shell entry at
.stack/keys/local.txtfor SOPS decryption. - SOPS-encrypted YAML: Secret files live in
.stack/secrets/vars/*.sops.yamland use# safe/# plaintextcomments for unencrypted values.
Codegen: Nix generates the env package under packages/gen/env/src/, including typed TypeScript modules, embedded encrypted payloads, and runtime loaders.
Runtime resolution chain: secrets:env script -> AGE decryption -> vals (SSM/Vault/SOPS) -> env files -> chamber (AWS SSM).
| Path | Purpose |
|---|---|
config.nix |
Primary user-editable config (apps, services, users, theme, IDE, AWS, Step CA) |
_internal.nix |
Merge point: data/*.nix + config.nix + GitHub collaborators + local overrides |
devenv.nix |
Devenv-specific: languages, packages, git-hooks |
config.local.nix |
Per-user gitignored overrides |
data/*.nix |
Auto-loaded data tables (apps, variables, secrets, sst, aws, ide, theme, tasks, commands, users, step-ca, packages) |
modules/default.nix |
User extension modules |
secrets/ |
SOPS config, encrypted YAML files, AGE keys |
| Path | Purpose |
|---|---|
state/stack.json |
Runtime state: evaluated apps, services, ports, URLs, extensions |
state/shellhook.sh |
Generated shell hook |
state/starship.toml |
Generated prompt config |
state/keys/ |
Local AGE key pair |
state/step/ |
Device certificates |
gen/config.json |
Full evaluated Nix config as JSON |
gen/ide/vscode/ |
VS Code workspace + devshell loader |
gen/zed/ |
Zed settings + devshell loader |
data/*.nix(defaults)config.nix(user config)external/github-collaborators.nix(auto-synced)config.local.nix(gitignored overrides)STACKPANEL_CONFIG_OVERRIDEenv var (CI)
Strict phase ordering on devshell entry:
hooks.before
-> Clean aliases, set strict mode
-> Path utilities + root resolution
-> Directory creation (state/, gen/)
-> Marker file + .gitignore
-> CLI init: stack init --config '${configJson}'
-> State file generation
-> Auto-generate local master key
-> Shell hash computation
hooks.main
-> Service shell hooks
-> Caddy site registration
-> Step CA interactive setup
hooks.after
-> Module init confirmation
-> MOTD display
-> Port information
-> Alias setup (sp, spx, x)
- Monorepo orchestration: Turborepo (JS/TS tasks) + Nix (dev environment)
- Package manager: Bun with workspaces
- Web deployment: Cloudflare Workers via Alchemy + Vite Cloudflare plugin
- Docs deployment: Static export to Cloudflare
- Infrastructure: SST + Pulumi (AWS OIDC, KMS, IAM)
- Go build:
gomod2nixfor Nix,airfor hot reload in dev - CI: GitHub Actions with OIDC-based AWS access
- Nix modules implement behavior once in
nix/stack/lib/, called from thin adapter modules - The Go CLI is the single writer for generated files (avoids symlink issues, ensures atomicity)
- Proto definitions in
packages/proto/are the contract between Go agent and TypeScript web app - Environment variables follow the pattern
STACKPANEL_<KEY>_<PROPERTY>(e.g.,STACKPANEL_POSTGRES_PORT) - All user-editable config uses YAML/Nix with JSON Schema validation for IDE intellisense
This is a stack project created with Better-T-Stack CLI.
This is a monorepo with the following structure:
-
apps/web/- Frontend application (React with TanStack Router) -
apps/server/- Backend server (Hono) -
packages/api/- Shared API logic and types -
packages/auth/- Authentication logic and utilities -
packages/db/- Database schema and utilities
bun run dev- Start all apps in development modebun run dev:web- Start only the web appbun run dev:server- Start only the server
All database operations should be run from the server workspace:
bun run db:push- Push schema changes to databasebun run db:studio- Open database studiobun run db:generate- Generate Prisma filesbun run db:migrate- Run database migrations
Database schema is located in apps/server/prisma/schema.prisma
- tRPC routers are in
apps/server/src/routers/ - Client-side tRPC utils are in
apps/web/src/utils/trpc.ts
Authentication is enabled in this project:
- Server auth logic is in
apps/server/src/lib/auth.ts - Web app auth client is in
apps/web/src/lib/auth-client.ts
You can add additional addons or deployment options to your project using:
bunx create-better-t-stack
addAvailable addons you can add:
- Documentation: Starlight, Fumadocs
- Linting: Biome, Oxlint, Ultracite
- Other: Ruler, Turborepo, PWA, Tauri, Husky
You can also add web deployment configurations like Cloudflare Workers support.
This project includes a bts.jsonc configuration file that stores your Better-T-Stack settings:
- Contains your selected stack configuration (database, ORM, backend, frontend, etc.)
- Used by the CLI to understand your project structure
- Safe to delete if not needed
- Updated automatically when using the
addcommand
- This is a Turborepo monorepo using bun workspaces
- Each app has its own
package.jsonand dependencies - Run commands from the root to execute across all workspaces
- Run workspace-specific commands with
bun run command-name - Turborepo handles build caching and parallel execution
- Use
bunx create-better-t-stack addto add more features later
- To enter the devshell:
nix develop --impure - Run ALL commands in the nix shell otherwise you will be using the wrong binaries.
- After you finish a task, ALWAYS try entering the devshell either by using the
devshellscript ornix develop --impure - Do NOT assume
devenv shellwill be used.
Stack is a Nix-based development environment framework that provides:
- Consistent dev environments via devenv/Nix with reproducible shells
- Multi-app monorepo support with automatic port assignment and Caddy reverse proxy
- Secrets management with SOPS/vals integration and per-app codegen
- IDE integration with VS Code workspace generation
- Service orchestration for PostgreSQL, Redis, Minio, etc.
.
├── .stack/ # Stack configuration (checked in)
│ ├── .gitignore # Ignores state/ only
│ ├── gen/ # Generated files (checked in, regenerated on devenv)
│ │ ├── ide/vscode/ # VS Code workspace and devshell loader
│ │ └── schemas/secrets/ # JSON schemas for YAML intellisense
│ ├── secrets/ # Secrets configuration
│ │ ├── config.yaml # Global secrets settings
│ │ ├── users.yaml # Team members and AGE keys
│ │ └── apps/{appName}/ # Per-app secret schemas
│ │ ├── config.yaml # Codegen settings (language, path)
│ │ ├── common.yaml # Shared schema across environments
│ │ ├── dev.yaml # Dev-specific schema + access
│ │ ├── staging.yaml # Staging-specific schema + access
│ │ └── prod.yaml # Production-specific schema + access
│ └── state/ # Runtime state (gitignored)
│ └── stack.json # State file for CLI/agent
│
├── apps/ # Application packages
│ ├── web/ # React frontend (TanStack Router)
│ ├── server/ # Hono backend (Cloudflare Workers)
│ ├── fumadocs/ # Documentation site
│ ├── cli/ # Go CLI for service management
│ └── agent/ # Go agent for remote operations
│
├── packages/ # Shared packages
│ ├── api/ # tRPC routers and types
│ ├── auth/ # Better-Auth logic
│ ├── db/ # Drizzle schema and utilities
│ ├── ui/ # Shared UI components
│ └── config/ # Shared TypeScript config
│
├── nix/ # Nix modules and libraries
│ ├── modules/ # Stack modules (options + config)
│ │ ├── stack.nix # Core module (dirs, motd, direnv)
│ │ ├── apps.nix # App definitions and port assignment
│ │ ├── ports.nix # Deterministic port allocation
│ │ ├── ide.nix # VS Code integration
│ │ ├── secrets/ # SOPS/vals secrets module
│ │ │ ├── secrets.nix # Main secrets module
│ │ │ ├── codegen.nix # TypeScript/Python/Go env codegen
│ │ │ ├── schemas.nix # JSON schema generation
│ │ │ └── ...
│ │ └── ...
│ ├── lib/ # Pure library functions
│ │ ├── services/ # Service helpers (postgres, redis, minio)
│ │ └── integrations/ # IDE integration utilities
│ └── templates/ # Project templates
│
├── tooling/ # Build tooling
│ ├── alchemy/ # Alchemy IaC scripts
│ └── devenv/ # Additional devenv config
│
├── devenv.nix # Main devenv configuration
├── devenv.yaml # Devenv inputs
└── flake.nix # Nix flake for flake-parts integration
Stack assigns deterministic ports based on a hash of the project name, ensuring each project gets a unique, predictable port range that won't conflict with other stack projects.
Computation Algorithm (in nix/modules/ports.nix):
- Hash the project name using MD5
- Convert first 8 hex chars to decimal
- Constrain to range:
minPort + (hash % portRange) - Round down to nearest
modulus(default 100) for clean port numbers
Default Parameters:
minPort: 3000 (minimum base port)maxPort: 65000 (maximum base port)modulus: 100 (ports round to nearest 100)
Port Layout:
- Apps get ports at
basePort + 0-9(sequential by definition order) - Services get ports at
basePort + 10-99(sequential by registration order)
Example for project stack:
Base port: 6400
Apps:
fumadocs → 6400
server → 6401
web → 6402
Services:
postgres → 6410
redis → 6411
minio → 6412
Environment Variables:
Each service port is exposed as STACKPANEL_<KEY>_PORT:
STACKPANEL_POSTGRES_PORT=6410
STACKPANEL_REDIS_PORT=6411
STACKPANEL_MINIO_PORT=6412Benefits:
- Same ports across all team members (deterministic from project name)
- No manual port configuration needed
- Projects don't conflict when running simultaneously
- Clean, memorable port numbers (rounded to modulus)
Secrets use a per-app architecture with environment inheritance:
common.yamldefines schema shared across all environments{env}.yamlextends/overrides common schema and defines access control- Codegen generates type-safe env access for TypeScript/Python/Go
Files in .stack/gen/ are regenerated on each devenv run:
- Should be checked into git for IDE functionality without devenv
- JSON schemas enable YAML intellisense in VS Code
- Workspace file configures terminal integration
The state file (.stack/state/stack.json) is generated on each devenv shell entry and provides the Go CLI and agent with access to the current devenv configuration without evaluating Nix.
Location: .stack/state/stack.json (gitignored)
Contents:
{
"version": 1,
"projectName": "stack",
"basePort": 6400,
"paths": {
"state": ".stack/state",
"gen": ".stack/gen",
"data": ".stack"
},
"apps": {
"web": { "port": 6402, "domain": "stack.localhost", "url": "http://stack.localhost", "tls": false },
"server": { "port": 6401, "domain": null, "url": null, "tls": false }
},
"services": {
"postgres": { "key": "POSTGRES", "name": "PostgreSQL", "port": 6410, "envVar": "STACKPANEL_POSTGRES_PORT" },
"redis": { "key": "REDIS", "name": "Redis", "port": 6411, "envVar": "STACKPANEL_REDIS_PORT" }
},
"network": {
"step": { "enable": true, "caUrl": "https://ca.internal:443" }
}
}For tools that need always-fresh config without state file drift, use nix eval:
# Within devenv shell (uses STACKPANEL_CONFIG_JSON env var for pre-computed JSON)
nix eval --impure --json --expr 'builtins.fromJSON (builtins.readFile (builtins.getEnv "STACKPANEL_CONFIG_JSON"))'
# Or import the source Nix config directly (uses STACKPANEL_NIX_CONFIG)
nix eval --impure --json --expr 'import (builtins.getEnv "STACKPANEL_NIX_CONFIG")'
# Returns same structure as state.json but directly from NixGo Usage (with fallback):
import "github.com/darkmatter/stack/cli/state"
// Load tries nix eval first, falls back to state file
st, err := state.Load("")
if err == nil {
fmt.Println("Project:", st.ProjectName)
fmt.Println("Postgres port:", st.GetServicePort("postgres"))
}
// Force state file only (skip nix eval)
st, err := state.Load("", state.WithNixEval(false))
}Environment Variables:
STACKPANEL_STATE_FILE: Full path to state fileSTACKPANEL_STATE_DIR: Directory containing state file
# Enter development shell
nix develop --impure # or: direnv allow (with .envrc)
# Start all dev processes (web, docs, server, etc.)
dev # Uses process-compose
# Individual commands
bun install # Install dependencies
bun run dev # Start dev servers
stack status # Check service status
stack services start # Start PostgreSQL, Redis, etc.When creating or modifying Nix modules:
- Options go in
options.stack.*- Follow the existing pattern - Use
lib.mkOptionwith descriptions - Document all options - Config uses
lib.mkIf cfg.enable- Guard config blocks - File generation via CLI - Add data to
cli-generate.nixconfig, notdevenv.files - Library functions go in
nix/lib/- Keep modules focused on options/config
When adding new generated files:
- Add the data to
fullConfiginnix/modules/cli-generate.nix - Add generation logic in
apps/cli/generator/generator.go - The CLI handles writing real files (avoiding symlink issues)
All user-editable config files use YAML with JSON Schema validation:
- Schemas are generated from Nix in
.stack/gen/schemas/ - VS Code workspace maps schemas to file patterns
- Install the Red Hat YAML extension for intellisense
The docs for stack are in apps/docs/content - ALWAYS give the docs a quick scan so that you understand stack.
- Primary entrypoint:
nix develop --impure(ordirenv allow) - Devenv compatibility: Stack modules work in devenv.shells for external users
- Make it obvious what is:
- core logic (reusable)
- module adapter (options + wiring)
- Remove duplication between modules and libraries.
nix/stack/lib/: shared behavior (pure-ish functions for ports, theme, IDE, services, etc.)nix/stack/core/: core schema, state, CLI integrationnix/stack/modules/: thin adapters (options + wiring for bun, go, turbo, git-hooks, process-compose)nix/stack/services/: service modules (aws, caddy, global-services, binary-cache)nix/stack/network/: network modules (ports, step-ca)nix/stack/ide/: IDE integration (vscode)nix/stack/secrets/: secrets management (agenix, schemas, codegen)- Entrypoints
nix/stack/default.nix: main module aggregatornix/flake/devenv.nix: devenv integrationflake.nix: exportsflake.lib.*,flake.devenvModules.*
- Single source of truth: implement behavior once (lib), call it from modules.
- Modules stay thin: avoid duplicating computation.
- Purity by default: impure reads must be explicit and optional.
- Compatibility: prefer shims/deprecations over breaking moves.
- Create shared core for global services:
nix/stack/services/global-services.nix - Ports module with deterministic port computation:
nix/stack/network/ports.nix - Caddy module:
nix/stack/services/caddy.nix - Network / Step CA:
nix/stack/network/network.nix - AWS Roles Anywhere:
nix/stack/services/aws.nix - Theme / starship:
nix/stack/lib/theme.nix - IDE integration:
nix/stack/ide/ide.nix - Secrets management:
nix/stack/secrets/ - SST infrastructure module:
nix/stack/sst/sst.nix - Process-compose:
nix/stack/modules/process-compose.nix - Git hooks:
nix/stack/modules/git-hooks.nix - CLI state integration:
nix/stack/core/state.nix
- Centralize shared option types/defaults in
nix/stack/core/options/so both adapters share one schema. - Update docs to recommend
nix/stackimport path everywhere.
The codebase follows a consistent pattern:
- Libraries (
nix/stack/lib/*.nix): Pure functions that implement behavior - Core (
nix/stack/core/*.nix): Schema definitions, state management, CLI integration - Modules (
nix/stack/modules/*.nix): Thin adapters for specific tooling (bun, go, turbo, etc.) - Services (
nix/stack/services/*.nix): Service-specific modules (aws, caddy, global-services) - Network (
nix/stack/network/*.nix): Networking modules (ports, step-ca) - IDE (
nix/stack/ide/*.nix): IDE integration (vscode workspace, terminal profiles) - Secrets (
nix/stack/secrets/*.nix): Secrets management (agenix, schemas, wrapped)
Always prefix commands with rtk. If RTK has a dedicated filter, it uses it. If not, it passes through unchanged. This means RTK is always safe to use.
Important: Even in command chains with &&, use rtk:
# ❌ Wrong
git add . && git commit -m "msg" && git push
# ✅ Correct
rtk git add . && rtk git commit -m "msg" && rtk git pushrtk cargo build # Cargo build output
rtk cargo check # Cargo check output
rtk cargo clippy # Clippy warnings grouped by file (80%)
rtk tsc # TypeScript errors grouped by file/code (83%)
rtk lint # ESLint/Biome violations grouped (84%)
rtk prettier --check # Files needing format only (70%)
rtk next build # Next.js build with route metrics (87%)rtk cargo test # Cargo test failures only (90%)
rtk vitest run # Vitest failures only (99.5%)
rtk playwright test # Playwright failures only (94%)
rtk test <cmd> # Generic test wrapper - failures onlyrtk git status # Compact status
rtk git log # Compact log (works with all git flags)
rtk git diff # Compact diff (80%)
rtk git show # Compact show (80%)
rtk git add # Ultra-compact confirmations (59%)
rtk git commit # Ultra-compact confirmations (59%)
rtk git push # Ultra-compact confirmations
rtk git pull # Ultra-compact confirmations
rtk git branch # Compact branch list
rtk git fetch # Compact fetch
rtk git stash # Compact stash
rtk git worktree # Compact worktreeNote: Git passthrough works for ALL subcommands, even those not explicitly listed.
rtk gh pr view <num> # Compact PR view (87%)
rtk gh pr checks # Compact PR checks (79%)
rtk gh run list # Compact workflow runs (82%)
rtk gh issue list # Compact issue list (80%)
rtk gh api # Compact API responses (26%)rtk pnpm list # Compact dependency tree (70%)
rtk pnpm outdated # Compact outdated packages (80%)
rtk pnpm install # Compact install output (90%)
rtk npm run <script> # Compact npm script output
rtk npx <cmd> # Compact npx command output
rtk prisma # Prisma without ASCII art (88%)rtk ls <path> # Tree format, compact (65%)
rtk read <file> # Code reading with filtering (60%)
rtk grep <pattern> # Search grouped by file (75%)
rtk find <pattern> # Find grouped by directory (70%)rtk err <cmd> # Filter errors only from any command
rtk log <file> # Deduplicated logs with counts
rtk json <file> # JSON structure without values
rtk deps # Dependency overview
rtk env # Environment variables compact
rtk summary <cmd> # Smart summary of command output
rtk diff # Ultra-compact diffsrtk docker ps # Compact container list
rtk docker images # Compact image list
rtk docker logs <c> # Deduplicated logs
rtk kubectl get # Compact resource list
rtk kubectl logs # Deduplicated pod logsrtk curl <url> # Compact HTTP responses (70%)
rtk wget <url> # Compact download output (65%)rtk gain # View token savings statistics
rtk gain --history # View command history with savings
rtk discover # Analyze Claude Code sessions for missed RTK usage
rtk proxy <cmd> # Run command without filtering (for debugging)
rtk init # Add RTK instructions to CLAUDE.md
rtk init --global # Add RTK to ~/.claude/CLAUDE.md| Category | Commands | Typical Savings |
|---|---|---|
| Tests | vitest, playwright, cargo test | 90-99% |
| Build | next, tsc, lint, prettier | 70-87% |
| Git | status, log, diff, add, commit | 59-80% |
| GitHub | gh pr, gh run, gh issue | 26-87% |
| Package Managers | pnpm, npm, npx | 70-90% |
| Files | ls, read, grep, find | 60-75% |
| Infrastructure | docker, kubectl | 85% |
| Network | curl, wget | 65-70% |
Overall average: 60-90% token reduction on common development operations.
This project uses bd (beads) for issue tracking. Run bd prime to see full workflow context and commands.
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work- Use
bdfor ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists - Run
bd primefor detailed command reference and session close protocol - Use
bd rememberfor persistent knowledge — do NOT use MEMORY.md files
When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.
MANDATORY WORKFLOW:
- File issues for remaining work - Create issues for anything that needs follow-up
- Run quality gates (if code changed) - Tests, linters, builds
- Update issue status - Close finished work, update in-progress items
- PUSH TO REMOTE - This is MANDATORY:
git pull --rebase bd dolt push git push git status # MUST show "up to date with origin" - Clean up - Clear stashes, prune remote branches
- Verify - All changes committed AND pushed
- Hand off - Provide context for next session
CRITICAL RULES:
- Work is NOT complete until
git pushsucceeds - NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called vp. Vite+ is distinct from Vite, but it invokes Vite through vp dev and vp build.
vp is a global binary that handles the full development lifecycle. Run vp help to print a list of commands and vp <command> --help for information about a specific command.
- create - Create a new project from a template
- migrate - Migrate an existing project to Vite+
- config - Configure hooks and agent integration
- staged - Run linters on staged files
- install (
i) - Install dependencies - env - Manage Node.js versions
- dev - Run the development server
- check - Run format, lint, and TypeScript type checks
- lint - Lint code
- fmt - Format code
- test - Run tests
- run - Run monorepo tasks
- exec - Execute a command from local
node_modules/.bin - dlx - Execute a package binary without installing it as a dependency
- cache - Manage the task cache
- build - Build for production
- pack - Build libraries
- preview - Preview production build
Vite+ automatically detects and wraps the underlying package manager such as pnpm, npm, or Yarn through the packageManager field in package.json or package manager-specific lockfiles.
- add - Add packages to dependencies
- remove (
rm,un,uninstall) - Remove packages from dependencies - update (
up) - Update packages to latest versions - dedupe - Deduplicate dependencies
- outdated - Check for outdated packages
- list (
ls) - List installed packages - why (
explain) - Show why a package is installed - info (
view,show) - View package information from the registry - link (
ln) / unlink - Manage local package links - pm - Forward a command to the package manager
- upgrade - Update
vpitself to the latest version
These commands map to their corresponding tools. For example, vp dev --port 3000 runs Vite's dev server and works the same as Vite. vp test runs JavaScript tests through the bundled Vitest. The version of all tools can be checked using vp --version. This is useful when researching documentation, features, and bugs.
- Using the package manager directly: Do not use pnpm, npm, or Yarn directly. Vite+ can handle all package manager operations.
- Always use Vite commands to run tools: Don't attempt to run
vp vitestorvp oxlint. They do not exist. Usevp testandvp lintinstead. - Running scripts: Vite+ built-in commands (
vp dev,vp build,vp test, etc.) always run the Vite+ built-in tool, not anypackage.jsonscript of the same name. To run a custom script that shares a name with a built-in command, usevp run <script>. For example, if you have a customdevscript that runs multiple services concurrently, run it withvp run dev, notvp dev(which always starts Vite's dev server). - Do not install Vitest, Oxlint, Oxfmt, or tsdown directly: Vite+ wraps these tools. They must not be installed directly. You cannot upgrade these tools by installing their latest versions. Always use Vite+ commands.
- Use Vite+ wrappers for one-off binaries: Use
vp dlxinstead of package-manager-specificdlx/npxcommands. - Import JavaScript modules from
vite-plus: Instead of importing fromviteorvitest, all modules should be imported from the project'svite-plusdependency. For example,import { defineConfig } from 'vite-plus';orimport { expect, test, vi } from 'vite-plus/test';. You must not installvitestto import test utilities. - Type-Aware Linting: There is no need to install
oxlint-tsgolint,vp lint --type-awareworks out of the box.
For GitHub Actions, consider using voidzero-dev/setup-vp to replace separate actions/setup-node, package-manager setup, cache, and install steps with a single action.
- uses: voidzero-dev/setup-vp@v1
with:
cache: true
- run: vp check
- run: vp test- Run
vp installafter pulling remote changes and before getting started. - Run
vp checkandvp testto validate changes.