CLAUDE.md 29 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a modular Node.js webhook server for Gogs (Git service) that receives webhooks and executes configurable shell commands based on events. The main server uses zero external dependencies - only built-in Node.js modules.

NEW: The project now includes a TypeScript-based Claude Agent SDK client (client/) for AI-powered issue automation, replacing the previous bash-based implementation.

Architecture

Module Structure

The codebase follows a clean separation of concerns with seven main modules:

index.js (Entry Point)
    ├── server.js (HTTP Server)
    │   └── webhookHandler.js (Event Management)
    ├── jobQueue.js (Job Queue & Persistence)
    │   └── commandExecutor.js (Command Execution)
    ├── emailNotifier.js (Email Notifications)
    │   └── emailSender.js (SMTP Email Sender)
    ├── config.js (Configuration)
    └── logger.js (Logging)

Key Components

WebhookServer (src/server.js)

  • HTTP server using Node.js http and crypto modules
  • Routes: POST /webhook, GET /health
  • Provides getHandler() to access WebhookHandler for callback registration
  • Binds to configurable host (0.0.0.0 by default) and port (3000 by default)
  • Implements HMAC-SHA256 signature verification for webhook security
  • Uses timing-safe comparison to prevent timing attacks

WebhookHandler (src/webhookHandler.js)

  • Event-driven callback system
  • Two callback types:
    • handler.on(eventType, callback) - Event-specific callbacks
    • handler.onAny(callback) - Global callbacks for all events
  • Callbacks receive: (payload, headers) or (eventType, payload, headers) for global

JobQueue (src/jobQueue.js)

  • Persistent job queue with FIFO (first-in-first-out) processing
  • Two operating modes:
    • Single-queue mode (default): One global queue, jobs execute sequentially
    • Multi-queue mode: Separate FIFO queue per repository, enables parallel execution across repositories
  • Webhooks are accepted immediately and added to queue
  • Queue state persisted to queue.json for crash recovery
  • Automatically resumes processing pending jobs after restart
  • Jobs that were running during shutdown are reset to pending state
  • Mode is configurable via QUEUE_PARALLEL_PER_REPOSITORY environment variable

CommandExecutor (src/commandExecutor.js)

  • Variable substitution engine using {{variable}} syntax
  • Executes shell commands via /bin/bash with timeout protection
  • Extracts 16+ variables from webhook payloads: {{repo}}, {{branch}}, {{pusher}}, {{commit}}, {{pr_number}}, {{issue_number}}, {{issue_title}}, etc.
  • Default timeout: 300000ms (5 minutes), configurable via COMMAND_TIMEOUT

Config (src/config.js)

  • Loads .env file synchronously on startup
  • Merges with process.env (env vars take precedence)
  • Provides type-safe getters: get(), getBoolean(), getNumber()
  • Exported as singleton

Logger (src/logger.js)

  • Console and file-based logger with ANSI colors and timestamps
  • Methods: info(), error(), webhook(), warn(), debug(), jobLifecycle()
  • File logging support with automatic rotation:
    • Enabled by default when running as systemd service
    • Configurable via FILE_LOGGING_ENABLED environment variable
    • Default log file: /var/log/agent-manager.log
    • Automatic rotation when file reaches MAX_LOG_SIZE (default: 10MB)
    • Keeps up to MAX_LOG_FILES rotated files (default: 5)
    • ANSI color codes stripped from file output
  • Exported as singleton

EmailNotifier (src/emailNotifier.js)

  • Email notification callback system
  • Loads .smtp-config.json for SMTP server configuration
  • Loads email-rules.json for notification rules
  • Registers callbacks for events defined in rules
  • Evaluates conditions (mention, branch, action, user, repository)
  • Substitutes variables in email subjects and bodies
  • Resolves recipient variables ({{mentioned_user}}, {{sender}}, {{assignee}})
  • Exported as singleton

EmailSender (src/emailSender.js)

  • SMTP email sender using Node.js built-in net and tls modules
  • Zero external dependencies
  • Supports STARTTLS and direct TLS connections
  • Implements SMTP authentication (AUTH LOGIN)
  • Builds RFC 5322 compliant email messages
  • Supports both plain text and HTML emails
  • Exported as class (instantiated by EmailNotifier)

Application Flow

  1. index.js loads config and creates WebhookServer
  2. JobQueue loads persisted queue state from queue.json (if exists)
  3. EmailNotifier loads SMTP config and email rules
  4. Gets enabled events from config (WEBHOOK_PUSH_ENABLED=true, etc.)
  5. Registers callbacks for enabled events (webhooks → enqueue jobs)
  6. Registers email notifier callbacks for events in rules
  7. Starts server on configured host:port
  8. On webhook: parses body → triggers callbacks → enqueues job + sends emails → responds immediately
  9. JobQueue processes jobs:
    • Single-queue mode: All jobs execute sequentially (one at a time, FIFO)
    • Multi-queue mode: Jobs from different repositories execute in parallel, each repository maintains FIFO order
  10. Each job: extracts variables → substitutes in command → executes → logs results
  11. Email notifier evaluates conditions and sends emails for matching rules
  12. Graceful shutdown on SIGTERM/SIGINT: saves queue state and stops server

Development Commands

npm start              # Start production server
npm run dev            # Start with auto-reload (--watch flag)
node examples/with-callbacks.js  # Run callback example

System Management (Production)

The agent-manager service runs as a systemd service on the production system.

Restart the service:

sudo /bin/systemctl restart agent-manager

Check service status:

sudo /bin/systemctl status agent-manager

View service logs:

sudo journalctl -u agent-manager -f

View application log file:

tail -f /var/log/agent-manager.log

Debugging: When running as a systemd service, file logging is enabled by default. All application logs (INFO, WARN, ERROR, DEBUG, webhook events, job lifecycle) are written to /var/log/agent-manager.log. The log file is automatically rotated when it reaches 10MB (default), keeping up to 5 rotated files. For troubleshooting issues, check this file for detailed execution logs.

Note: The claude user has passwordless sudo access to restart the agent-manager service via /etc/sudoers.d/50-agent-manager configuration.

Testing endpoints:

curl http://localhost:3000/health

curl -X POST http://localhost:3000/webhook \
  -H "Content-Type: application/json" \
  -H "X-Gogs-Event: push" \
  -H "X-Gogs-Delivery: 12345" \
  -d '{"ref":"refs/heads/main","repository":{"name":"test-repo","full_name":"user/test-repo"},"pusher":{"username":"testuser"},"commits":[{"id":"abc123","message":"Test commit"}]}'

Configuration

Configuration is split between two files:

1. Environment Configuration (.env)

Copy from .env.example and configure:

Server Configuration:

HOST=0.0.0.0          # Network interface (0.0.0.0=all, 127.0.0.1=localhost only)
PORT=3000             # Port number
WEBHOOK_PATH=/webhook # Webhook endpoint path
WEBHOOK_SECRET=       # Optional webhook verification secret

Event Enable/Disable:

WEBHOOK_{EVENT_TYPE}_ENABLED=true|false

Supported Event Types: push, pull_request, create, delete, release, issues, issue_comment, global

File Logging Configuration:

FILE_LOGGING_ENABLED=true|false  # Enable/disable file logging (default: false, auto-enabled for systemd)
LOG_FILE_PATH=/var/log/agent-manager.log  # Path to log file (default: /var/log/agent-manager.log)
MAX_LOG_SIZE=10485760  # Max size in bytes before rotation (default: 10MB)
MAX_LOG_FILES=5  # Number of rotated files to keep (default: 5)

Note: File logging is automatically enabled when running as a systemd service. The logger detects systemd environment and enables file output by default. For debugging, check /var/log/agent-manager.log.

MCP Server Configuration:

GOGS_MCP_PATH=/data/gogs-mcp/dist/index.js  # Path to gogs-mcp server for headless Claude Code

The GOGS_MCP_PATH environment variable configures the location of the gogs-mcp server used by Claude Code in headless mode for issue automation. The handle-issue.sh script dynamically generates the MCP configuration file (.mcp-gogs.json) using this path at runtime, making it environment-specific.

2. Command Configuration (commands.json)

Copy from commands.json.example and configure commands for each event type.

Command Structure:

{
  "commands": {
    "event_type": [
      {
        "name": "command-identifier",
        "description": "Human-readable description",
        "type": "shell" | "node",
        "command": "path/to/command",
        "args": ["arg1", "{{variable}}", "arg3"],
        "cwd": "/working/directory" | null,
        "timeout": 300000,
        "filterBranch": "branch-name" | null,
        "filterActions": ["action1", "action2"] | null,
        "filterAssignee": "username" | null
      }
    ]
  }
}

Command Types:

  • shell - Execute bash shell command/script
  • node - Execute Node.js script (automatically prepends node command)

Per-Command Settings:

  • name - Unique identifier for the command
  • description - Human-readable description
  • type - Execution type (shell or node)
  • command - Command or script path
  • args - Array of arguments (supports variable substitution)
  • cwd - Working directory (null = project root)
  • timeout - Timeout in milliseconds
  • filterBranch - Only execute for specific branch (null = all branches)
  • filterActions - Only execute for specific actions (array, optional). Examples: ["assigned", "opened"], ["synchronize"]. If omitted or empty, execute for all actions
  • filterAssignee - Only execute when issue/PR is assigned to specific user (string, optional). If omitted, execute regardless of assignee

Important Patterns

  1. ES6 Modules: All files use import/export syntax ("type": "module" in package.json)
  2. Singleton Exports: Config, Logger, CommandExecutor, EmailNotifier are singletons (created on import)
  3. Zero Dependencies: Pure Node.js - no npm packages required beyond Node.js built-ins (including SMTP implementation)
  4. Graceful Shutdown: Both SIGTERM and SIGINT trigger server.stop() before exit
  5. Configuration Files:
    • .env for enable/disable flags
    • commands.json for command definitions
    • .smtp-config.json for SMTP server configuration
    • email-rules.json for email notification rules
  6. Backward Compatibility: Legacy .env command format still supported (deprecated)
  7. Error Handling: Try-catch blocks with logging; errors don't stop server
  8. Command Filtering: Optional per-command filtering via:
    • filterBranch - Execute only for specific branches
    • filterActions - Execute only for specific actions (e.g., ["assigned", "opened"])
    • filterAssignee - Execute only when assigned to specific user (e.g., "claude")
  9. Multiple Commands: Each event type can have multiple commands that execute sequentially
  10. Shell & Node Execution: Commands can be shell scripts or Node.js scripts
  11. Email Notifications: Optional callback-based email notifications with condition matching
  12. File Logging: Automatic file logging with rotation (enabled by default for systemd services)

Extending with Callbacks

The server supports custom callback registration beyond .env command execution:

import { WebhookServer } from './src/server.js';

const server = new WebhookServer({ port: 3000 });
const handler = server.getHandler();

// Event-specific callback
handler.on('push', async (payload, headers) => {
  console.log('Push to:', payload.repository.name);
  // Custom logic here
});

// Global callback (all events)
handler.onAny(async (eventType, payload, headers) => {
  console.log('Event:', eventType);
  // Send to analytics, logging, etc.
});

server.start();

See examples/with-callbacks.js for complete example.

Variable Substitution System

Commands in commands.json and legacy .env commands support variable substitution using {{variable}} syntax.

Available variables:

  • {{event}} - Event type (push, create, delete, etc.)
  • {{repo}} - Repository name only
  • {{full_repo}} - User/repository format
  • {{repo_owner}} - Repository owner username
  • {{branch}} - Branch name (extracted from refs)
  • {{pusher}} - Username of person who triggered event
  • {{commit}} - Short commit hash (push events)
  • {{commit_msg}} - Last commit message (push events)
  • {{pr_number}} - Pull request number (PR events)
  • {{pr_action}} - PR action (opened, closed, etc.)
  • {{tag}} - Tag name (create/delete tag events)
  • {{ref_type}} - "branch" or "tag"
  • {{issue_number}} - Issue number (issue events)
  • {{issue_title}} - Issue title (issue events)
  • {{issue_action}} - Issue action (opened, closed, reopened, etc.)
  • {{issue_body}} - Issue description/body (issue events)
  • {{issue_assignee}} - Username of person assigned to issue (issue events)
  • {{issue_labels}} - Comma-separated list of issue label names (issue/issue_comment events)
  • {{comment_body}} - Comment text (issue_comment events)

Variables are extracted in commandExecutor.js via extractVariables() and substituted via substituteVariables().

Job Queue System

The webhook server uses a persistent job queue to ensure reliable command execution. The queue system supports two operating modes:

Operating Modes

Single-Queue Mode (Default)

  • One global FIFO queue for all repositories
  • Jobs execute sequentially, one at a time
  • Prevents conflicts and resource contention
  • Recommended for single-repository setups or when strict sequential execution is required

Multi-Queue Mode (Parallel Per Repository)

  • Separate FIFO queue for each Gogs repository
  • Jobs from different repositories execute in parallel
  • Each repository maintains FIFO order internally
  • Recommended for multi-repository setups where independent execution is desired
  • Enable with: QUEUE_PARALLEL_PER_REPOSITORY=true

Features

  • FIFO Processing: Jobs are executed in the order they are received (per repository in multi-queue mode)
  • Immediate Response: Webhooks are accepted and queued instantly, ensuring no webhook delivery timeouts
  • Persistence: Queue state is saved to queue.json after every change
  • Crash Recovery: Pending jobs are automatically restored and processed after server restart
  • Safe Restart: Jobs marked as "running" during shutdown are reset to "pending" on restart
  • Automatic Cleanup: Empty repository queues are automatically removed (multi-queue mode)

Queue File Structure

Single-Queue Mode:

{
  "queue": [
    {
      "id": 1,
      "eventType": "push",
      "status": "pending",
      "createdAt": "2025-10-28T12:00:00.000Z",
      "config": { "command": "...", "enabled": true }
    }
  ],
  "jobIdCounter": 5,
  "lastSaved": "2025-10-28T12:05:00.000Z"
}

Multi-Queue Mode:

{
  "queues": {
    "owner/repo1": {
      "queue": [
        {
          "id": 1,
          "eventType": "push",
          "status": "pending",
          "createdAt": "2025-10-28T12:00:00.000Z",
          "config": { "command": "...", "enabled": true }
        }
      ]
    },
    "owner/repo2": {
      "queue": [
        {
          "id": 2,
          "eventType": "issues",
          "status": "running",
          "createdAt": "2025-10-28T12:01:00.000Z",
          "config": { "command": "...", "enabled": true }
        }
      ]
    }
  },
  "jobIdCounter": 5,
  "lastSaved": "2025-10-28T12:05:00.000Z"
}

Job Lifecycle

  1. Created: Webhook received → Job created with status "pending"
  2. Queued: Job added to queue and persisted to disk
  3. Running: Job status updated to "running" before execution starts
  4. Completed/Failed: Job finishes → Status updated → Job removed from queue
  5. Next: Queue processes next pending job (if any)

Benefits

Single-Queue Mode:

  • No Lost Jobs: Server crashes won't lose pending webhook events
  • No Concurrent Execution: Prevents race conditions in deployment scripts
  • High Availability: Can accept webhooks even while executing long-running commands
  • Predictable Order: Strict sequential execution across all repositories

Multi-Queue Mode:

  • All benefits of single-queue mode, plus:
  • Parallel Execution: Jobs from different repositories run independently
  • Better Resource Usage: Multiple repositories can be processed simultaneously
  • Reduced Wait Time: One slow repository won't block others
  • Repository Isolation: Issues in one repository don't affect others

Email Notification System

The webhook server includes an email notification system that sends emails based on webhook events and configurable conditions. The system follows the same callback pattern as the Claude agent client.

Architecture

EmailNotifier (src/emailNotifier.js)

  • Callback-based notification system (similar to Claude agent callback)
  • Loads configuration from .smtp-config.json and email-rules.json
  • Registers callbacks with WebhookHandler for events defined in rules
  • Evaluates conditions and sends emails for matching events
  • Supports variable substitution in email subjects and bodies
  • Resolves recipient variables to email addresses

EmailSender (src/emailSender.js)

  • Pure Node.js SMTP implementation using net and tls modules
  • Zero external dependencies (maintains project philosophy)
  • Supports STARTTLS (port 587) and direct TLS (port 465)
  • Implements SMTP AUTH LOGIN authentication
  • Builds RFC 5322 compliant email messages
  • Supports both plain text and HTML emails

Configuration Files

.smtp-config.json - SMTP server configuration (excluded from git):

{
  "host": "mail.example.com",
  "port": 1025,
  "secure": false,
  "user": "your-email@example.com",
  "pass": "your-password",
  "from": "noreply@example.com"
}

email-rules.json - Email notification rules (excluded from git):

{
  "rules": [
    {
      "name": "mention-notification",
      "event": "issue_comment",
      "condition": {
        "type": "mention",
        "value": "username"
      },
      "recipients": ["{{mentioned_user}}"],
      "subject": "You were mentioned in {{full_repo}}#{{issue_number}}",
      "body": "Comment by {{sender}}:\n{{comment_body}}"
    }
  ]
}

Condition Types

  • mention - Check if a user is mentioned in the payload (issue, PR, or comment body)
  • branch - Check if event is for a specific branch
  • action - Check if webhook action matches (e.g., "opened", "assigned")
  • user - Check if sender/pusher matches
  • repository - Check if repository full name matches

Recipient Variables

  • {{mentioned_user}} - User mentioned in comment/issue (extracts email from payload)
  • {{sender}} - Event sender email
  • {{assignee}} - Issue/PR assignee email
  • Direct email addresses (e.g., "admin@example.com")

Email Variable Substitution

All standard webhook variables are available in email subjects and bodies:

  • Repository: {{repo}}, {{full_repo}}, {{repo_owner}}
  • Git: {{branch}}, {{commit}}, {{commit_msg}}
  • User: {{sender}}, {{mentioned_user}}
  • Issue/PR: {{issue_number}}, {{issue_title}}, {{issue_action}}, {{pr_number}}, {{pr_action}}
  • Content: {{comment_body}}, {{issue_body}}

Integration

The email notifier is automatically integrated in src/index.js:

import emailNotifier from './emailNotifier.js';

// ... after handler setup ...
emailNotifier.register(handler);

If .smtp-config.json is missing, email notifications are disabled automatically.

How It Works

  1. Startup: EmailNotifier loads SMTP config and email rules
  2. Registration: Registers callbacks for all events defined in rules
  3. Event Trigger: When a matching webhook arrives, callback is executed
  4. Condition Check: Rule condition is evaluated against payload
  5. Variable Substitution: Variables in subject/body are replaced with actual values
  6. Recipient Resolution: Recipient variables are converted to email addresses
  7. Email Send: Email is sent via SMTP using EmailSender
  8. Error Handling: Errors are logged but don't stop webhook processing

Security

  • Configuration files are excluded from git (.gitignore)
  • Credentials stored in local files only
  • File permissions should be restricted (600)
  • No external dependencies (no npm package vulnerabilities)

TypeScript Client for Issue Automation

The client/ directory contains a TypeScript-based Claude Agent SDK client that provides AI-powered issue automation:

Location: client/

Key Files:

  • src/claude-client.ts - Main Claude Agent SDK client
  • src/config.ts - Configuration management
  • src/repository-manager.ts - Git repository operations (clone, pull, environment setup)
  • src/gogs-helper.ts - Gogs API helper functions
  • src/types.ts - TypeScript type definitions
  • src/index.ts - CLI entry point
  • dist/ - Compiled JavaScript (auto-generated by npm run build)

Usage:

cd client
npm install
npm run build

Integration: The TypeScript client is called directly from commands.json for issues and issue_comment events. No shell script wrapper is needed.

Features:

  • Integrates with gogs-mcp MCP server for Gogs API access
  • Processes issues assigned to Claude
  • Responds to issue comments automatically
  • Environment-specific configuration via .env
  • Label-aware behavior - Adjusts behavior based on issue labels (question, documentation, bug, enhancement)
  • Per-repository MCP configuration support - Different repositories can use different MCP servers
  • Dynamic tool discovery - Automatically discovers available tools from all configured MCP servers
  • Automatic repository management - Clones repositories on demand and pulls latest changes
  • Environment setup - Handles HOME, PATH, and XDG directory configuration
  • Git URL from Gogs API - Fetches SSH URL dynamically from Gogs instead of hardcoding

Label-Aware Behavior

The Claude agent automatically adjusts its behavior based on issue labels:

🔴 "question" label:

  • DO NOT implement any code changes
  • Provide information, guidance, and answers only
  • May read code to understand context, but won't modify files
  • Focus on helpful explanations and clarifications

📚 "documentation" label:

  • Focus on creating/updating documentation files
  • Acceptable changes: README.md, CLAUDE.md, other .md files, code comments
  • Avoid implementation changes unless needed for documentation examples

🐛 "bug" label:

  • Focus on identifying and fixing the root cause
  • Implement minimal changes necessary to resolve the bug
  • Add tests when appropriate to prevent regression

✨ "enhancement" label:

  • May implement code changes as requested
  • Follow existing code patterns and architecture
  • Consider backward compatibility

Labels are automatically extracted from webhook payloads and passed to the client as the {{issue_labels}} variable.

See client/README.md for detailed documentation.

MCP Configuration System

The client supports flexible MCP server configuration with three priority levels:

  1. Repository-specific config: ~/.config/agent-manager/mcp/{owner}/{repo}.json
  2. Global default config: ~/.config/agent-manager/mcp/default.json
  3. Hardcoded fallback: Built-in gogs-mcp configuration (automatic)

Key Features:

  • Multiple MCP servers per repository
  • Environment variable substitution using ${VAR_NAME} syntax
  • Secure storage with restricted file permissions (600)
  • Automatic tool discovery - Tools from custom MCP servers are automatically available to Claude
  • No need to manually configure allowed tools

Configuration Structure:

{
  "mcpServers": {
    "gogs": {
      "type": "stdio",
      "command": "node",
      "args": ["/data/gogs-mcp/dist/index.js"],
      "env": {}
    },
    "custom-mcp": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/custom-mcp/dist/index.js"],
      "env": {
        "API_KEY": "${MY_API_KEY}"
      }
    }
  }
}

Security: Configuration files are stored outside repositories in ~/.config/agent-manager/mcp/ with restricted permissions to protect secrets like API keys and JWT tokens.

See examples/MCP-CONFIG.md for detailed configuration guide and examples.

Dynamic Tool Discovery

The client automatically discovers available tools from all configured MCP servers at runtime:

How It Works:

  1. When the client starts, it loads the MCP configuration for the repository
  2. The ToolDiscovery class connects to each configured MCP server
  3. It queries each server using the MCP tools/list method
  4. Tool names are formatted as mcp__{server-name}__{tool-name}
  5. Built-in Claude Code tools (Read, Write, Edit, Bash, etc.) are added automatically
  6. The complete list is passed to the Claude Agent SDK as allowedTools

Benefits:

  • No manual configuration - Add a custom MCP server and its tools are immediately available
  • Repository-specific tools - Different repos can have different tool sets based on their MCP config
  • Always up-to-date - Tool list reflects the actual capabilities of configured servers

Built-in Tools (always available):

  • Read, Write, Edit - File operations
  • Bash, Grep, Glob - Shell operations
  • TodoWrite, Task - Task management
  • WebFetch, WebSearch - Web access
  • NotebookEdit, BashOutput, KillShell - Advanced operations
  • Skill, SlashCommand - Extension points

Example: If you configure a custom MCP server named "github" with tools "create_pr" and "list_repos", they will automatically be available as mcp__github__create_pr and mcp__github__list_repos.

Environment Variable Configuration

The client supports a two-tier environment variable configuration system to eliminate the need for duplicating .env files in every cloned repository:

Configuration Priority:

  1. Global configuration: ~/.config/agent-manager/.env (shared across all repositories)
  2. Repository-specific configuration: .env in repository root (overrides global)

How It Works:

  1. When the client starts, it first loads Config.loadGlobal() to read ~/.config/agent-manager/.env
  2. Then it loads Config.load(repoPath) to read the repository-specific .env (if it exists)
  3. Repository-specific values override global values
  4. If a repository doesn't have a .env file, it uses only global values

Required Environment Variables:

  • GOGS_ACCESS_TOKEN or GOGS_TOKEN - Gogs API authentication token
  • GOGS_BASE_URL - Gogs server URL (e.g., https://git.smartbotics.ai)
  • GOGS_MCP_PATH - Path to gogs-mcp server (defaults to /data/gogs-mcp/dist/index.js)

Setup Global Configuration:

mkdir -p ~/.config/agent-manager
cp examples/global-env.example ~/.config/agent-manager/.env
chmod 600 ~/.config/agent-manager/.env
# Edit the file and add your actual values

Benefits:

  • No duplication - Set GOGS_ACCESS_TOKEN once in global config instead of in every repository
  • Flexibility - Repositories can override global values when needed
  • Backward compatible - Existing repository .env files continue to work
  • Secure - Credentials stored in ~/.config/agent-manager/ with restricted permissions

See examples/global-env.example for a complete example configuration file.

Code Modification Guidelines

Main Server (src/):

  • Maintain zero-dependency philosophy (use only Node.js built-ins)
  • Follow singleton pattern for utilities (Config, Logger, CommandExecutor)
  • Use async/await for all async operations
  • Add error handling with try-catch and logger.error()
  • Update .env.example when adding new configuration options
  • Update README.md when adding new features
  • Follow existing naming conventions: camelCase for variables/functions, PascalCase for classes
  • Export singletons with export default new ClassName()
  • Keep modules focused on single responsibility

Testing

No formal test suite currently. Test manually using:

  1. Start server with npm run dev
  2. Use curl to send webhook payloads
  3. Check console logs for execution results
  4. Verify commands execute with expected variable substitution You always have to push the changes into the git reposiroty. Before pushing changes, you have to test the project with building and running it. Take care when running the project to use an unused port if the project already running. Never keep running instance from the project

Issue handling

  • always update the issue which you works on
  • always add label to the issue if no label added
  • always write comment with the current status of the work
  • when you create commit message, mention the issue if exists
  • close the issue only when:
    • the user explicitly requests it, OR
    • all work is completed and no further user interaction is needed
  • never close an issue if you (Claude) need to ask the user for more information or if work is incomplete