agentleFS
Sign inSign up

dmux

standardagents/dmux/.dmux-hooks/AGENTS.md

Auto-generated documentation for AI agents This document contains everything an AI agent needs to create, modify, and understand dmux hooks. It is automatically generated from the dmux source code and embedded in the binary. You are editing hooks for dmux, a tmux pane manager that creates AI-powered development workflows. Each pane runs in its own git worktree with an AI agent (Claude Code or opencode). Create executable bash scripts in .dmux-hooks/ that run automatically at key lifecycle events. Interactive hooks…

AGENTS.md1.8k starsChanged 3 months ago
  • Reads credentials
  • Installs packages
  • Sends data out
  • Commits and pushes
# dmux Hooks System - Agent Reference

**Auto-generated documentation for AI agents**

This document contains everything an AI agent needs to create, modify, and understand dmux hooks. It is automatically generated from the dmux source code and embedded in the binary.

## What You're Working On

You are editing hooks for **dmux**, a tmux pane manager that creates AI-powered development workflows. Each pane runs in its own git worktree with an AI agent (Claude Code or opencode).

## Your Goal

Create executable bash scripts in `.dmux-hooks/` that run automatically at key lifecycle events.

## Quick Start

1. **Create a hook file**: `touch .dmux-hooks/worktree_created`
2. **Make it executable**: `chmod +x .dmux-hooks/worktree_created`
3. **Add shebang**: Start with `#!/bin/bash`
4. **Use environment variables**: Access `$DMUX_ROOT`, `$DMUX_WORKTREE_PATH`, etc.
5. **Test it**: Set env vars manually and run the script

## Hook Execution Model

- **Non-blocking**: Hooks run in background (detached processes)
- **Silent failures**: Hook errors are logged but don't stop dmux
- **Environment-based**: All context passed via environment variables
- **Version controlled**: Hooks in `.dmux-hooks/` are shared with team
- **Priority resolution**: `.dmux-hooks/` → `.dmux/hooks/` → `~/.dmux/hooks/`

## Available Hooks

### Pane Lifecycle Hooks

| Hook | When | Common Use Cases |
|------|------|------------------|
| `before_pane_create` | Before pane creation | Validation, notifications, pre-flight checks |
| `pane_created` | After pane, before worktree | Configure tmux settings, prepare environment |
| `worktree_created` | After full setup | Install deps, copy configs, setup git |
| `before_pane_close` | Before closing | Save state, backup uncommitted work |
| `pane_closed` | After closed | Cleanup resources, analytics, notifications |

### Worktree Lifecycle Hooks

| Hook | When | Common Use Cases |
|------|------|------------------|
| `before_worktree_remove` | Before worktree removal | Archive worktree, save artifacts |
| `worktree_removed` | After worktree removed | Cleanup external references |

### Merge Lifecycle Hooks

| Hook | When | Common Use Cases |
|------|------|------------------|
| `pre_merge` | Before merge operation | Run final tests, create backups |
| `post_merge` | After successful merge | Deploy, close issues, notify team |

### Interactive Hooks (with HTTP callbacks)

| Hook | When | Common Use Cases |
|------|------|------------------|
| `run_test` | When tests triggered | Run test suite, report status via HTTP |
| `run_dev` | When dev server triggered | Start dev server, create tunnel, report URL |


## Environment Variables

### Always Available
```bash
DMUX_ROOT="/path/to/project"           # Project root directory
DMUX_SERVER_PORT="3142"                # HTTP server port
```

### Pane Context (most hooks)
```bash
DMUX_PANE_ID="dmux-1234567890"         # dmux pane identifier
DMUX_SLUG="fix-auth-bug"               # Branch/worktree name
DMUX_PROMPT="Fix authentication bug"   # User's prompt
DMUX_AGENT="claude"                    # Agent type (claude|opencode)
DMUX_TMUX_PANE_ID="%38"                # tmux pane ID
```

### Worktree Context
```bash
DMUX_WORKTREE_PATH="/path/.dmux/worktrees/fix-auth-bug"
DMUX_BRANCH="fix-auth-bug"             # Same as slug
```

### Merge Context
```bash
DMUX_TARGET_BRANCH="main"              # Branch being merged into
```

## HTTP Callback API

Interactive hooks (`run_test` and `run_dev`) can update dmux UI via HTTP.

### Update Test Status
```bash
curl -X PUT "http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test"   -H "Content-Type: application/json"   -d '{"status": "running", "output": "optional test output"}'

# Status values: "running" | "passed" | "failed"
```

### Update Dev Server
```bash
curl -X PUT "http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev"   -H "Content-Type: application/json"   -d '{"status": "running", "url": "http://localhost:3000"}'

# Status values: "running" | "stopped"
# url: Can be localhost or tunnel URL (ngrok, cloudflared, etc.)
```

## Common Patterns

### Pattern 1: Install Dependencies
```bash
#!/bin/bash
# .dmux-hooks/worktree_created

cd "$DMUX_WORKTREE_PATH"

if [ -f "pnpm-lock.yaml" ]; then
  pnpm install --prefer-offline &
elif [ -f "package-lock.json" ]; then
  npm install &
elif [ -f "yarn.lock" ]; then
  yarn install &
elif [ -f "Gemfile" ]; then
  bundle install &
elif [ -f "requirements.txt" ]; then
  pip install -r requirements.txt &
elif [ -f "Cargo.toml" ]; then
  cargo build &
fi
```

### Pattern 2: Copy Configuration
```bash
#!/bin/bash
# .dmux-hooks/worktree_created

# Copy environment file
if [ -f "$DMUX_ROOT/.env.local" ]; then
  cp "$DMUX_ROOT/.env.local" "$DMUX_WORKTREE_PATH/.env.local"
fi

# Copy other config files
for file in .env.development .npmrc .yarnrc; do
  if [ -f "$DMUX_ROOT/$file" ]; then
    cp "$DMUX_ROOT/$file" "$DMUX_WORKTREE_PATH/$file"
  fi
done
```

### Pattern 3: Run Tests with Status Updates
```bash
#!/bin/bash
# .dmux-hooks/run_test

set -e
cd "$DMUX_WORKTREE_PATH"
API="http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test"

# Update: starting
curl -s -X PUT "$API" -H "Content-Type: application/json"   -d '{"status": "running"}' > /dev/null

# Run tests and capture output
OUTPUT_FILE="/tmp/dmux-test-$DMUX_PANE_ID.txt"
if pnpm test > "$OUTPUT_FILE" 2>&1; then
  STATUS="passed"
else
  STATUS="failed"
fi

# Get output (truncate if too long)
OUTPUT=$(head -c 5000 "$OUTPUT_FILE")

# Update: complete
curl -s -X PUT "$API" -H "Content-Type: application/json"   -d "$(jq -n --arg status "$STATUS" --arg output "$OUTPUT"     '{status: $status, output: $output}')" > /dev/null

rm -f "$OUTPUT_FILE"
```

### Pattern 4: Dev Server with Tunnel
```bash
#!/bin/bash
# .dmux-hooks/run_dev

set -e
cd "$DMUX_WORKTREE_PATH"
API="http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev"

# Start dev server in background
LOG_FILE="/tmp/dmux-dev-$DMUX_PANE_ID.log"
pnpm dev > "$LOG_FILE" 2>&1 &
DEV_PID=$!

# Wait for server to start
sleep 5

# Detect port from logs
PORT=$(grep -oP 'localhost:Kd+' "$LOG_FILE" | head -1)
[ -z "$PORT" ] && PORT=3000

# Optional: Create tunnel with cloudflared
if command -v cloudflared &> /dev/null; then
  TUNNEL=$(cloudflared tunnel --url "http://localhost:$PORT" 2>&1 |     grep -oP 'https://[a-z0-9-]+.trycloudflare.com' | head -1)
  URL="${TUNNEL:-http://localhost:$PORT}"
else
  URL="http://localhost:$PORT"
fi

# Report status
curl -s -X PUT "$API" -H "Content-Type: application/json"   -d "{"status": "running", "url": "$URL"}" > /dev/null

echo "[Hook] Dev server running at $URL (PID: $DEV_PID)"
```

### Pattern 5: Post-Merge Deployment
```bash
#!/bin/bash
# .dmux-hooks/post_merge

set -e
cd "$DMUX_ROOT"

# Only deploy from main/master
if [ "$DMUX_TARGET_BRANCH" != "main" ] && [ "$DMUX_TARGET_BRANCH" != "master" ]; then
  exit 0
fi

# Push to remote
git push origin "$DMUX_TARGET_BRANCH"

# Trigger deployment (example: Vercel)
if [ -n "$VERCEL_TOKEN" ]; then
  curl -s -X POST "https://api.vercel.com/v1/deployments"     -H "Authorization: Bearer $VERCEL_TOKEN"     -H "Content-Type: application/json"     -d '{"name": "my-project"}' > /dev/null
fi

# Close GitHub issue if prompt contains #123
ISSUE=$(echo "$DMUX_PROMPT" | grep -oP '#Kd+' | head -1)
if [ -n "$ISSUE" ] && command -v gh &> /dev/null; then
  gh issue close "$ISSUE"     -c "Resolved in $DMUX_SLUG, merged to $DMUX_TARGET_BRANCH"     2>/dev/null || true
fi
```

## Best Practices

1. **Always start with shebang**: `#!/bin/bash`
2. **Set error handling**: `set -e` (exit on error)
3. **Make executable**: `chmod +x .dmux-hooks/hook_name`
4. **Background long operations**: Append `&` to avoid blocking
5. **Check for required tools**: `command -v tool &> /dev/null`
6. **Log for debugging**: `echo "[Hook] message" >> "$DMUX_ROOT/.dmux/hooks.log"`
7. **Handle missing vars gracefully**: `[ -z "$VAR" ] && exit 0`
8. **Use silent curl**: `curl -s` to avoid noise in logs
9. **Clean up temp files**: Remove files in `/tmp/`
10. **Test before committing**: Run hooks manually with mock env vars

## Testing Hooks

### Manual Testing
```bash
# 1. Set environment variables
export DMUX_ROOT="$(pwd)"
export DMUX_PANE_ID="test-pane"
export DMUX_SLUG="test-branch"
export DMUX_WORKTREE_PATH="$(pwd)"
export DMUX_SERVER_PORT="3142"
export DMUX_AGENT="claude"
export DMUX_PROMPT="Test prompt"

# 2. Run hook directly
./.dmux-hooks/worktree_created

# 3. Check exit code
echo $?  # Should be 0 for success
```

### Syntax Check
```bash
# Check for syntax errors without running
bash -n ./.dmux-hooks/worktree_created
```

### Shellcheck (if available)
```bash
shellcheck ./.dmux-hooks/worktree_created
```

## Project Context Analysis

Before creating hooks, analyze these files in the project:

### Package Manager Detection
```bash
# Check which package manager is used
if [ -f "pnpm-lock.yaml" ]; then
  # Use: pnpm install, pnpm test, pnpm dev
elif [ -f "package-lock.json" ]; then
  # Use: npm install, npm test, npm run dev
elif [ -f "yarn.lock" ]; then
  # Use: yarn install, yarn test, yarn dev
fi
```

### Test Command Discovery
```bash
# Read package.json to find test command
cat package.json | grep '"test"'
# Or with jq:
jq -r '.scripts.test' package.json
```

### Dev Command Discovery
```bash
# Read package.json to find dev command
cat package.json | grep '"dev"'
# Or with jq:
jq -r '.scripts.dev' package.json
```

### Environment Variables
```bash
# Check for .env files to copy
ls -la | grep '.env'
```

### Build System
```bash
# Detect build system
if [ -f "vite.config.ts" ]; then
  # Vite project
elif [ -f "next.config.js" ]; then
  # Next.js project
elif [ -f "nuxt.config.ts" ]; then
  # Nuxt project
fi
```

## Common Mistakes to Avoid

❌ **Blocking operations**: `sleep 60` (blocks dmux)
✅ **Background long tasks**: `slow_operation &`

❌ **Hardcoded paths**: `/Users/me/project`
✅ **Use variables**: `"$DMUX_ROOT"`

❌ **Assuming tools exist**: `pnpm install`
✅ **Check first**: `command -v pnpm && pnpm install`

❌ **No error handling**: Script fails silently
✅ **Set error mode**: `set -e` or check exit codes

❌ **Forgetting executable bit**: Hook won't run
✅ **Make executable**: `chmod +x`

❌ **Noisy output**: Clutters dmux logs
✅ **Silent operations**: `curl -s`, `> /dev/null 2>&1`

❌ **Not testing**: Deploy and hope
✅ **Test manually**: Run with mock env vars first

## Debugging

If a hook isn't working:

1. **Check if file exists**: `ls -la .dmux-hooks/`
2. **Check permissions**: Should show `x` in `rwxr-xr-x`
3. **Check syntax**: `bash -n .dmux-hooks/hook_name`
4. **Test manually**: Set env vars and run
5. **Check logs**: dmux logs to stderr with `[Hooks]` prefix
6. **Simplify**: Remove complex parts, test basic version
7. **Check tool availability**: `command -v required_tool`

### Debug Mode
```bash
#!/bin/bash
# Add to top of hook for debugging
set -x  # Print each command before executing
set -e  # Exit on error

# Your hook logic here
```

## Summary Checklist

When creating a new hook:

- [ ] Create file in `.dmux-hooks/`
- [ ] Add shebang: `#!/bin/bash`
- [ ] Make executable: `chmod +x`
- [ ] Add `set -e` for error handling
- [ ] Use environment variables (never hardcode paths)
- [ ] Background long operations with `&`
- [ ] Check for required tools before using
- [ ] Test manually with mock env vars
- [ ] Add comments explaining what it does
- [ ] Commit to version control

## Getting Help

- **Full documentation**: See `HOOKS.md` in project root
- **Claude-specific tips**: See `CLAUDE.md` in `.dmux-hooks/`
- **Examples**: Check `.dmux-hooks/examples/` directory
- **dmux API**: See `API.md` for REST endpoints

---

*This documentation was auto-generated from dmux source code.*
*Version: 2025-10-10*

Discussion

Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.

Posts are public.Sign in to post

No one has posted yet. Be the first.