Socket
Book a DemoInstallSign in
Socket

github.com/panyam/devloop

Package Overview
Dependencies
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

github.com/panyam/devloop

v0.0.73
Source
Go
Version published
Created
Source

devloop: Multi-Component Project Watcher

Screenshot

devloop is a versatile tool designed to streamline your inner development loop, 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.

Workflow Overview

🏗️ Architecture Overview

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

1. Standalone Mode (Default)

Like Air but for multiple components. Devloop runs as a local file watcher that monitors multiple file types and components within a single project directory. No network servers or connectivity.

Standalone Mode Architecture

Use Case: Single project development, local development only, no external API needed.

2. Agent Mode

Like Standalone mode but with an embedded gRPC server. Devloop watches multiple components in a single project while also providing API access for external clients to connect directly to this agent. Includes MCP integration via HTTP handler when enabled.

Agent Mode Architecture

Use Case: Single project that needs API access, AI integration, remote monitoring.

3. Gateway Mode

Multiple separate daemon processes (each watching their own project components) connect to a central gateway hub. Clients connect only to the gateway, which aggregates information from all connected daemons.

Gateway Mode Architecture

# Start the central gateway
devloop --mode gateway --http-port 9999 --grpc-port 55555

# Connect individual project daemons to the gateway
devloop --mode agent --gateway-addr localhost:55555 -c project-a/.devloop.yaml
devloop --mode agent --gateway-addr localhost:55555 -c project-b/.devloop.yaml

Note: Gateway mode is temporarily removed and will be reimplemented using the grpcrouter library for simplified proxy and reverse tunnel functionality.

Use Case: Microservices, monorepos, multi-project development with centralized monitoring.

📋 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

  • Install devloop:

    go install github.com/panyam/devloop@latest
    
  • Initialize a new configuration:

    # Create basic configuration
    devloop init
    
    # Or create with specific project profiles
    devloop init golang           # Go project
    devloop init ts python        # TypeScript + Python projects
    devloop init go ts py         # Multiple projects with aliases
    
  • Or manually 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
    
  • 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.

Quick Configuration with devloop init

The init command provides pre-configured templates for common project types:

Available profiles:

  • golang (alias: go) - Go project with build and run commands
  • typescript (aliases: ts, node, nodejs) - TypeScript/Node.js project with build and serve
  • python (aliases: py, flask) - Python Flask project with development server

Usage examples:

devloop init                    # Basic "Hello World" configuration
devloop init golang             # Go project configuration  
devloop init ts python          # TypeScript and Python configurations
devloop init --output custom.yaml golang  # Custom output location
devloop init --force golang     # Overwrite existing configuration

📚 Examples

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

ExampleDescriptionKey TechnologiesUse Case
01-fullstack-webComplete web application with backend, frontend, database, and docsGo, JavaScript, SQL, HTTPTraditional web development with multiple parallel services
02-microservicesDistributed microservices architecture with gateway patternGo, API Gateway, JWT, HTTPService-oriented architecture with centralized monitoring
03-python-datascienceData science workflow with notebooks, training, and testingPython, Jupyter, pytest, MLData analysis and machine learning development
04-docker-composeMulti-container development with orchestrated servicesDocker, PostgreSQL, Redis, React, Go, PythonContainerized application development
05-frontend-frameworkModern frontend development with multiple frameworksReact, Vue.js, TypeScript, Storybook, ViteComponent-driven frontend development

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

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

SolutionGood ForNot Great For
Docker ComposeProduction-like isolationFast local iteration
tmux/screenTerminal managementProcess lifecycle
Make -jBuild orchestrationLong-running services
Foreman/OvermindProcfile-based appsFile watching & triggers
Shell scriptsSimple automationComplex process management
devloopMulti-service developmentProduction deployment

Feature Comparison

Featuredevloopairnodemonwatchexec
Language FocusMulti-languageGoNode.jsAny
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 FormatYAMLTOMLJSONCLI 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.
  • Cross-Platform Support: Commands execute natively on Windows (cmd /c), macOS, and Linux (bash -c with sh -c fallback).
  • Color-Coded Output: Automatically assigns consistent colors to each rule's output, making it easy to distinguish logs in busy development environments. Preserves native colors from subprocess tools like npm, go test, etc.
  • Channel-Based Event Handling: Clean Go concurrency patterns with file changes routed through channels for reliable debouncing and execution.
  • Command Log Prefixing: Prepends a customizable prefix to each line of your command's output, with optional color coding for enhanced readability.
  • .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)
  color_logs: boolean          # Enable colored output (default: true)
  color_scheme: string         # Color scheme: "auto", "dark", "light" (default: "auto")
  custom_colors:               # Optional: Custom color mappings
    rule_name: "color"         # Map rule names to specific colors
  verbose: boolean             # Global verbose logging (default: false)
  default_debounce_delay: duration  # Global debounce delay (default: 500ms)
  max_parallel_rules: number   # Maximum concurrent rules (default: 0 = unlimited)

rules:                         # Required: Array of rules
  - name: string              # Required: Unique rule identifier
    prefix: string            # Optional: Custom log prefix (defaults to name)
    color: string             # Optional: Custom color for this rule's output
    workdir: string           # Optional: Working directory for commands (defaults to config dir)
    run_on_init: boolean      # Optional: Run on startup (default: true)
    verbose: boolean          # Optional: Per-rule verbose logging
    debounce_delay: duration  # Optional: Per-rule debounce delay (e.g., "200ms")
    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

OptionTypeDefaultDescription
prefix_logsbooleantruePrepend rule name/prefix to each output line
prefix_max_lengthintegerunlimitedTruncate/pad prefixes to this length for alignment
color_logsbooleantrueEnable colored output to distinguish different rules
color_schemestring"auto"Color palette: "auto" (detect), "dark", "light", or "custom"
custom_colorsmap{}Map rule names to specific colors (e.g., rule_name: "blue")
verbosebooleanfalseEnable verbose logging globally
default_debounce_delayduration"500ms"Default delay before executing commands after file changes
suppress_subprocess_colorsbooleanfalseSuppress colors from subprocess output (npm, go test, etc.)

Rule Options

OptionTypeRequiredDescription
namestringUnique identifier for the rule
prefixstringCustom prefix for log output (overrides name)
colorstringCustom color for this rule's output (e.g., "blue", "red", "bold-green")
workdirstringWorking directory for command execution (defaults to config file directory)
verbosebooleanEnable verbose logging for this rule only
debounce_delaydurationDelay before executing after file changes (e.g., "200ms")
envmapAdditional environment variables
watcharrayFile patterns to monitor
commandsarrayCommands to execute when files change
run_on_initbooleanRun commands on startup (default: true)
exit_on_failed_initbooleanExit devloop when this rule fails startup (default: false)
max_init_retriesintegerMaximum retry attempts for failed startup (default: 10)
init_retry_backoff_baseintegerBase backoff duration in ms for startup retries (default: 3000)

Watch Configuration

Each watch entry consists of:

FieldTypeValuesDescription
actionstringinclude, excludeWhether to trigger on or ignore matches
patternsarrayglob patternsFile 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

Startup Behavior and Retry Logic

devloop includes robust startup retry logic to handle transient failures during initialization:

rules:
  - name: "Database"
    commands:
      - "docker-compose up -d postgres"
      - "wait-for-postgres.sh"
    # Critical service - exit devloop if this fails after retries
    exit_on_failed_init: true
    max_init_retries: 5
    init_retry_backoff_base: 5000  # 5s, 10s, 20s, 40s, 80s backoff
    
  - name: "API Server"  
    commands:
      - "go build -o bin/api ./cmd/api"
      - "./bin/api"
    # Default behavior: retry failures but don't exit devloop
    # exit_on_failed_init: false (default)
    # max_init_retries: 10 (default) 
    # init_retry_backoff_base: 3000 (default - 3s, 6s, 12s, 24s...)

Startup Retry Behavior:

  • By default, failed rules retry up to 10 times with exponential backoff
  • Backoff starts at 3 seconds and doubles each attempt (3s, 6s, 12s, 24s, etc.)
  • devloop continues running and watching files even if some rules fail startup
  • Set exit_on_failed_init: true for critical rules that must succeed

Retry Configuration:

  • exit_on_failed_init: Whether to exit devloop when this rule fails startup (default: false)
  • max_init_retries: Maximum retry attempts (default: 10)
  • init_retry_backoff_base: Base backoff duration in milliseconds (default: 3000)

Example Log Output:

[api] Rule "api" execution failed (attempt 1/11): exit status 1
[api] Rule "api" failed, retrying in 3s (attempt 2/11) at 15:04:08
[api] Rule "api" execution failed (attempt 2/11): exit status 1
[api] Rule "api" failed, retrying in 6s (attempt 3/11) at 15:04:14
[api] Rule "api" succeeded on attempt 3/11

Example with All Options

settings:
  prefix_logs: true
  prefix_max_length: 12
  color_logs: true
  suppress_subprocess_colors: false  # Preserve colors from npm, go test, etc.

rules:
  - name: "Backend API"
    prefix: "api"
    workdir: "./backend"
    exit_on_failed_init: false
    max_init_retries: 5
    init_retry_backoff_base: 2000
    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

  • Sequential Execution: Commands run in the order specified
  • Cross-Platform Shell Execution: Commands run via platform-specific shells (bash -c on Unix, cmd /c on Windows)
  • Process Groups: Commands run in separate process groups for clean termination
  • Environment Inheritance: Commands inherit parent environment plus env variables
  • Working Directory: Commands execute in workdir (or directory containing the config file if not set)
  • Process Termination: Previous instances receive SIGTERM when rule re-triggers
  • Error Handling: Failed commands don't stop subsequent commands in the list

Environment Variable Precedence

  • System environment variables
  • Variables from env configuration (overrides system vars)
  • 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:9999 (default gateway port)

List All Projects

GET /projects

Returns all registered devloop projects and their connection status.

Response:

{
  "projects": [
    {
      "projectId": "auth-service",
      "projectRoot": "/path/to/auth-service",
      "status": "CONNECTED"
    }
  ]
}

Get Project Configuration

GET /projects/{projectId}/config

Returns the full configuration for a specific project.

Response:

{
  "configJson": "{\"rules\":[{\"name\":\"backend\",\"commands\":[\"go run .\"]}]}"
}

Get Rule Status

GET /projects/{projectId}/status/{ruleName}

Returns the current status of a specific rule.

Response:

{
  "ruleStatus": {
    "projectId": "backend",
    "ruleName": "backend", 
    "isRunning": true,
    "startTime": "1704092400000",
    "lastBuildTime": "1704092400000",
    "lastBuildStatus": "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:

{
  "paths": [
    "**/*.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: {"projectId":"backend","ruleName":"api","line":"Starting server...","timestamp":"1704092400000"}

data: {"projectId":"backend","ruleName":"api","line":"Server listening on :9999","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": [
    {
      "projectId": "backend",
      "ruleName": "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:9999/api/projects');
const data = await response.json();

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

Python

import requests
import sseclient

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

# Stream logs
response = requests.get('http://localhost:9999/api/projects/backend/stream/logs/api', stream=True)
client = sseclient.SSEClient(response)
for event in client.events():
    log = json.loads(event.data)
    print(f"[{log['ruleName']}] {log['line']}")

Go

// Using the generated gRPC client
conn, _ := grpc.NewClient("localhost:55555", grpc.WithTransportCredentials(insecure.NewCredentials()))
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.Status)
}

🤖 MCP Server Integration

Devloop can act as a Model Context Protocol (MCP) server, enabling AI agents and LLMs (like Claude) to monitor and control your development workflows. The MCP server runs as an HTTP handler alongside the gRPC API when enabled.

MCP Integration Architecture

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 Devloop with MCP Enabled

# Start standalone mode with MCP server enabled
devloop --grpc-port 5555 --http-port 9999 --enable-mcp -c .devloop.yaml

The MCP server runs as an HTTP handler on the /mcp endpoint, using the same Agent Service that provides the gRPC API.

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. Access MCP Endpoint

The MCP server is available at the /mcp HTTP endpoint:

# MCP endpoint (when --enable-mcp is used)
http://localhost:9999/mcp/

Using with Claude Desktop

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

{
  "mcpServers": {
    "devloop": {
      "type": "http",
      "url": "http://localhost:9999/mcp/"
    }
  }
}

Available MCP Tools

When connected, the following tools are available to AI agents (auto-generated from the Agent Service protobuf definitions):

Project Management

// Get project configuration
await use_mcp_tool("devloop", "GetConfig", {});

// Get specific rule information
await use_mcp_tool("devloop", "GetRule", {
  ruleName: "backend-build"
});

// List watched file paths
await use_mcp_tool("devloop", "ListWatchedPaths", {});

Rule Control

// Trigger a rule manually
await use_mcp_tool("devloop", "TriggerRule", {
  ruleName: "backend-build"
});

// Stream logs (placeholder for future implementation)
// await use_mcp_tool("devloop", "StreamLogs", {
//   ruleName: "backend-build"
// });

Legacy Example (for reference)

// 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
});

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:

  • "Run the tests for the backend project"
  • "Show me any failing tests"
  • "Read the source file for the failing test"
  • "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
    }
  }
}

📡 Available Endpoints by Mode

Different devloop modes provide different endpoints and capabilities:

Standalone Mode (--mode standalone)

devloop --mode standalone --http-port 9999 --grpc-port 55555 --enable-mcp
  • ✅ HTTP API: http://localhost:9999/api/projects
  • ✅ gRPC API: localhost:55555
  • ✅ MCP via HTTP: http://localhost:9999/mcp/ (if --enable-mcp)
  • ✅ File watching and rule execution

Gateway Mode (--mode gateway)

devloop --mode gateway --http-port 9999 --grpc-port 55555 --enable-mcp
  • ✅ HTTP API: http://localhost:9999/api/projects
  • ✅ gRPC API: localhost:55555
  • ✅ Agent management and coordination
  • ✅ MCP via HTTP: http://localhost:9999/mcp/ (if --enable-mcp)
  • ❌ No direct file watching (agents do the watching)
  • ⚠️ Note: Gateway mode temporarily removed, being reimplemented with grpcrouter

Agent Mode (--mode agent --gateway-addr localhost:55555)

devloop --mode agent --gateway-addr localhost:55555
  • ❌ No HTTP API endpoints (connects to gateway)
  • ❌ No direct gRPC API (uses gateway's API)
  • ❌ No MCP server (MCP only available in standalone/gateway modes)
  • ✅ File watching and rule execution
  • ✅ Reports to gateway

Quick Test Commands:

# Test standalone/gateway HTTP API
curl http://localhost:9999/api/projects

# Test MCP HTTP endpoints (when --enable-mcp)
curl http://localhost:9999/mcp/

# Test if any devloop process is running
ps aux | grep devloop

Troubleshooting MCP Integration

Connection Issues

Note: MCP uses StreamableHTTP transport for universal compatibility.

# Check if devloop is running with MCP enabled
ps aux | grep devloop

# Test MCP HTTP endpoint (when --enable-mcp is specified)
curl http://localhost:9999/mcp/

# Test regular HTTP API endpoints
curl http://localhost:9999/api/

# MCP communication:
# - stdio: For process-launched clients (Claude Desktop)
# - HTTP: For network clients (web tools, external integrations)

Common Problems

  • "MCP server not found"

    • Ensure devloop is running with --enable-mcp flag and --http-port specified
    • Check firewall settings
  • "Tool execution failed"

    • Verify the rule name exists in your .devloop.yaml
    • Check the gRPC server is running (requires --grpc-port)
  • "Timeout waiting for response"

    • Increase timeout in tool parameters
    • Check if commands are hanging

Best Practices

  • Use Descriptive Project IDs: Makes it easier for AI to identify projects
  • Use Descriptive Rule Names: Makes it easier for AI to identify and trigger rules
  • Set Reasonable Timeouts: Prevent long-running operations from blocking
  • Monitor Rate Limits: Prevent AI from overwhelming your system
  • 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-addr localhost:55555 -c .devloop.yaml

Running in Gateway Mode

To start a central gateway:

devloop --mode gateway --gateway-port 9999

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

Subcommands

devloop also supports subcommands for specific utilities:

init

Initialize a new .devloop.yaml configuration file with predefined project profiles.

devloop init [profiles...]

Available profiles:

  • golang (alias: go) - Go project with build and run commands
  • typescript (aliases: ts, node, nodejs) - TypeScript/Node.js project
  • python (aliases: py, flask) - Python Flask development server

Examples:

devloop init                    # Basic "Hello World" configuration
devloop init golang             # Go project configuration
devloop init ts python          # Multiple profiles
devloop init -o config.yaml go  # Custom output file
devloop init --force golang     # Overwrite existing file

Flags:

  • -o, --output - Output file path (default: .devloop.yaml)
  • -f, --force - Overwrite existing configuration file

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

  • Convert your .air.toml automatically:

    devloop convert -i .air.toml > .devloop.yaml
    
  • 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] sectionSingle 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 = 1000Built-in debouncing
[log] sectionUse 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

  • Multiple Rules: devloop supports multiple concurrent rules, while Air focuses on a single build process
  • No Temp Directory: devloop doesn't require a temporary directory
  • Better Process Management: devloop uses process groups for cleaner termination
  • Distributed Mode: devloop supports agent/gateway architecture for multi-project setups
  • API Access: devloop provides gRPC/REST APIs for monitoring and control

Advanced Migration Tips

  • For Complex Build Steps:

    commands:
      - "go generate ./..."
      - "go mod tidy"
      - "go build -ldflags='-s -w' -o ./bin/app ./cmd/app"
      - "./bin/app"
    
  • 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 9999"
    
      - name: "Worker"
        prefix: "worker"
        watch:
          - action: "include"
            patterns: ["cmd/worker/**/*.go", "internal/**/*.go"]
        commands:
          - "go build -o bin/worker ./cmd/worker"
          - "bin/worker"
    
  • 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.

Development & Testing

Running Tests

# Run all tests
make test

# Run tests with coverage
make coverage-agent

# Generate HTML coverage report
make coverage-agent-html

# Open coverage report in browser
make coverage-agent-open

Test Coverage

The project maintains 57% test coverage with testing for:

  • WorkerPool Process Management: Process lifecycle, termination, job killing, debounce logic
  • Scheduler Integration: Event-driven routing, mixed workload scenarios
  • WorkerPool: Unified job execution, global parallelism, process management
  • File Watching: Per-rule watchers, pattern matching, dynamic directories
  • Configuration: YAML parsing, validation, rule loading

Coverage Reports

All test artifacts are organized in the reports/ directory:

  • reports/agent_coverage.out - Coverage data
  • reports/agent_coverage.html - Interactive HTML report
  • Use make coverage-help to see all available coverage targets

Process Management

Devloop intelligently handles all types of processes with unified execution:

settings:
  max_parallel_rules: 5  # Global worker pool size for all jobs

rules:
  - name: "build"      # Short-running - completes quickly
    commands:
      - "go build -o bin/server"
      
  - name: "dev-server" # Long-running - will be killed/restarted on changes
    commands:
      - "./bin/server --dev"

Process Management Benefits:

  • Unified Execution: All jobs use the same worker pool and process management
  • Smart Killing: File changes respect debounce window; manual triggers restart immediately
  • Global Concurrency: Configure worker pool size once for all job types
  • Graceful Termination: SIGTERM to SIGKILL progression with process group handling

🔧 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 :9999: bind: address already in use

Solutions:

  • Kill existing processes: lsof -ti:9999 | xargs kill -9
  • Use different ports for different rules
  • Implement port checking in your startup scripts:
    commands:
      - "kill $(lsof -ti:9999) || 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:9999/projects
  • Check network connectivity: ping gateway-host
  • Ensure correct gateway address format: --gateway-addr host:port (note: it's gateway-addr, not gateway-url)
  • Check firewall rules allow connection
  • Verify gateway is in "gateway" mode, not "agent" mode

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:

  • Check existing issues: https://github.com/panyam/devloop/issues
  • Create a minimal reproducible example
  • Include your .devloop.yaml configuration
  • 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.

6. Control Rule Parallelism

Use max_parallel_rules to control concurrent rule execution for debugging or resource management:

settings:
  max_parallel_rules: 1  # Sequential execution for debugging
  
# Or unlimited (default)
settings:
  max_parallel_rules: 0  # All rules can run concurrently

Use Cases:

  • Sequential debugging (1): Isolate rule chains and prevent overlapping output
  • Resource limited (N): Prevent overwhelming system resources
  • Default (0): Maximum performance with unlimited concurrency

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 9999

# Each service
cd service-a && devloop --mode agent --gateway-url localhost:9999
cd service-b && devloop --mode agent --gateway-url localhost:9999

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):

OperationTimeMemory
Startup87ms15MB
File change detection12ms+0.1MB
Rule trigger23ms+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.

FAQs

Package last updated on 30 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.