devx

command module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 1 Imported by: 0

README

devx

Develop multiple features in parallel with instant switching and zero port conflicts.

devx is a terminal-based development environment manager that makes it trivial to work on multiple features simultaneously. Each session gets its own git worktree, unique ports, HTTPS hostnames via Caddy, and tmux session—all managed through an interactive TUI or CLI.

Browse all your sessions at a glance, see their real-time status, and switch between them instantly. No more stashing changes, juggling ports, or losing context. Just lightweight, isolated environments that spin up in seconds.

Built on battle-tested open tools (tmuxp, Caddy, direnv) with powerful configuration options—use the defaults or customize every detail.

devx TUI demo

Features

Terminal Interface
  • Interactive TUI: Browse all sessions, see real-time tmux previews, and manage everything with keyboard shortcuts
  • Live Session Preview: Watch your tmux sessions update in real-time without attaching
  • Attention Flags: Mark sessions that need review (perfect for AI coding workflows)
  • Quick Switching: Jump between sessions instantly—no stashing, no context loss
Parallel Development
  • Git Worktrees: Each session is an isolated worktree with its own branch
  • Zero Port Conflicts: Automatic unique port allocation per session
  • HTTPS Hostnames: Caddy integration gives each service a .localhost domain (e.g., https://my-feature-api.localhost)
  • Environment Variables: Auto-generated .envrc files with ports and hostnames for each session
Developer Experience
  • tmux Integration: Pre-configured sessions with customizable layouts via tmuxp templates
  • Editor Integration: Auto-launch Cursor, VS Code, or any editor when creating/attaching to sessions
  • Bootstrap Files: Copy setup files (.env.example, scripts) into each new worktree automatically
  • Cleanup Commands: Run teardown scripts (Docker cleanup, database drops) when removing sessions
Configuration & Reliability
  • Project-Level Config: Team-shareable .devx/ configs that override global settings
  • Caddy Health Monitoring: Automatic route verification and repair
  • Dependency Checking: Validates required tools with installation guidance
  • Fully Customizable: Built on open tools (tmuxp, Caddy, direnv)—configure or replace any part

Documentation versions

This README documents v0.4.0. Homebrew, go install ...@latest, the universal installer, and direct release downloads install the latest published release; they do not install unreleased changes from main.

  • Check devx version and use the README at that release tag: v0.4.0 or v0.3.0. Version v0.3.0 does not have devx artifact, devx agent, or devx ask.
  • To work on unreleased changes, build from source from main. A development build is not a published release.

Dependencies

Core worktrees
  • Git: For worktree management
  • Go 1.23+: For building the tool (Go 1.26.9+ recommended; older toolchains compile in known standard-library vulnerabilities)
Optional features
  • tmux and tmuxp: Required for persistent terminal sessions, but optional for worktree creation. macOS does not bundle tmux. On macOS, install with brew install tmux pipx, pipx ensurepath, and pipx install tmuxp, then start a new shell so pipx's app directory is on PATH. On Linux, install tmux and pipx with your distribution's package manager, then run the same two pipx commands and start a new shell. See the pipx installation guide.
  • direnv: For automatic environment variable loading (brew install direnv).
  • Caddy: For local proxy routing (brew install caddy). Set disable_caddy: true in your config when you only need worktrees and ports.

Run devx check to see what is available. Git is the core requirement; the checker lists terminal and routing tools as optional and explains which features use them.

Installation

Homebrew (macOS & Linux)
brew tap jfox85/homebrew-devx
brew install devx
go install github.com/jfox85/devx@latest

go install pkg@version builds with your local Go toolchain (the module's toolchain line is ignored), so use Go 1.26.9 or newer to pick up current standard-library security fixes. Homebrew and release binaries are already built with the pinned toolchain.

Universal install script
curl -fsSL https://raw.githubusercontent.com/jfox85/devx/main/install/install.sh | bash

Set DEVX_INSTALL_DIR or DEVX_VERSION to customize the installation:

curl -fsSL https://raw.githubusercontent.com/jfox85/devx/main/install/install.sh \
  | DEVX_INSTALL_DIR=$HOME/.local/bin DEVX_VERSION=v1.2.3 bash
Direct binary download

Download the appropriate archive from the releases page, extract it, and move the devx binary into your PATH.

Build from source
git clone https://github.com/jfox85/devx
cd devx
make build
# Move to your PATH, e.g.:
mv devx /usr/local/bin/

Alternative build targets:

# Development build (no version info)
make dev

# Install directly to GOPATH/bin
make install

# Build manually without Makefile
go build -o devx main.go

Reproducible local install (recommended for day-to-day use):

# Build origin/main in a clean throwaway worktree and install to GOPATH/bin
make install-local
# Also rebuild and install /Applications/DevX.app (quit the app first)
scripts/install-local.sh --app
# Build a specific pushed ref instead of origin/main
scripts/install-local.sh --ref v1.2.3

install-local builds only commits that exist on the remote. Your uncommitted edits never reach the installed binary. It verifies that devx version reports the commit it built and keeps the previous binary as devx.previous. Restart any running devx web afterwards.

Quick Start

  1. Initialize configuration:

    devx config init
    

    In v0.4.0 and newer, this creates ~/.config/devx/config.yaml and session.yaml.tmpl, preserving any existing files. Use devx --config PATH config init for a different config destination. On v0.3.0, initialization creates only the template; create config.yaml from the global config example before copying it into a project.

  2. Navigate to your Git repository and create a session:

    cd /path/to/your/project
    devx session create feature-branch
    

    For a minimal setup without tmux/tmuxp, set disable_caddy: true in ~/.config/devx/config.yaml and run:

    devx session create feature-branch --no-tmux
    

    The worktree and ports are usable immediately. After installing terminal dependencies, open the existing session with devx session attach feature-branch.

  3. This will:

    • Create a Git worktree at .worktrees/feature-branch
    • Allocate unique ports for your services
    • Generate .envrc with environment variables
    • Generate .tmuxp.yaml with session configuration
    • Launch a tmux session (if tmux/tmuxp available)
    • Create HTTPS routes via Caddy (if enabled and available)

Configuration

Project-Level Configuration

devx supports project-level configuration that takes precedence over global settings. This is perfect for team projects or repositories with specific requirements.

Create a project-level config:

# In your project root
mkdir .devx
cp ~/.config/devx/config.yaml .devx/config.yaml
# Edit .devx/config.yaml as needed

Project-level files:

  • .devx/config.yaml - Project-specific configuration
  • .devx/sessions.json - Project-specific sessions (isolated from global)
  • .devx/session.yaml.tmpl - Project-specific tmux template

Configuration Discovery: devx walks up the directory tree looking for a .devx directory, starting from your current working directory. If found, it uses project-level configs first, then falls back to global configs.

Benefits:

  • Team projects can share consistent devx configuration
  • Different projects can have different port configurations
  • Project sessions are isolated from global sessions
  • Custom tmux templates per project
Global Configuration

Global configuration is stored in ~/.config/devx/config.yaml:

basedomain: localhost
caddy_api: http://localhost:2019
tmuxp_template: ~/.config/devx/session.yaml.tmpl
disable_caddy: false
editor: ""  # Uses VISUAL or EDITOR env vars if empty
ports:
  - ui
  - api
bootstrap_files:  # Files to copy from project root to each new worktree
  - .env.example
  - scripts/setup.sh
  - config/local.json
cleanup_command: ""  # Command to run when removing sessions (optional)
View Configuration
devx config view
Update Configuration
# Set individual values
devx config set basedomain "dev.local"
devx config set caddy_api "http://localhost:2020"

# Configure services
devx config set ports "ui,api,database,cache"
# or with JSON array
devx config set ports '["ui", "api", "database"]'

# Disable Caddy integration
devx config set disable_caddy true

# Configure preferred editor
devx config set editor "cursor"
devx config set editor "code"  # VS Code
devx config set editor "nvim"  # Neovim

# Configure bootstrap files (copy from project root to each new worktree)
devx config set bootstrap_files ".env.example,scripts/setup.sh,config/local.json"
# or with JSON array
devx config set bootstrap_files '["docker-compose.local.yml", "scripts/init.sh"]'

# Configure cleanup command (runs when removing sessions)
devx config set cleanup_command "scripts/teardown.sh"
devx config set cleanup_command "docker-compose -f docker-compose.local.yml down"
Environment Variable Overrides

Any configuration value can be overridden with environment variables using the DEVX_ prefix:

DEVX_BASEDOMAIN=custom.local devx config view

Gatepost target

DevX can launch a session behind Gatepost with:

devx session create my-session --target gatepost

The first runtime is docker-mitmproxy: DevX starts an agent container on an internal-only network plus a Gatepost proxy container with egress. Gatepost owns policy, secret injection, event ingestion, smart evaluation, and audit logs; DevX stores only the capability metadata needed for lifecycle, bypass, and links.

Useful user-global config (~/.config/devx/config.yaml; executable Gatepost commands are intentionally not trusted from project .devx/config.yaml):

web_secret_token: "..."              # required for `devx web`
gatepost:
  agent_image: gatepost-pi-agent:latest
  # Prefer packaged commands when available:
  logs_command: gatepost-logs
  provider_bootstrap_command: gatepost-provider-bootstrap
  # Source checkout fallback for local development:
  root: /path/to/gatepost-checkout
  # Optional: use real Pi auth while testing with a temporary HOME.
  auth_home: ~/.pi-auth-home
  # Comma-separated readiness gate. For the full Pi/subscription setup,
  # fail session creation unless all expected providers registered.
  required_providers: anthropic-oauth,codex-oauth,openai-key

Provider credentials are registered from the host into Gatepost; the agent receives placeholders only. Credentials can come from the Gatepost provider bootstrap helper or host env (OPENAI_API_KEY, GEMINI_API_KEY, CLIPROXYAPI_API_KEY). Session metadata records the provider bootstrap mode, registered providers, and warnings so partial provider readiness is visible. The initial policy broadly allows common AI provider destinations and sends unknown traffic to smart evaluation. Gatepost Logs are linked from the DevX web UI and shown in TUI session details via the DevX web redirect.

Emergency host-side controls:

devx session gatepost bypass <session>
devx session gatepost enforce <session>

These commands mutate Docker network attachment from the host/orchestrator side; the agent does not receive the Gatepost control token or Docker socket.

Usage

Terminal User Interface (TUI)

Launch the interactive TUI to browse and manage sessions:

devx

TUI Features:

  • Session Browser: Navigate sessions with arrow keys or vim bindings (j/k); sessions default to recent activity order
  • Pinned Sessions: Press * to pin/unpin the selected session in a global section
  • Session Views: Press v to switch between recent activity and project-grouped ordering; the TUI preference is stored in user-local UI state
  • Live Preview: View tmux session content in real-time
  • Attention Flags: Visual indicators (🔔) for sessions needing attention
  • Quick Actions:
    • Enter: Attach to selected session
    • c: Create new session
    • r: Remove selected session
    • *: Pin or unpin selected session
    • v: Switch Recent / Projects view
    • ?: Toggle help
    • q: Quit

Attention Flags in TUI:

  • Flagged sessions appear with a bell icon (🔔) and are sorted to the top
  • Preview pane shows attention banner with reason and timestamp
  • Flags are automatically cleared when you attach to a session
Session Management
Create a Session
# Create with default/configured ports
devx session create my-feature

# Create with custom ports (legacy)
devx session create my-feature --fe-port 8080 --api-port 8081

# Create without launching tmux
devx session create my-feature --no-tmux

# Handle existing worktree conflicts
devx session create my-feature --detach
List Sessions
# View all active sessions with status
devx session list

# Example output:
# NAME               BRANCH             PORTS                    HOSTS                               STATUS
# feature-auth       feature-auth       WEB:3000,API:3001       ui.localhost,api.localhost         tmux:attached,editor:running
# hotfix-bug         hotfix-bug         WEB:3002,API:3003       ui.localhost,api.localhost         tmux:detached,editor:stopped
Agent Session Context and Asks
# Print agent-friendly metadata for all sessions, including paths, branches,
# git dirty/clean state, service ports, and local URLs.
devx session context --json

# Ask another session a question. By default this creates a pending approval
# request under ~/.config/devx/asks.
devx ask backend "What API endpoint should the frontend use?"

# Approve or deny pending asks from the CLI. The TUI and web/desktop app also
# surface pending asks as explicit approval prompts.
devx ask pending
devx ask approve req_abc123
devx ask approve req_abc123 --always  # remember this requester/target pair
devx ask deny req_abc123

Responder execution is opt-in via the owner config ~/.config/devx/config.yaml (or --config). The responder runs a local command, so its settings are read only from that file: a project .devx/config.yaml and DEVX_* environment variables cannot enable it, change its mode or choose its command. On macOS and Linux the file must also be owned by you and not group/world-writable; Windows has no such ownership check, so there the file's ACL is what protects it. An unreadable or invalid agent_responder section disables the responder.

agent_responder:
  enabled: true
  mode: approval # none | approval | always
  command: pi
  args: ["--print", "--no-session", "@{{.PromptFile}}"]
  timeout: 5m
  read_only: true # prompt instruction only; not a filesystem sandbox
Attach to Session
# Attach to existing session (launches tmux and editor)
devx session attach my-feature

# This will:
# - Attach to the tmux session if it exists
# - Launch editor if configured and not running
# - Relaunch editor if it was closed
Recover After a Crash or Reboot

Worktrees, session metadata and Pi conversations survive a crash; only the tmux server and the processes in it are lost. devx session recover brings them back:

# See what would be recovered (changes nothing)
devx session recover --dry-run

# Recreate missing tmux sessions (from .tmuxp.yaml) and relaunch crashed
# managed Pi agents (same conversation) for sessions active in the last 24h
devx session recover

# Widen the window, or pick sessions explicitly
devx session recover --since 72h
devx session recover my-feature other-feature
devx session recover --all

Running tmux sessions are never killed or modified (crashed agents inside them are still relaunched), and a session whose -web viewer survived is skipped rather than started twice. Managed agents are relaunched only when their Pi and its tmux pane are confirmed gone and Pi was last seen within --since; a Pi that exited while its pane stayed open is skipped unless you pass --include-exited, and adopted agents must be re-adopted by hand. --dry-run changes no session, agent or task state. Recreating a session runs its .tmuxp.yaml just like devx session attach, so check the dry run before --all. Prefer this over tmux-resurrect for DevX sessions: a restored session with the same name makes DevX skip its template.

Remove Session
# Clean up session completely
devx session rm my-feature

# This removes:
# - tmux session
# - Editor processes
# - Caddy HTTPS routes  
# - Git worktree
# - Session metadata
Session Attention Flags

Mark sessions for attention (perfect for Claude Code integration):

# Flag a session with a reason
devx session flag my-feature "Ready for review"

# Flag without a reason
devx session flag my-feature

# Unflag a session
devx session flag my-feature --clear

# Force flag even if it's the current session
devx session flag my-feature "Force flag" --force

Attention Flag Features:

  • Visual indicators in TUI and session list
  • Automatic clearing when attaching to session
  • Cannot flag the currently active session (use --force to override)
  • Timestamps track when flags were set
  • Flags are sorted to the top in TUI
Bootstrap Files

Automatically copy files from your project root to each new worktree. Perfect for config files, setup scripts, and environment templates that you need but don't want to commit to the repository.

Configure bootstrap files:

# Add files to copy
devx config set bootstrap_files ".env.example,scripts/setup.sh,docker-compose.local.yml"

# View current bootstrap files
devx config get bootstrap_files

Example bootstrap_files configuration:

bootstrap_files:
  - .env.example          # Environment template
  - scripts/setup.sh      # Setup script
  - scripts/init.sh       # Initialization script
  - config/local.json     # Local configuration
  - docker-compose.local.yml  # Local Docker setup
  - .vscode/settings.json # Editor settings (if not in repo)

Bootstrap file behavior:

  • Files are copied from project root to the new worktree
  • Preserves file permissions and directory structure
  • Warns about missing files but continues session creation
  • Paths must be relative to project root
  • Security: Prevents directory traversal (e.g., ../../../etc/passwd)

Common use cases:

  • Environment variable templates (.env.example → .env)
  • Local development configuration files
  • Setup and initialization scripts
  • IDE/editor configuration
  • Local Docker compose overrides
  • Test data or fixtures
Managed Pi agents (MCP)

devx mcp pi is a local stdio MCP server that starts Pi agents in new sessions, queues follow-ups, and returns results. Every agent runs as a normal interactive Pi in the session's pi-agent window. You can watch it, attach, and take control. While you have control, remote prompts wait. While a task runs, the MCP client can follow it: pi_events carries rate-limited progress events, and pi_status carries latest_progress. Both show the latest assistant message (redacted, max 500 bytes) and the last tool called.

devx agent list                 # managed agents and who has control
devx agent attach <agent-id>    # drop in (typing a message takes control)
devx agent takeover <agent-id>  # pause remote prompts
devx agent release <agent-id>   # resume them

Starting agents requires pi_mcp.allowed_projects in the config. See docs/pi-mcp.md.

Cleanup Command

Automatically run cleanup commands when removing sessions. Perfect for tearing down Docker containers, databases, external services, or any infrastructure that needs cleanup.

Configure cleanup command:

# Set cleanup command
devx config set cleanup_command "scripts/teardown.sh"

# View current cleanup command
devx config get cleanup_command

Example cleanup commands:

# Docker cleanup
devx config set cleanup_command "docker-compose -f docker-compose.local.yml down"

# Custom script
devx config set cleanup_command "scripts/cleanup.sh"

# Multiple commands (using shell)
devx config set cleanup_command "npm run cleanup && docker system prune -f"

# Conditional cleanup
devx config set cleanup_command "[ -f docker-compose.local.yml ] && docker-compose -f docker-compose.local.yml down || true"

Environment variables available to cleanup command:

  • SESSION_NAME - The session name (e.g., my-feature)
  • WORKTREE_PATH - Full path to the worktree directory
  • SESSION_BRANCH - The git branch name
  • UI_PORT, API_PORT, etc. - All configured service ports
  • UI_HOST, API_HOST, etc. - All configured service hostnames (if Caddy is enabled)

Example cleanup script:

#!/bin/bash
# scripts/teardown.sh

echo "Cleaning up session: $SESSION_NAME"

# Stop any running containers for this session
docker stop "${SESSION_NAME}-db" 2>/dev/null || true
docker rm "${SESSION_NAME}-db" 2>/dev/null || true

# Clean up any test databases
psql -c "DROP DATABASE IF EXISTS test_${SESSION_NAME}" 2>/dev/null || true

# Remove any temporary files
rm -rf "/tmp/${SESSION_NAME}-*"

# Log cleanup
echo "$(date): Cleaned up session $SESSION_NAME" >> ~/.devx-cleanup.log

echo "Cleanup completed for session: $SESSION_NAME"

Cleanup command behavior:

  • Runs from the worktree directory (cd to session path)
  • Has access to all session environment variables
  • Executed through shell (sh -c) for complex commands
  • 30-second timeout to prevent hanging
  • Warnings shown for failures but don't stop session removal
  • Runs after Caddy routes are removed but before git worktree removal

Common use cases:

  • Stop and remove Docker containers
  • Drop test databases
  • Clean up temporary files
  • Remove external service resources
  • Notify external systems of teardown
  • Log cleanup activities
Session Structure

When you create a session named my-feature, devx creates:

.worktrees/my-feature/
├── .envrc              # Environment variables
├── .tmuxp.yaml         # tmux session configuration
├── .git               # Git worktree metadata
├── .env.example        # Bootstrap file (if configured)
├── scripts/            # Bootstrap directory (if configured)
│   └── setup.sh        # Bootstrap file (if configured)
└── ... (your project files)
Port Configuration
Default Services

By default, devx allocates two services:

  • ui: Frontend/web server
  • api: Backend API server
Custom Service Names

Configure any number of services with meaningful names:

# For a microservices setup
devx config set ports "ui,api,auth,database,redis,queue"

# For a full-stack app with services
devx config set ports "frontend,backend,database,cache"
Generated Environment Variables

The .envrc file will contain:

export UI_PORT=52815
export API_PORT=52816
export DATABASE_PORT=52817
export CACHE_PORT=52818

# HTTPS hostnames (when Caddy is enabled)
export UI_HOST=https://my-feature-ui.localhost
export API_HOST=https://my-feature-api.localhost
export DATABASE_HOST=https://my-feature-database.localhost
export CACHE_HOST=https://my-feature-cache.localhost

export SESSION_NAME=my-feature
tmux Integration
Default tmux Layout

Each session creates a tmux session with three windows:

  • editor: For code editing
  • backend: For running backend services
  • frontend: For running frontend development server
Custom tmux Templates

Customize your tmux layout by editing ~/.config/devx/session.yaml.tmpl:

session_name: {{.Name}}
start_directory: {{.Path}}
windows:
  - window_name: editor
    layout: tiled
    shell_command_before:
      - cd {{.Path}}
    panes:
      - echo "Editor window - Session: {{.Name}}"
      - nvim  # or your preferred editor

  - window_name: backend
    layout: tiled
    shell_command_before:
      - cd {{.Path}}{{range $name, $port := .Ports}}
      - export {{$name}}={{$port}}{{end}}
      - export SESSION_NAME={{.Name}}
    panes:
      - echo "Backend running on port $API_PORT"
      - npm run dev  # or your backend start command

  - window_name: frontend
    layout: tiled
    shell_command_before:
      - cd {{.Path}}{{range $name, $port := .Ports}}
      - export {{$name}}={{$port}}{{end}}
      - export SESSION_NAME={{.Name}}
    panes:
      - echo "Frontend running on port $WEB_PORT"
      - npm run start  # or your frontend start command
Manual tmux Operations
# List tmux sessions
tmux list-sessions

# Attach to existing session
tmux attach -t my-feature

# Load session manually
tmuxp load .worktrees/my-feature/.tmuxp.yaml
direnv Integration

If you have direnv installed, devx automatically runs direnv allow so environment variables are loaded when you cd into the worktree directory.

cd .worktrees/my-feature
echo $API_PORT  # Shows allocated port number
echo $SESSION_NAME  # Shows "my-feature"
Caddy HTTPS Integration

devx can automatically create HTTPS routes through Caddy for your development services.

Caddy Health Check and Route Management

devx includes built-in tools to verify and manage Caddy routes:

# Check Caddy status and verify all routes
devx caddy check

# Automatically fix any routing issues
devx caddy check --fix

The health check will:

  • Verify Caddy is running and accessible
  • Check all session routes are properly configured
  • Detect if catch-all routes are blocking specific routes
  • Show detailed status for each route
  • Automatically repair issues with --fix flag

TUI Integration: The TUI automatically checks Caddy health on startup and displays warnings:

  • ⚠️ Caddy is not running. Session hostnames won't work.
  • ⚠️ Caddy routes are misconfigured. Run 'devx caddy check --fix' to repair.
  • ⚠️ X Caddy routes are missing. Run 'devx caddy check --fix' to repair.
Hostname Environment Variables

When Caddy routes are created, devx automatically adds hostname environment variables to your .envrc file:

# For services: ui=3000, api=3001, database=5432
export UI_PORT=3000
export API_PORT=3001
export DATABASE_PORT=5432

# HTTPS hostnames
export UI_HOST=https://my-session-ui.localhost
export API_HOST=https://my-session-api.localhost
export DATABASE_HOST=https://my-session-database.localhost

export SESSION_NAME=my-session

Use in your applications:

# Shell scripts
curl $API_HOST/health

# Node.js
fetch(process.env.UI_HOST + '/api/users')

# Python
import os
requests.get(f"{os.environ['API_HOST']}/data")
Setup Caddy
# Install Caddy
brew install caddy

# Option 1: Use the provided helper scripts
~/.config/devx/caddy-start.sh  # Start Caddy in background
~/.config/devx/caddy-stop.sh   # Stop Caddy

# Option 2: Start Caddy manually with admin API
caddy run --config /dev/null --adapter caddyfile

# Option 3: Use the devx Caddyfile
caddy run --config ~/.config/devx/Caddyfile

Verify Caddy is running:

curl http://localhost:2019/config/
Automatic Route Creation

When you create a session, devx automatically:

  • Creates HTTPS routes for each service port
  • Maps ports to logical service names
  • Provides secure .localhost domain access
# Create session (with Caddy running)
devx session create my-feature

# This creates routes like:
# https://my-feature-ui.localhost -> 127.0.0.1:3000
# https://my-feature-api.localhost -> 127.0.0.1:3001
# https://my-feature-db.localhost -> 127.0.0.1:5432
Service Configuration

Configure service names directly - devx will create matching port and host environment variables:

Configuration:

devx config set ports "ui,api,database,cache"

Generated Environment Variables:

  • Service ui → UI_PORT and UI_HOST
  • Service api → API_PORT and API_HOST
  • Service database → DATABASE_PORT and DATABASE_HOST
  • Service cache → CACHE_PORT and CACHE_HOST

DNS Normalization: Service names are automatically converted to be DNS-compatible:

  • Uppercase → lowercase
  • Underscores → hyphens
  • Invalid characters removed

Examples:

  • UI → ui → Route: https://session-ui.localhost
  • API_SERVICE → api-service → Route: https://session-api-service.localhost
  • STREAMING_IMAGES → streaming-images → Route: https://session-streaming-images.localhost
Configuration
# Configure Caddy API endpoint
devx config set caddy_api "http://localhost:2019"

# Disable Caddy integration entirely
devx config set disable_caddy true

# Change base domain (advanced)
devx config set basedomain "dev.local"
Manual Route Management
# Session cleanup automatically removes routes
devx session rm my-feature

# Check Caddy routes manually
curl http://localhost:2019/config/

Web Interface

devx includes an optional web interface for managing sessions from any browser — phone, tablet, or desktop.

In-browser terminal

Features:

  • Recent and Projects views — globally sort sessions by last creation/open activity or retain project/status grouping; the selected view persists per browser
  • Pinned sessions — keep important sessions in a durable global section shared with the TUI
  • Session list — activity ages, project context, status indicators, search, and keyboard-stable navigation
  • In-browser terminal — full tmux access via ttyd, with tmux window tabs in the header
  • Mobile-friendly — responsive layout, soft key toolbar (Tab, Ctrl, arrows) for touchscreens
  • Artifacts — attach plans, reports, screenshots, logs, recordings, and docs to a session; view them next to the terminal and organize them into folders
  • Image upload — paste, drag-and-drop, or use the [img] button to inject an image path into the terminal
  • Create & delete sessions — from the browser, same as the CLI
  • Service links — tap "svc" on any session to open its Caddy routes in the browser
  • Keyboard shortcuts — ↑↓ navigate, Enter open, / filter, Shift+P pin outside form fields, Ctrl+Shift+C new session

The web server has three layers:

  • devx web — local HTTP server with session manager SPA
  • In-browser terminal — tmux access via ttyd, proxied through devx web
  • External domain routing — optional Cloudflare Tunnel to reach sessions from your phone over the internet
Quick start

1. Set required config keys in ~/.config/devx/config.yaml:

web_secret_token: "your-secret-token"  # required to start devx web
web_port: 7777                          # default port
web_autostart: false                    # set true to auto-start with TUI
web_bind: "127.0.0.1"                   # loopback only; 0.0.0.0 is for containers
web_trusted_proxies: ""                 # extra CIDRs whose X-Forwarded-* headers are
                                        # trusted (loopback always is). Only needed when
                                        # your reverse proxy reaches devx web over a
                                        # non-loopback path, e.g. Docker port publishing.

2. Start the web server:

devx web                  # foreground (Ctrl-C to stop)
devx web --daemon         # background daemon
devx web status           # check status
devx web stop             # stop daemon

3. Open http://localhost:7777 in your browser and enter your web_secret_token.

Auto-start: Set web_autostart: true to have the web daemon start automatically when you open the TUI.

Session artifacts

Available in v0.4.0 and newer; devx artifact is unavailable in v0.3.0. See Documentation versions.

Artifacts are files stored under a session worktree's .artifacts/ directory and indexed by .artifacts/manifest.json. They are useful for agent-generated plans, reviews, screenshots, QA reports, logs, diffs, and proof-of-work reports.

# Add a normal flat artifact
devx artifact add ./report.md \
  --title "Completion report" \
  --type report \
  --agent pi

# Group related workflow outputs under a safe relative folder path
devx artifact add ./10-plan.md \
  --title "Implementation plan" \
  --type plan \
  --folder workflow/run-123 \
  --file 10-plan.md

# List all artifacts, filter one folder, or print a grouped tree
devx artifact list
devx artifact list --folder workflow/run-123
devx artifact list --tree

# Print web, local, or same-folder/embed URLs
devx artifact url <artifact-id>
devx artifact url <artifact-id> --local
devx artifact url <artifact-id> --embed

When --folder is supplied, DevX writes the file under .artifacts/<folder>/<file> and records both the full manifest file path and the artifact folder. Folder paths must be safe relative paths: no absolute paths, .., or empty segments such as workflow//run.

Example workflow layout:

.artifacts/
  workflow/run-123/00-office-hours.md
  workflow/run-123/10-plan.md
  workflow/run-123/20-review.md
  workflow/run-123/30-qa/results.log
  workflow/run-123/40-proof-of-work.html

DevX Web shows artifact folders as groups and keeps artifacts without a folder in Unfiled. See docs/artifacts.md for more examples.

External domain routing (optional)

To access devx services from your phone via a custom domain:

One-time Cloudflare setup:

  1. Create a Cloudflare Tunnel and note the tunnel ID
  2. Add a wildcard DNS record: *.your-domain.com CNAME <tunnel-id>.cfargotunnel.com

Config:

external_domain: "your-domain.com"
cloudflare_tunnel_id: "your-tunnel-id"
cloudflare_tunnel_config: "~/.cloudflared/config.yaml"

Sync and check:

devx cloudflare sync   # regenerate cloudflared config from current sessions
devx cloudflare check  # validate tunnel setup (binary, config, DNS)

devx manages the cloudflared ingress config file automatically when sessions are created or removed. You manage the cloudflared daemon separately.

Desktop app (Wails)

The desktop/ directory builds a native desktop shell (macOS, Linux, Windows) around the same web UI using Wails v2. It is a thin native window — each launch starts a private, loopback-only devx web server on a random port with an ephemeral in-memory token, and the WebView loads only that private origin. The auth token is injected server-side by the shell's reverse proxy and is never exposed to the WebView, URLs, CLI args, logs, or disk.

Build requirements (platform WebView toolchain):

  • macOS — Xcode Command Line Tools
  • Linux — webkit2gtk
  • Windows — WebView2 runtime
cd desktop
wails build          # produces the platform app bundle
wails dev            # development loop with hot reload

macOS native build: install an arm64 Go toolchain (e.g. brew install go) and build with cd desktop && ./build-macos-app.sh. Running the build under Rosetta (Intel Go/tmux on PATH) produces a translated x86_64 binary.

Native bridge. The shell adds a few native capabilities the browser can't provide. They are exposed only through the privileged Host binding (plan invariant: service/artifact previews never get access to it):

  • File drop — Wails' WebView swallows OS file drops before the DOM sees them, so the host reads each dropped image and forwards it to the SPA as a devx:desktop:filedrop event routed through the normal upload flow.
  • Clipboard image paste — macOS WKWebView often omits clipboard images from the DOM paste event, so Cmd/Ctrl+V calls the native Host.ClipboardImage binding (AppleScript «class PNGf») and uploads the result the same way.
  • Open external links — target=_blank doesn't behave like a browser tab in a WebView, so service/artifact links route through Host.OpenExternal to the system browser.
  • Native notifications — session attention flags fire OS notifications via Host.Notify.

Image policy is centralized. Accepted image types and the upload size cap live in one Go source of truth (web/imagepolicy), consumed by the HTTP upload handlers and the desktop drop/clipboard bridge. The frontend mirror (web/app/src/lib/imagePolicy.js) is kept in lockstep by a drift test (web/imagepolicy/frontend_drift_test.go), so a policy change is a single coordinated edit.

All frontend access to the native shell goes through one adapter, web/app/src/lib/desktopBridge.js (bridge config, Host bindings, and the devx:desktop:* event names). Each helper is a no-op in a plain browser, so the same SPA runs unmodified in both.

Troubleshooting:

Symptom Likely cause / fix
Dropped/pasted image does nothing Drop requires an active session. Unsupported type, files over the size cap, or unreadable files are rejected with a toast; check logs for desktop: skipping dropped file.
Drop silently ignored, no toast No active session selected — open a session first.
Clipboard paste does nothing on macOS Grant the app Automation/AppleScript permission (System Settings → Privacy & Security → Automation). desktop: clipboard image osascript failed in logs indicates a permission/exec failure.
App shows stale UI after a rebuild A previous PWA service worker may be cached; the desktop build unregisters service workers on launch. Fully quit and relaunch.
App runs under Rosetta (slow) An Intel Go or Intel tmux is on PATH. Use an arm64 Go toolchain and arm64 tmux, then rebuild.

Examples

Basic Web Development Workflow
# Configure for web development
devx config set ports "ui,api"

# Create session
devx session create user-auth-feature

# Your tmux session launches with:
# - Window 1: Editor ready
# - Window 2: Backend with API_PORT=3001 and API_HOST=https://user-auth-feature-api.localhost exported
# - Window 3: Frontend with UI_PORT=3000 and UI_HOST=https://user-auth-feature-ui.localhost exported
# - HTTPS routes: https://user-auth-feature-ui.localhost, https://user-auth-feature-api.localhost

# In backend window: npm run dev
# In frontend window: npm start
# Access via: https://user-auth-feature-ui.localhost or $UI_HOST
Microservices Development
# Configure for microservices
devx config set ports "gateway,auth,user,order,payment,database"

# Create session
devx session create payment-service

# All services get unique ports and HTTPS routes with hostname env vars:
# GATEWAY_PORT=5000 -> GATEWAY_HOST=https://payment-service-gateway.localhost
# AUTH_PORT=5001 -> AUTH_HOST=https://payment-service-auth.localhost  
# USER_PORT=5002 -> USER_HOST=https://payment-service-user.localhost
# ORDER_PORT=5003 -> ORDER_HOST=https://payment-service-order.localhost
# PAYMENT_PORT=5004 -> PAYMENT_HOST=https://payment-service-payment.localhost
# DATABASE_PORT=5005 -> DATABASE_HOST=https://payment-service-database.localhost

# Use in your code:
# curl $AUTH_HOST/validate
# fetch(process.env.API_HOST + '/users')
Multiple Parallel Features
# Work on multiple features simultaneously
devx session create feature-a    # Gets ports 3000, 3001
devx session create feature-b    # Gets ports 3002, 3003  
devx session create hotfix-123   # Gets ports 3004, 3005

# Each in separate worktrees with isolated environments
ls .worktrees/
# feature-a/  feature-b/  hotfix-123/

Advanced Configuration

Custom Template Variables

The tmux template receives these variables:

  • {{.Name}}: Session name
  • {{.Path}}: Worktree path
  • {{.Ports}}: Map of port name to port number

You can iterate over ports:

{{range $name, $port := .Ports}}
- export {{$name}}={{$port}}{{end}}
Configuration File Locations

Project-level (takes precedence):

  • .devx/config.yaml - Project configuration
  • .devx/sessions.json - Project sessions (isolated)
  • .devx/session.yaml.tmpl - Project tmux template

Global (fallback):

  • ~/.config/devx/config.yaml - Global configuration
  • ~/.config/devx/session.yaml.tmpl - Global tmux template
  • ~/.config/devx/sessions.json - Global sessions

Configuration Discovery: devx searches for a .devx directory starting from your current working directory and walking up the directory tree. If found, project-level configs take precedence over global configs.

Dependency Checking

Check system dependencies and get installation guidance:

# Check all dependencies
devx check

# Example output:
# Dependency Check (devx v1.0.0):
# =================
# ✓ Git (git version 2.39.0) - Version control system for managing worktrees
# ✓ Tmux (tmux 3.3a) - Terminal multiplexer for session management
# ✗ Tmuxp - Tmux session manager
#   └─ Install with: pip install tmuxp
# ✓ Caddy (v2.6.4) - Web server for local development routing
# ✓ Direnv (2.32.2) - Environment variable management (recommended)
# ✓ Editor (cursor 0.29.3) - Configured editor: cursor
#
# ℹ️ Missing optional dependencies: Tmuxp
#    These are recommended but not required.

Automatic Dependency Warnings:

  • Quiet dependency check runs when launching TUI
  • Shows warnings for missing required dependencies
  • Notes for missing optional dependencies
  • Run devx check for detailed installation instructions
Version Information

Display version and build information:

# Show version
devx version
# or
devx --version
devx -v

# Detailed version info
devx version --detailed

# JSON output
devx version --output json
Editor Integration

devx can automatically launch your preferred editor when creating or attaching to sessions.

Editor Configuration Priority
  1. devx config set editor "command" - devx-specific setting
  2. VISUAL environment variable
  3. EDITOR environment variable
Editor Commands
# Configure specific editors
devx config set editor "cursor"     # Cursor
devx config set editor "code"       # VS Code
devx config set editor "nvim"       # Neovim
devx config set editor "subl"       # Sublime Text

# Or use environment variables
export VISUAL="cursor"
export EDITOR="nvim"
Editor Behavior
  • Session Create: Automatically launches editor with the new worktree path
  • Session Attach: Launches editor if not running, or reuses existing instance
  • Session Remove: Terminates tracked editor processes
  • PID Tracking: Monitors editor processes to detect when they close

Troubleshooting

Dependency Issues
# Check all dependencies with installation hints
devx check

# Common issues:
# - Missing tmuxp: pip install tmuxp
# - Missing caddy: brew install caddy  
# - Missing direnv: brew install direnv
# - Editor not found: Check devx config get editor
tmux Issues

If tmux doesn't launch automatically:

# Check if tmux is available
which tmux

# Check if tmuxp is available  
which tmuxp

# Install tmuxp
pip install tmuxp

# Launch manually
tmuxp load .worktrees/my-feature/.tmuxp.yaml
Port Conflicts

If you get port allocation errors:

# Check what's using ports
lsof -i :3000

# Kill conflicting processes
kill -9 <PID>
direnv Not Working
# Install direnv
brew install direnv

# Add to your shell (add to ~/.zshrc or ~/.bashrc)
eval "$(direnv hook zsh)"  # for zsh
eval "$(direnv hook bash)" # for bash

# Allow the directory
cd .worktrees/my-feature
direnv allow
Git Worktree Issues
# List all worktrees
git worktree list

# Remove problematic worktree
git worktree remove .worktrees/feature-name

# Prune stale worktree references
git worktree prune
Editor Issues
# Check if editor command is available
devx config get editor
which cursor  # or your configured editor

# Test editor configuration
devx config set editor "cursor"
devx session create test-editor

# Clear editor PID if stuck
devx session rm session-name
Session Management Issues
# List all sessions with status
devx session list

# Force remove stuck session
devx session rm session-name

# Check session metadata
cat ~/.config/devx/sessions.json

# Clean up orphaned tmux sessions
tmux list-sessions
tmux kill-session -t session-name

# Clear stuck attention flags
devx session flag session-name --clear

# Check current session detection
devx session flag current-session  # Should show warning
Caddy Issues

If HTTPS routes aren't working:

# First, run the health check to diagnose issues
devx caddy check

# Automatically fix common issues (missing routes, wrong order)
devx caddy check --fix

# Check if Caddy is running
curl http://localhost:2019/config/

# Start Caddy manually
caddy run --config /dev/null --adapter caddyfile

# Disable Caddy integration if not needed
devx config set disable_caddy true

# Check route creation manually
curl -X GET http://localhost:2019/config/apps/http/servers/srv0/routes

Common Caddy routing issues:

  • "No service found for this hostname": Routes exist but are blocked by catch-all route. Run devx caddy check --fix to reorder routes.
  • 502 Bad Gateway: Route is working but the backend service isn't running on the expected port.
  • Connection refused: Caddy isn't running. Start it with the helper scripts or manually.
  • Stale routes: Session shows caddy:stale status. Run devx caddy check --fix to recreate routes.

If you get certificate warnings:

  • .localhost domains use self-signed certificates
  • Add security exception in your browser, or
  • Install Caddy's root certificate for trusted HTTPS

Contributing

  1. Fork the repository
  2. Create a feature branch: devx session create my-new-feature
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Documentation

Overview

Copyright © 2025 NAME HERE <EMAIL ADDRESS>

Directories

Path Synopsis
Package artifactbridge lets remote MCP clients exchange explicitly registered files with a managed Pi agent's DevX session, without any general filesystem access.
Package artifactbridge lets remote MCP clients exchange explicitly registered files with a managed Pi agent's DevX session, without any general filesystem access.
internal
backuprestore
Package backuprestore verifies a DevX private backup by restoring it into a fixture-owned directory only.
Package backuprestore verifies a DevX private backup by restoring it into a fixture-owned directory only.
tmuxfixture
Package tmuxfixture gives tests a private tmux server that cannot reach a developer's real tmux server.
Package tmuxfixture gives tests a private tmux server that cannot reach a developer's real tmux server.
Package piagent manages Pi coding-agent sessions that DevX launches on behalf of a local MCP client while keeping them visible to, and controllable by, the human.
Package piagent manages Pi coding-agent sessions that DevX launches on behalf of a local MCP client while keeping them visible to, and controllable by, the human.
Package target defines the execution environment abstraction for DevX sessions.
Package target defines the execution environment abstraction for DevX sessions.
Package usage exposes provider subscription allowances (Claude, Codex) read from a Redline service running on the same host, mapped onto a DevX-owned wire shape so Redline's model never leaks into DevX clients.
Package usage exposes provider subscription allowances (Claude, Codex) read from a Redline service running on the same host, mapped onto a DevX-owned wire shape so Redline's model never leaks into DevX clients.
web
imagepolicy
Package imagepolicy is the single source of truth for which image types the upload flow accepts and the maximum upload size.
Package imagepolicy is the single source of truth for which image types the upload flow accepts and the maximum upload size.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL