Agent skill
gen-env
Creates, updates, or reviews a project's gen-env command for running multiple isolated instances on localhost. Handles instance identity, port allocation, data isolation, browser state separation, and cleanup.
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/0xbigboss/gen-env
SKILL.md
gen-env Skill
Generate or review a gen-env command that enables running multiple isolated instances of a project on localhost simultaneously (e.g., multiple worktrees, feature branches, or versions).
The Problem
Without isolation, multiple instances of the same project:
- Fight for hardcoded ports (3000, 5432, 8080)
- Share Docker volumes → data corruption
- Share browser cookies/localStorage → auth confusion
- Have ambiguous container names → can't tell which is which
- Risk catastrophic cleanup →
docker down -vnukes everything
The Solution: Instance Identity
Everything flows from a workspace name:
name = "feature-x"
↓
┌─────────────────────────────────────────────────────┐
│ COMPOSE_PROJECT_NAME = localnet-feature-x │
│ DOCKER_NETWORK = localnet-feature-x │
│ VOLUME_PREFIX = localnet-feature-x │
│ CONTAINER_PREFIX = localnet-feature-x- │
│ TILT_HOST = feature-x.localhost │
│ Ports = dynamically allocated │
│ URLs = derived from host + ports │
└─────────────────────────────────────────────────────┘
Isolation Dimensions
1. Port Isolation
Each instance gets unique ports from ephemeral range (49152-65535).
2. Data Isolation
Docker Compose project name controls volume naming:
- Instance A:
localnet-main_postgres_data - Instance B:
localnet-feature-x_postgres_data
No cross-contamination. Independent databases.
3. Network Isolation
Separate Docker networks per instance. Containers reference each other by service name without collision.
4. Browser State Isolation
Critical: Different ports on localhost still share cookies!
http://localhost:3000 ─┐
├─ SAME cookies, localStorage
http://localhost:3001 ─┘
Solution: subdomain isolation via *.localhost:
http://main.localhost:3000 ─ separate cookies
http://feature-x.localhost:3001 ─ separate cookies
Chrome/Edge treat *.localhost as 127.0.0.1 automatically. No /etc/hosts needed.
5. Auth Isolation
Each instance can have its own auth realm/audience, preventing token confusion.
6. Resource Naming
Clear prefixes on containers, volumes, Tilt resources, logs → know exactly which instance you're looking at.
Implementation Checklist
When creating or reviewing gen-env:
Identity & Naming:
- Requires
--name <workspace>argument - Validates name (alphanumeric + dashes, max 63 chars for DNS)
- Generates
COMPOSE_PROJECT_NAMEfrom name - Generates
DOCKER_NETWORK,VOLUME_PREFIX,CONTAINER_PREFIX - Generates
*_HOSTfor browser isolation (name.localhost)
Port Allocation:
- Allocates from ephemeral range (49152-65535)
- Checks port availability before assignment
- Uses short timeout (100ms) for CI compatibility
- Handles IPv6-disabled environments gracefully
Persistence:
- Lockfile stores name + ports (
.gen-env.lock) - Reuses ports when lockfile exists and name matches
-
--forceregenerates all -
--cleanremoves generated files
Output:
- Generates
.localnet.env(or project-specific name) - Clear header with generation timestamp
- All derived URLs use correct host + port
Integration:
- Script added to PATH via
.envrc - Generated env sourced by
.envrc - Works with Docker Compose (
--env-file) - Works with Tilt (Starlark reads env file)
Generated Environment Structure
# .localnet.env - generated by gen-env
# Instance: feature-x
# Generated: 2024-01-15T10:30:00Z
# === Instance Identity ===
WORKSPACE_NAME=feature-x
COMPOSE_NAME=localnet-feature-x
COMPOSE_PROJECT_NAME=localnet-feature-x
DOCKER_NETWORK=localnet-feature-x
VOLUME_PREFIX=localnet-feature-x
CONTAINER_PREFIX=localnet-feature-x-
# === Host (for browser isolation) ===
APP_HOST=feature-x.localhost
TILT_HOST=feature-x.localhost
# === Allocated Ports ===
POSTGRES_PORT=51234
REDIS_PORT=51235
API_PORT=51236
WEB_PORT=51237
# ... more ports
# === Derived URLs ===
DATABASE_URL=postgres://user:pass@localhost:51234/dev
WEB_URL=http://feature-x.localhost:51237
API_URL=http://feature-x.localhost:51236
direnv Integration
# .envrc
PATH_add bin # or scripts
dotenv_if_exists .localnet.env
Reference Implementation (TypeScript/Bun)
See @IMPLEMENTATION.md for full implementation.
Key types:
interface InstanceConfig {
name: string; // Workspace identity
composeName: string; // Docker Compose project name
dockerNetwork: string; // Docker network name
volumePrefix: string; // Docker volume prefix
containerPrefix: string; // Container name prefix
host: string; // Browser hostname (name.localhost)
ports: Record<string, number>; // Allocated ports
urls: Record<string, string>; // Derived URLs
}
interface LockfileData {
version: 1;
generatedAt: string;
instance: InstanceConfig;
}
Cleanup Patterns
Surgical cleanup per instance:
# Clean only feature-x (containers + volumes + networks)
docker compose -p localnet-feature-x down -v
# Or via gen-env
gen-env --clean # removes .localnet.env and .gen-env.lock
# List all localnet instances
docker ps -a --filter "name=localnet-" --format "table {{.Names}}\t{{.Status}}"
# Nuclear option (all instances) - DANGEROUS
docker ps -a --filter "name=localnet-" -q | xargs docker rm -f
docker volume ls --filter "name=localnet-" -q | xargs docker volume rm
Common Patterns
Pattern 1: Worktree-Based Naming
# Derive name from git worktree directory
WORKTREE_NAME=$(basename "$(git rev-parse --show-toplevel)")
gen-env --name "$WORKTREE_NAME"
Pattern 2: Branch-Based Naming
# Derive name from branch
BRANCH=$(git branch --show-current | tr '/' '-')
gen-env --name "$BRANCH"
Pattern 3: Explicit Naming
# User specifies (recommended for clarity)
gen-env --name bb-dev
gen-env --name testing-v2
Review Checklist
When reviewing an existing gen-env:
- Does it create instance identity? (not just ports)
- Does it set COMPOSE_PROJECT_NAME? (controls Docker naming)
- Does it generate a browser-safe host? (
*.localhost) - Are URLs derived with correct host? (not hardcoded
localhost) - Is cleanup surgical? (can remove one instance without affecting others)
- Does the lockfile store the name? (for consistency across runs)
- Does it validate name conflicts? (warn if lockfile has different name)
Anti-Patterns
❌ Hardcoded localhost in URLs
WEB_URL=http://localhost:${WEB_PORT} # BAD: shares cookies
✅ Use instance host
WEB_URL=http://${APP_HOST}:${WEB_PORT} # GOOD: isolated cookies
❌ No COMPOSE_PROJECT_NAME
# BAD: uses directory name, may conflict
docker compose up
✅ Explicit project name
COMPOSE_PROJECT_NAME=localnet-feature-x
docker compose up # Uses project name for all resources
❌ Shared cleanup
docker compose down -v # BAD: which instance?
✅ Instance-specific cleanup
docker compose -p localnet-feature-x down -v # GOOD: explicit
References
- @IMPLEMENTATION.md - Full TypeScript implementation
- @ADVANCED_PATTERNS.md - Complex scenarios (monorepos, CI, Tilt integration)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?