devloop

command module
v0.0.22 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2025 License: Apache-2.0 Imports: 10 Imported by: 0

README ΒΆ

devloop: Intelligent Development Workflow Orchestrator

devloop Logo/Banner (Placeholder)

devloop is a generic, multi-variant tool designed to streamline development workflows, particularly within Multi-Component Projects (MCPs) (no not that MCP). It combines functionalities inspired by live-reloading tools like air (for Go) and build automation tools like make, focusing on simple, configuration-driven orchestration of tasks based on file system changes.

πŸ—οΈ Architecture Overview

Devloop operates in three distinct modes to support different development scenarios:

1. Standalone Mode (Default)

The simplest mode for individual projects. Devloop runs as a single daemon process with an embedded gRPC server.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Your Project      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  .devloop.yamlβ”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚          β”‚          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  devloop      β”‚  β”‚
β”‚  β”‚  (daemon)     β”‚  β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚
β”‚  β”‚ β”‚gRPC Serverβ”‚ β”‚  β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use Case: Single project development, simple setup.

2. Agent Mode

Devloop connects to a central gateway, ideal for multi-component projects where you want centralized monitoring.

Project A                    Project B
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚.devloop.yaml β”‚            β”‚.devloop.yaml β”‚
β”‚              β”‚            β”‚              β”‚
β”‚  devloop     β”‚            β”‚  devloop     β”‚
β”‚  (agent)     β”‚            β”‚  (agent)     β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                           β”‚
       └─────────┐   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 β”‚   β”‚
              β”Œβ”€β”€β–Όβ”€β”€β”€β–Όβ”€β”€β”
              β”‚ Gateway β”‚
              β”‚         β”‚
              β”‚  :8080  β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use Case: Microservices, monorepos, distributed development

3. Gateway Mode

Acts as a central hub accepting connections from multiple agents, providing a unified interface for monitoring and control.

devloop --mode gateway --gateway-port 8080

Features:

  • Centralized logging and monitoring
  • Unified HTTP/gRPC API for all connected projects
  • Real-time status updates from all agents
  • Cross-project orchestration capabilities

πŸ“‹ Prerequisites

Before installing devloop, ensure you have:

  • Go 1.20 or higher installed (Download Go)
  • Git (for version control operations)
  • $GOPATH/bin added to your system's PATH
Supported Platforms
  • Linux (amd64, arm64)
  • macOS (Intel, Apple Silicon)
  • Windows (amd64)

πŸš€ Getting Started

  1. Install devloop:
    go install github.com/panyam/devloop@latest
    
  2. Create a .devloop.yaml file in your project's root directory:
    rules:
      - name: "Go Backend Build and Run"
        watch:
          - action: "include"
            patterns:
              - "**/*.go"
              - "go.mod"
              - "go.sum"
        commands:
          - "echo 'Building backend...'"
          - "go build -o ./bin/server ./cmd/server"
          - "./bin/server"    # This starts the server and is long running
    
  3. Run devloop:
    devloop -c .devloop.yaml
    

devloop will now watch your files and automatically rebuild and restart your backend server whenever you make changes to your Go code.

πŸ“š Examples

The examples/ directory contains comprehensive real-world examples demonstrating devloop's capabilities across different development scenarios:

Example Description Key Technologies Use Case
01-fullstack-web Complete web application with backend, frontend, database, and docs Go, JavaScript, SQL, HTTP Traditional web development with multiple parallel services
02-microservices Distributed microservices architecture with gateway pattern Go, API Gateway, JWT, HTTP Service-oriented architecture with centralized monitoring
03-python-datascience Data science workflow with notebooks, training, and testing Python, Jupyter, pytest, ML Data analysis and machine learning development
04-docker-compose Multi-container development with orchestrated services Docker, PostgreSQL, Redis, React, Go, Python Containerized application development
05-frontend-framework Modern frontend development with multiple frameworks React, Vue.js, TypeScript, Storybook, Vite Component-driven frontend development
06-ai-ml-development Advanced ML pipeline with experiment tracking and serving MLflow, PyTorch, TensorFlow, FastAPI, Jupyter MLOps and production machine learning
Quick Start with Examples

Each example includes:

  • Complete setup instructions in their respective README files
  • Working .devloop.yaml configurations
  • Makefile with common commands (make run, make deps, make clean)
  • Sample code and realistic project structure
  • Testing and deployment guidance

To try any example:

# Navigate to an example
cd examples/01-fullstack-web

# Install dependencies
make deps

# Start development environment
make run
Example Complexity Levels
  • Beginner: Examples 1-3 demonstrate core devloop concepts
  • Intermediate: Examples 4-5 show advanced orchestration patterns
  • Advanced: Example 6 illustrates enterprise-grade ML workflows

Each example builds upon the concepts from previous ones, so we recommend exploring them in order if you're new to devloop.

πŸ”„ Comparison with Similar Tools

Quick Use Case Comparison
Solution Good For Not Great For
Docker Compose Production-like isolation Fast local iteration
tmux/screen Terminal management Process lifecycle
Make -j Build orchestration Long-running services
Foreman/Overmind Procfile-based apps File watching & triggers
Shell scripts Simple automation Complex process management
devloop Multi-service development Production deployment
Feature Comparison
Feature devloop air nodemon watchexec
Language Focus Multi-language Go Node.js Any
Parallel Rules βœ… Yes ❌ No ❌ No ❌ No
Distributed Mode βœ… Agent/Gateway ❌ No ❌ No ❌ No
Process Groups βœ… Yes βœ… Yes βœ… Yes ⚠️ Limited
Log Prefixing βœ… Yes ❌ No ❌ No ❌ No
gRPC/HTTP API βœ… Yes ❌ No ❌ No ❌ No
Config Format YAML TOML JSON CLI args
Debouncing βœ… Yes βœ… Yes βœ… Yes βœ… Yes
Exclude Patterns βœ… Yes βœ… Yes βœ… Yes βœ… Yes
Build Tool ❌ No βœ… Yes ❌ No ❌ No
Live Reload βœ… Via commands βœ… Built-in ❌ No ❌ No
Multi-Project βœ… Yes ❌ No ❌ No ❌ No
When to Use devloop
  • Multi-component projects: When you need to orchestrate multiple services/components
  • Microservices development: Centralized monitoring with agent/gateway mode
  • Complex workflows: When you need multiple parallel build/watch tasks
  • API monitoring: Built-in gRPC/HTTP endpoints for integration
  • Cross-language projects: Not tied to a specific language ecosystem
When to Use Alternatives
  • air: Go-only projects with built-in compilation and live-reload
  • nodemon: Simple Node.js projects with minimal configuration
  • watchexec: Single-command execution with complex file watching needs

✨ Key Features

  • Parallel & Concurrent Task Running: Define rules for different parts of your project (backend, frontend, etc.) and devloop will run them concurrently.
  • Intelligent Change Detection: Uses glob patterns to precisely match file changes, triggering only the necessary commands.
  • Robust Process Management: Automatically terminates old processes before starting new ones, preventing zombie processes and ensuring a clean state.
  • Debounced Execution: Rapid file changes trigger commands only once, preventing unnecessary builds and restarts.
  • Command Log Prefixing: Prepends a customizable prefix to each line of your command's output, making it easy to distinguish logs from different processes.
  • .air.toml Converter: Includes a built-in tool to convert your existing .air.toml configuration into a devloop rule.

βš™οΈ Configuration Reference

Complete Configuration Structure
# .devloop.yaml
settings:                    # Optional: Global settings
  prefix_logs: boolean       # Enable/disable log prefixing (default: true)
  prefix_max_length: number  # Max length for prefixes (default: unlimited)

rules:                       # Required: Array of rules
  - name: string            # Required: Unique rule identifier
    prefix: string          # Optional: Custom log prefix (defaults to name)
    workdir: string         # Optional: Working directory for commands
    run_on_init: boolean    # Optional: Run on startup (default: true)
    env:                    # Optional: Environment variables
      KEY: "value"
    watch:                  # Required: File watch configuration
      - action: string      # Required: "include" or "exclude"
        patterns: [string]  # Required: Glob patterns
    commands: [string]      # Required: Shell commands to execute
Settings Options
Option Type Default Description
prefix_logs boolean true Prepend rule name/prefix to each output line
prefix_max_length integer unlimited Truncate/pad prefixes to this length for alignment
Rule Options
Option Type Required Description
name string βœ… Unique identifier for the rule
prefix string ❌ Custom prefix for log output (overrides name)
workdir string ❌ Working directory for command execution
env map ❌ Additional environment variables
watch array βœ… File patterns to monitor
commands array βœ… Commands to execute when files change
run_on_init boolean ❌ Run commands on startup (default: true)
Watch Configuration

Each watch entry consists of:

Field Type Values Description
action string include, exclude Whether to trigger on or ignore matches
patterns array glob patterns File patterns using doublestar syntax
Glob Pattern Syntax
  • * - Matches any sequence of non-separator characters
  • ** - Matches any sequence of characters including path separators
  • ? - Matches any single non-separator character
  • [abc] - Matches any character in the set
  • [a-z] - Matches any character in the range
  • {a,b} - Matches either pattern a or b
Example with All Options
settings:
  prefix_logs: true
  prefix_max_length: 12

rules:
  - name: "Backend API"
    prefix: "api"
    workdir: "./backend"
    env:
      NODE_ENV: "development"
      PORT: "3000"
      DATABASE_URL: "postgres://localhost/myapp"
    watch:
      - action: "exclude"
        patterns:
          - "**/vendor/**"
          - "**/*_test.go"
          - "**/.*"
      - action: "include"
        patterns:
          - "**/*.go"
          - "go.mod"
          - "go.sum"
    commands:
      - "echo 'Building API server...'"
      - "go mod tidy"
      - "go build -tags dev -o bin/api ./cmd/api"
      - "./bin/api --dev"
Pattern Matching Examples
# Match all Go files
"**/*.go"

# Match Go files only in src directory
"src/**/*.go"

# Match test files
"**/*_test.go"

# Match multiple extensions
"**/*.{js,jsx,ts,tsx}"

# Match specific directory
"cmd/server/**/*"

# Match top-level files only
"*.go"

# Match hidden files
"**/.*"
Command Execution Behavior
  1. Sequential Execution: Commands run in the order specified
  2. Cross-Platform Shell Execution: Commands run via platform-specific shells (bash -c on Unix, cmd /c on Windows)
  3. Process Groups: Commands run in separate process groups for clean termination
  4. Environment Inheritance: Commands inherit parent environment plus env variables
  5. Working Directory: Commands execute in workdir (or directory containing the config file if not set)
  6. Process Termination: Previous instances receive SIGTERM when rule re-triggers
  7. Error Handling: Failed commands don't stop subsequent commands in the list
Environment Variable Precedence
  1. System environment variables
  2. Variables from env configuration (overrides system vars)
  3. devloop internal variables:
    • DEVLOOP_RULE_NAME - Current rule name
    • DEVLOOP_TRIGGER_FILE - File that triggered the rule

πŸ“¦ Installation

go install github.com/panyam/devloop@latest

This command will compile the devloop executable and place it in your Go binary directory, making it globally accessible.

Alternatively, to build the executable locally:

go build -o devloop

πŸ”Œ API Reference

Devloop provides both gRPC and REST APIs for monitoring and control. The REST API is available via gRPC-Gateway.

REST API Endpoints

Base URL: http://localhost:8080 (default gateway port)

List All Projects
GET /projects

Returns all registered devloop projects and their connection status.

Response:

{
  "projects": [
    {
      "project_id": "auth-service",
      "project_root": "/path/to/auth-service",
      "connection_status": "CONNECTED"
    }
  ]
}
Get Project Configuration
GET /projects/{projectId}/config

Returns the full configuration for a specific project.

Response:

{
  "config_json": "{\"rules\":[{\"name\":\"backend\",\"commands\":[\"go run .\"]}]}"
}
Get Rule Status
GET /projects/{projectId}/status/{ruleName}

Returns the current status of a specific rule.

Response:

{
  "rule_name": "backend",
  "is_running": true,
  "started_at": "1704092400000",
  "last_build_time": "1704092400000",
  "last_build_status": "SUCCESS"
}
Trigger Rule Manually
POST /projects/{projectId}/trigger/{ruleName}

Manually triggers a rule execution.

Response:

{
  "success": true,
  "message": "Rule 'backend' triggered successfully"
}
List Watched Paths
GET /projects/{projectId}/watched-paths

Returns all glob patterns being watched by the project.

Response:

{
  "patterns": [
    "**/*.go",
    "go.mod",
    "go.sum"
  ]
}
Read File Content
GET /projects/{projectId}/file-content?path={filePath}

Reads a file from the project directory.

Response:

{
  "content": "package main\n\nfunc main() {\n    // ...\n}"
}
Stream Real-time Logs
GET /projects/{projectId}/stream/logs/{ruleName}?filter={optional}

Server-sent events stream for real-time logs.

Response (SSE):

data: {"project_id":"backend","rule_name":"api","line":"Starting server...","timestamp":"1704092400000"}

data: {"project_id":"backend","rule_name":"api","line":"Server listening on :8080","timestamp":"1704092401000"}
Get Historical Logs
GET /projects/{projectId}/historical-logs/{ruleName}?filter={optional}&startTime={ms}&endTime={ms}

Retrieve historical logs with optional time range.

Parameters:

  • filter: Optional text filter
  • startTime: Start timestamp in milliseconds
  • endTime: End timestamp in milliseconds

Response:

{
  "logs": [
    {
      "project_id": "backend",
      "rule_name": "api",
      "line": "Request processed",
      "timestamp": "1704092400000"
    }
  ]
}
gRPC Interface

For direct gRPC access, use the following service definitions:

service GatewayClientService {
  rpc ListProjects(ListProjectsRequest) returns (ListProjectsResponse);
  rpc GetProjectConfig(GetProjectConfigRequest) returns (GetProjectConfigResponse);
  rpc GetRuleStatus(GetRuleStatusRequest) returns (GetRuleStatusResponse);
  rpc TriggerRule(TriggerRuleRequest) returns (TriggerRuleResponse);
  rpc ListWatchedPaths(ListWatchedPathsRequest) returns (ListWatchedPathsResponse);
  rpc ReadFileContent(ReadFileContentRequest) returns (ReadFileContentResponse);
  rpc StreamLogs(StreamLogsRequest) returns (stream LogLine);
  rpc GetHistoricalLogs(GetHistoricalLogsRequest) returns (GetHistoricalLogsResponse);
}
Client Examples
JavaScript/TypeScript
// Fetch all projects
const response = await fetch('http://localhost:8080/projects');
const data = await response.json();

// Stream logs using EventSource
const events = new EventSource('http://localhost:8080/projects/backend/stream/logs/api');
events.onmessage = (event) => {
  const log = JSON.parse(event.data);
  console.log(`[${log.rule_name}] ${log.line}`);
};
Python
import requests
import sseclient

# Get rule status
response = requests.get('http://localhost:8080/projects/backend/status/api')
status = response.json()

# Stream logs
response = requests.get('http://localhost:8080/projects/backend/stream/logs/api', stream=True)
client = sseclient.SSEClient(response)
for event in client.events():
    log = json.loads(event.data)
    print(f"[{log['rule_name']}] {log['line']}")
Go
// Using the generated gRPC client
conn, _ := grpc.Dial("localhost:8080", grpc.WithInsecure())
client := pb.NewGatewayClientServiceClient(conn)

// List projects
resp, _ := client.ListProjects(context.Background(), &pb.ListProjectsRequest{})
for _, project := range resp.Projects {
    fmt.Printf("Project: %s (%s)\n", project.ProjectId, project.ConnectionStatus)
}

πŸ€– MCP Server Integration

Devloop Gateway can act as a Model Context Protocol (MCP) server, enabling AI agents and LLMs (like Claude) to monitor and control your development workflows.

What is MCP?

Model Context Protocol (MCP) is a standard that allows AI assistants to interact with external tools and systems. By exposing devloop as an MCP server, you enable:

  • AI-Assisted Development: LLMs can trigger builds, run tests, and analyze errors
  • Automated Workflows: AI agents can respond to build failures and suggest fixes
  • Intelligent Monitoring: Query project status and logs through natural language
Setting Up Devloop MCP Server
1. Start Gateway in MCP Mode
# Start gateway with MCP server enabled
devloop --mode gateway --gateway-port 8080 --mcp-port 3000
2. Configure MCP Server Settings

Create mcp-config.json:

{
  "name": "devloop-mcp",
  "version": "1.0.0",
  "description": "Control and monitor development workflows",
  "tools": {
    "project_management": {
      "enabled": true,
      "allowed_operations": ["list", "status", "info"]
    },
    "build_control": {
      "enabled": true,
      "require_confirmation": false,
      "timeout_seconds": 300
    },
    "log_access": {
      "enabled": true,
      "max_lines": 1000,
      "allow_streaming": true
    }
  }
}
3. Connect Your Devloop Agents
# In each project directory
devloop --mode agent --gateway-url localhost:8080 \
        --project-id "my-backend" \
        -c .devloop.yaml
Using with Claude Desktop

Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "devloop": {
      "command": "devloop",
      "args": ["mcp-client", "--gateway-url", "localhost:3000"],
      "env": {
        "DEVLOOP_API_KEY": "your-optional-api-key"
      }
    }
  }
}
Available MCP Tools

When connected, the following tools are available to AI agents:

Project Management
// List all projects
await use_mcp_tool("devloop", "list_projects", {
  filter: "backend",
  include_status: true
});

// Get project information
await use_mcp_tool("devloop", "project_info", {
  project_id: "my-backend"
});
Build & Test Control
// Trigger a build
await use_mcp_tool("devloop", "trigger_build", {
  project_id: "my-backend",
  rule_name: "build",
  wait_for_completion: true
});

// Run tests
await use_mcp_tool("devloop", "run_tests", {
  project_id: "my-backend",
  test_pattern: "**/*_test.go",
  coverage: true
});

// Execute custom command
await use_mcp_tool("devloop", "execute_command", {
  project_id: "my-backend",
  command: "make lint",
  timeout_seconds: 60
});
Monitoring & Logs
// Check status
await use_mcp_tool("devloop", "check_status", {
  project_id: "my-backend",
  rule_name: "api-server"
});

// Read recent logs
await use_mcp_tool("devloop", "read_logs", {
  project_id: "my-backend",
  lines: 100,
  filter: "ERROR"
});

// Stream real-time output
await use_mcp_tool("devloop", "watch_output", {
  project_id: "my-backend",
  rule_name: "api-server",
  duration_seconds: 30
});
Code Intelligence
// Read file content
await use_mcp_tool("devloop", "read_file", {
  project_id: "my-backend",
  file_path: "src/main.go"
});

// Search for files
await use_mcp_tool("devloop", "find_files", {
  project_id: "my-backend",
  pattern: "**/*_test.go"
});

// Analyze build errors
await use_mcp_tool("devloop", "analyze_errors", {
  project_id: "my-backend",
  include_suggestions: true
});
Example Workflows
1. AI-Assisted Debugging
# .devloop.yaml with MCP annotations
rules:
  - name: "test"
    mcp_exposed: true
    mcp_description: "Run unit tests with coverage"
    commands:
      - "go test -v -coverprofile=coverage.out ./..."
      - "go tool cover -html=coverage.out -o coverage.html"

AI Agent workflow:

  1. "Run the tests for the backend project"
  2. "Show me any failing tests"
  3. "Read the source file for the failing test"
  4. "Suggest a fix for the error"
2. Automated Build Pipeline
// AI agent can orchestrate complex workflows
const projects = await use_mcp_tool("devloop", "list_projects");

for (const project of projects) {
  // Check if project needs rebuild
  const status = await use_mcp_tool("devloop", "check_status", {
    project_id: project.id
  });
  
  if (status.needs_rebuild) {
    // Trigger build
    const result = await use_mcp_tool("devloop", "trigger_build", {
      project_id: project.id,
      wait_for_completion: true
    });
    
    if (!result.success) {
      // Analyze errors
      const errors = await use_mcp_tool("devloop", "analyze_errors", {
        project_id: project.id
      });
      
      console.log(`Build failed: ${errors.summary}`);
    }
  }
}
3. Multi-Project Coordination
# Gateway coordinates multiple services
# AI agent can manage the entire stack
// Start all services in correct order
const startOrder = ["database", "cache", "api", "frontend"];

for (const service of startOrder) {
  await use_mcp_tool("devloop", "trigger_build", {
    project_id: service,
    rule_name: "start"
  });
  
  // Wait for service to be ready
  let ready = false;
  while (!ready) {
    const status = await use_mcp_tool("devloop", "check_status", {
      project_id: service
    });
    ready = status.is_running && status.health_check_passing;
    await new Promise(r => setTimeout(r, 1000));
  }
}
Security Considerations
Authentication
# mcp-config.json
{
  "authentication": {
    "required": true,
    "type": "api_key",
    "key_header": "X-Devloop-API-Key"
  }
}
Access Control
{
  "access_control": {
    "allowed_projects": ["frontend", "backend"],
    "forbidden_commands": ["rm", "sudo"],
    "max_command_length": 500,
    "rate_limit": {
      "requests_per_minute": 60,
      "concurrent_operations": 5
    }
  }
}
Troubleshooting MCP Integration
Connection Issues
# Test MCP server connectivity
curl http://localhost:3000/mcp/tools

# Check gateway logs
devloop logs --mode gateway --tail 100
Common Problems
  1. "MCP server not found"

    • Ensure gateway is running with --mcp-port flag
    • Check firewall settings
  2. "Tool execution failed"

    • Verify project is connected as agent
    • Check tool permissions in mcp-config.json
  3. "Timeout waiting for response"

    • Increase timeout in tool parameters
    • Check if commands are hanging
Best Practices
  1. Use Descriptive Project IDs: Makes it easier for AI to identify projects
  2. Add MCP Descriptions: Document your rules for better AI understanding
  3. Set Reasonable Timeouts: Prevent long-running operations from blocking
  4. Monitor Rate Limits: Prevent AI from overwhelming your system
  5. Log AI Actions: Audit trail for debugging and security

πŸš€ Usage

Running in Standalone Mode (Default)

Navigate to your project's root directory and execute:

devloop -c .devloop.yaml
  • Use the -c flag to specify the path to your .devloop.yaml configuration file. If omitted, devloop will look for .devloop.yaml in the current directory.
Running in Agent Mode

To connect to a gateway:

devloop --mode agent --gateway-url localhost:8080 -c .devloop.yaml
Running in Gateway Mode

To start a central gateway:

devloop --mode gateway --gateway-port 8080

The gateway will accept connections from agents and provide a unified interface at http://localhost:8080.

Subcommands

devloop also supports subcommands for specific utilities:

convert

This subcommand allows you to convert an existing .air.toml configuration file (used by the air live-reloading tool) into a devloop-compatible .devloop.yaml rule.

devloop convert -i .air.toml
  • Use the -i flag to specify the path to the .air.toml input file. If omitted, it defaults to .air.toml in the current directory. The converted output will be printed to standard output.

πŸ”„ Migrating from Air

If you're currently using Air for Go development, migrating to devloop is straightforward.

Quick Migration
  1. Convert your .air.toml automatically:

    devloop convert -i .air.toml > .devloop.yaml
    
  2. Review and adjust the generated configuration:

    cat .devloop.yaml
    
Manual Migration Reference

Here's how Air configurations map to devloop:

Air (.air.toml) devloop (.devloop.yaml)
root = "." workdir: "."
tmp_dir = "tmp" Not needed (devloop doesn't use tmp)
[build] section Single rule with commands
bin = "./tmp/main" Part of commands
cmd = "go build -o ./tmp/main ." commands: ["go build -o ./tmp/main ."]
full_bin = "./tmp/main" commands: ["./tmp/main"]
include_ext = ["go", "tpl"] patterns: ["**/*.go", "**/*.tpl"]
exclude_dir = ["assets", "vendor"] action: "exclude" with patterns
delay = 1000 Built-in debouncing
[log] section Use settings.prefix_logs
Example Migration

Before (air.toml):

root = "."
tmp_dir = "tmp"

[build]
  bin = "./tmp/main"
  cmd = "go build -o ./tmp/main ."
  delay = 1000
  exclude_dir = ["assets", "tmp", "vendor"]
  exclude_file = []
  exclude_regex = ["_test.go"]
  exclude_unchanged = true
  follow_symlink = false
  full_bin = "./tmp/main"
  include_dir = []
  include_ext = ["go", "tpl", "tmpl", "html"]
  kill_delay = "0s"
  log = "build-errors.log"
  send_interrupt = false
  stop_on_error = true

[color]
  app = ""
  build = "yellow"
  main = "magenta"
  runner = "green"
  watcher = "cyan"

[log]
  time = false

[misc]
  clean_on_exit = false

After (devloop.yaml):

settings:
  prefix_logs: true
  prefix_max_length: 10

rules:
  - name: "Go App"
    prefix: "go"
    workdir: "."
    watch:
      - action: "exclude"
        patterns:
          - "assets/**"
          - "tmp/**"
          - "vendor/**"
          - "**/*_test.go"
      - action: "include"
        patterns:
          - "**/*.go"
          - "**/*.tpl"
          - "**/*.tmpl"
          - "**/*.html"
    commands:
      - "go build -o ./tmp/main ."
      - "./tmp/main"
Key Differences
  1. Multiple Rules: devloop supports multiple concurrent rules, while Air focuses on a single build process
  2. No Temp Directory: devloop doesn't require a temporary directory
  3. Better Process Management: devloop uses process groups for cleaner termination
  4. Distributed Mode: devloop supports agent/gateway architecture for multi-project setups
  5. API Access: devloop provides gRPC/REST APIs for monitoring and control
Advanced Migration Tips
  1. For Complex Build Steps:

    commands:
      - "go generate ./..."
      - "go mod tidy"
      - "go build -ldflags='-s -w' -o ./bin/app ./cmd/app"
      - "./bin/app"
    
  2. For Multiple Services:

    rules:
      - name: "API Server"
        prefix: "api"
        watch:
          - action: "include"
            patterns: ["cmd/api/**/*.go", "internal/**/*.go"]
        commands:
          - "go build -o bin/api ./cmd/api"
          - "bin/api --port 8080"
    
      - name: "Worker"
        prefix: "worker"
        watch:
          - action: "include"
            patterns: ["cmd/worker/**/*.go", "internal/**/*.go"]
        commands:
          - "go build -o bin/worker ./cmd/worker"
          - "bin/worker"
    
  3. For Test Automation:

    rules:
      - name: "Tests"
        prefix: "test"
        watch:
          - action: "include"
            patterns: ["**/*.go"]
        commands:
          - "go test -v ./..."
    
Migration Checklist
  • Run devloop convert to generate initial config
  • Review and adjust file patterns
  • Update build commands if needed
  • Test with devloop -c .devloop.yaml
  • Remove .air.toml and Air dependency
  • Update your README/documentation
  • Update CI/CD scripts if applicable
Running the Orchestrator

devloop will start watching your files. When changes occur that match your defined rules, it will execute the corresponding commands. You will see log output indicating which rules are triggered and which commands are being run.

To stop devloop gracefully, press Ctrl+C (SIGINT). devloop will attempt to terminate any running child processes before exiting, ensuring a clean shutdown of your development environment.

πŸ”§ Troubleshooting

Common Issues and Solutions
1. Configuration File Not Found

Error: Failed to read config file: open .devloop.yaml: no such file or directory

Solutions:

  • Ensure .devloop.yaml exists in your current directory
  • Use -c flag to specify the config path: devloop -c path/to/.devloop.yaml
  • Check file permissions: ls -la .devloop.yaml
2. Commands Not Executing

Symptoms: File changes detected but commands don't run

Solutions:

  • Verify glob patterns match your files:
    # Test pattern matching
    find . -name "*.go" | grep -E "pattern"
    
  • Check command syntax - commands run via bash -c
  • Ensure commands are in your PATH
  • Add debug output to commands:
    commands:
      - "echo 'Rule triggered for: $DEVLOOP_TRIGGER_FILE'"
      - "your-actual-command"
    
3. Process Won't Terminate

Symptoms: Old processes keep running after file changes

Solutions:

  • Ensure your process handles SIGTERM properly
  • For servers, implement graceful shutdown:
    // Go example
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
    <-sigChan
    server.Shutdown(context.Background())
    
  • Use process managers that handle signals correctly
4. High CPU Usage

Symptoms: devloop consuming excessive CPU

Solutions:

  • Reduce watch scope - avoid watching node_modules, .git, etc.:
    watch:
      - action: "exclude"
        patterns:
          - "node_modules/**"
          - ".git/**"
          - "*.log"
      - action: "include"
        patterns:
          - "src/**/*.js"
    
  • Check for recursive file generation (logs writing to watched directories)
  • Ensure proper debouncing is working
5. Port Already in Use

Error: listen tcp :8080: bind: address already in use

Solutions:

  • Kill existing processes: lsof -ti:8080 | xargs kill -9
  • Use different ports for different rules
  • Implement port checking in your startup scripts:
    commands:
      - "kill $(lsof -ti:8080) || true"
      - "npm start"
    
6. Permission Denied Errors

Error: permission denied

Solutions:

  • Check file permissions: chmod +x your-script.sh
  • Run devloop with appropriate user permissions
  • For privileged ports (<1024), use port forwarding or reverse proxy
7. Log Output Issues

Symptoms: Missing or garbled log output

Solutions:

  • Enable log prefixing for clarity:
    settings:
      prefix_logs: true
      prefix_max_length: 10
    
  • Check if commands buffer output (use unbuffered mode):
    commands:
      - "python -u script.py"  # Unbuffered Python
      - "node --no-buffering app.js"  # Unbuffered Node.js
    
8. Agent Can't Connect to Gateway

Error: Failed to connect to gateway

Solutions:

  • Verify gateway is running: curl http://gateway-host:8080/projects
  • Check network connectivity: ping gateway-host
  • Ensure correct gateway URL format: --gateway-url host:port
  • Check firewall rules allow connection
9. File Changes Not Detected

Symptoms: Modifying files doesn't trigger rules

Solutions:

  • Verify file system supports inotify (Linux) or FSEvents (macOS)
  • Check if you're editing files via network mount (may not trigger events)
  • Ensure patterns are correct - use ** for recursive matching:
    # Wrong
    patterns: ["*.go"]  # Only matches root directory
    
    # Correct
    patterns: ["**/*.go"]  # Matches all subdirectories
    
10. Memory Leaks

Symptoms: Memory usage grows over time

Solutions:

  • Ensure commands properly clean up resources
  • Check for accumulating log files
  • Monitor with: ps aux | grep devloop
  • Restart devloop periodically if needed
Debug Mode

To get more detailed output for troubleshooting:

# Run with verbose logging (when implemented)
devloop -v -c .devloop.yaml

# Check devloop version
devloop --version

# Validate configuration
devloop validate -c .devloop.yaml
Getting Help

If you continue experiencing issues:

  1. Check existing issues: https://github.com/panyam/devloop/issues
  2. Create a minimal reproducible example
  3. Include your .devloop.yaml configuration
  4. Provide system information:
    go version
    uname -a
    devloop --version
    
Log Interpretation

Understanding log prefixes:

  • [devloop] - Internal devloop operations
  • [rule-name] - Output from your rule's commands
  • ERROR - Critical errors requiring attention
  • WARN - Non-critical issues
  • INFO - General information
  • DEBUG - Detailed debugging information (verbose mode)

❓ FAQ

Why not just use Docker Compose?

Docker is excellent for production-like environments, but adds overhead for local development:

  • Container rebuild times vs millisecond restarts
  • File sync delays (especially on macOS)
  • Resource consumption for multiple containers
  • Debugging friction through container layers
  • Configuration complexity for simple watch tasks

Devloop is designed for the tight feedback loop of development, where speed matters more than isolation.

Why not use tmux/screen with multiple panes?

Terminal multiplexers manage windows, not processes. Devloop provides:

  • Unified logging with automatic prefixes
  • Proper process lifecycle management
  • Restart on file changes
  • API access for monitoring and control
  • Cross-platform consistency
How is this different from Foreman/Overmind?

Foreman and Overmind are great for Procfile-based applications. Devloop adds:

  • File watching with automatic triggers
  • Glob pattern matching for fine-grained control
  • Multi-project orchestration via agent/gateway mode
  • gRPC/REST API for programmatic access
  • Integration with AI tools via MCP
Why not Make with parallel jobs?

Make is a build tool, not a process manager. It's not designed for:

  • Long-running processes
  • Restarting on file changes
  • Managing process lifecycles
  • Handling streaming logs from multiple sources
Can I use devloop in production?

Devloop is designed for development environments. For production, use proper orchestration tools like:

  • Kubernetes for containerized workloads
  • systemd for system services
  • Docker Swarm or Nomad for distributed applications
How does devloop handle process cleanup?

Devloop uses process groups to ensure clean termination:

  • Each rule's commands run in a separate process group
  • On restart or shutdown, SIGTERM is sent to the entire group
  • This prevents orphaned processes and ensures proper cleanup
Does devloop support Windows?

Yes, devloop is fully cross-platform:

  • Command execution: Uses cmd /c on Windows, bash -c (or sh -c) on Unix
  • Process management: Adapted for Windows process group differences
  • File watching: Works reliably via fsnotify on all platforms
  • Signal handling: Platform-appropriate termination signals

Minor differences:

  • Process group management implementation varies by OS
  • Some signal handling features may behave slightly differently
Can I mix devloop with other tools?

Absolutely! Common patterns include:

  • Using devloop to orchestrate multiple tools (air, nodemon, etc.)
  • Running devloop alongside Docker for databases
  • Combining with Make for complex build steps

⚑ Performance & Optimization

Performance Characteristics

devloop is designed for efficiency with minimal overhead:

  • Memory Usage: ~10-20MB base + rule overhead
  • CPU Usage: <1% when idle, scales with file system events
  • Startup Time: <100ms for typical configurations
  • File Watch Latency: <50ms from file change to command trigger
Optimization Tips
1. Minimize Watch Scope
# Bad - watches everything
watch:
  - action: "include"
    patterns: ["**/*"]

# Good - specific patterns
watch:
  - action: "exclude"
    patterns:
      - "node_modules/**"
      - ".git/**"
      - "dist/**"
      - "*.log"
  - action: "include"
    patterns:
      - "src/**/*.js"
      - "package.json"
2. Use Exclude Patterns First

Exclusions are processed before inclusions, making them more efficient:

watch:
  - action: "exclude"
    patterns: ["**/test/**", "**/*.test.js"]
  - action: "include"
    patterns: ["**/*.js"]
3. Optimize Commands
# Combine commands when possible
commands:
  - "go build -o bin/app && ./bin/app"

# Use incremental builds
commands:
  - "go build -i -o bin/app ./cmd/app"
4. Leverage Process Groups

devloop automatically manages process groups, but ensure your apps handle SIGTERM:

// Graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

go func() {
    <-sigChan
    cancel()
}()
5. Configure Debouncing

devloop has built-in debouncing to prevent command storms during rapid file changes.

Project Organization Tips
1. Monorepo Structure
rules:
  - name: "Shared Libraries"
    watch:
      - action: "include"
        patterns: ["packages/shared/**/*.ts"]
    commands:
      - "cd packages/shared && npm run build"
  
  - name: "Service A"
    watch:
      - action: "include"
        patterns: 
          - "services/service-a/**/*.go"
          - "packages/shared/dist/**"
    commands:
      - "cd services/service-a && go run ."
2. Microservices with Gateway
# Central gateway
devloop --mode gateway --gateway-port 8080

# Each service
cd service-a && devloop --mode agent --gateway-url localhost:8080
cd service-b && devloop --mode agent --gateway-url localhost:8080
3. Development vs Production
# dev.devloop.yaml
rules:
  - name: "Dev Server"
    env:
      NODE_ENV: "development"
    commands:
      - "npm run dev"

# prod.devloop.yaml  
rules:
  - name: "Prod Build"
    env:
      NODE_ENV: "production"
    commands:
      - "npm run build"
      - "npm start"
4. Testing Strategy
rules:
  - name: "Unit Tests"
    watch:
      - action: "include"
        patterns: ["**/*.go"]
    commands:
      - "go test -short ./..."
  
  - name: "Integration Tests"
    watch:
      - action: "include"
        patterns: ["**/*.go", "docker-compose.yml"]
    commands:
      - "docker-compose up -d"
      - "go test -tags=integration ./..."
      - "docker-compose down"
Benchmarks

Typical performance for a medium-sized project (10K files, 5 rules):

Operation Time Memory
Startup 87ms 15MB
File change detection 12ms +0.1MB
Rule trigger 23ms +0.5MB
Idle (watching) - 18MB
Resource Limits

For large projects, consider system limits:

# Increase file watch limits (Linux)
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Check current limits
cat /proc/sys/fs/inotify/max_user_watches

πŸ› οΈ Development Status & Roadmap

devloop is stable and ready for use. All core features are implemented and tested.

Future development will focus on:

  • Enhanced User Experience: Improving error messages, logging, and providing more detailed feedback.
  • Advanced Configuration: Exploring more powerful configuration options, such as rule dependencies or conditional execution.
  • Plugin System: A potential plugin system to allow for custom extensions and integrations.
  • Broader Community Adoption: Creating more examples and tutorials for different languages and frameworks.

🀝 Contributing

Contributions are welcome! Please feel free to open issues or submit pull requests.

πŸ“„ License

This project is licensed under the Apache License - see the LICENSE file for details.

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
gen
go/protos/devloop/v1
Package v1 is a reverse proxy.
Package v1 is a reverse proxy.

Jump to

Keyboard shortcuts

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