← Documentation Home

Agent Mesh - Development Guide

Local Development Setup and Contribution Guidelines

Overview

This guide covers setting up a local development environment for Agent Mesh, running tests, debugging, and contributing code to the project.

Prerequisites

Required Software

Optional Software

System Requirements

Initial Setup

1. Clone Repository

# Clone the main repository
git clone https://gitlab.bluefly.io/llm/npm/agent-buildkit.git
cd agent-buildkit

# Create development branch
git checkout -b feature/your-feature-name

2. Install Dependencies

# Install all dependencies
npm install

# Install development dependencies
npm install --save-dev @types/node @types/jest

# Verify installation
npm list --depth=0

3. Configure Tailscale

# Install Tailscale (if not already installed)
curl -fsSL https://tailscale.com/install.sh | sh

# Authenticate
sudo tailscale up

# Verify connection
tailscale status

4. Environment Setup

Create .env.development file:

# Copy example environment
cp .env.example .env.development

# Edit with your settings
nano .env.development

Required Environment Variables:

# Mesh Configuration
MESH_JWT_SECRET=dev-secret-change-me
TAILSCALE_ENABLED=true
NODE_ENV=development

# Logging
LOG_LEVEL=debug

# Optional: Redis
REDIS_URL=redis://localhost:6379

# Optional: Custom ports
COORDINATOR_PORT=3000
AGENT_PORT=3001

5. Build Project

# Build TypeScript
npm run build

# Build CLI
npm run build:cli

# Verify build
ls -la dist/

Development Workflow

Running Locally

Start Coordinator

# Terminal 1: Start coordinator in development mode
npm run dev

# Or with watch mode
npm run dev -- --watch

# Or use CLI directly
npm run cli -- agent:mesh status

Start Test Agents

# Terminal 2: Deploy first worker agent
npm run cli -- agent:mesh deploy \
  --agent-id dev-worker-1 \
  --agent-name "Dev Worker 1" \
  --agent-type worker \
  --namespace development \
  --capabilities "task-execution,data-processing" \
  --port 3001

# Terminal 3: Deploy second worker agent
npm run cli -- agent:mesh deploy \
  --agent-id dev-worker-2 \
  --agent-name "Dev Worker 2" \
  --agent-type worker \
  --namespace development \
  --capabilities "task-execution" \
  --port 3002

Test Task Execution

# Terminal 4: Submit test task
npm run cli -- agent:mesh execute \
  --task-id dev-task-001 \
  --task-type test \
  --payload '{"message": "Hello from development"}'

# Check status
npm run cli -- agent:mesh status --namespace development

# View workload
npm run cli -- agent:mesh workload

Docker Development

Using Docker Compose

# Start full stack
docker-compose -f docker-compose.dev.yml up -d

# View logs
docker-compose -f docker-compose.dev.yml logs -f

# Run commands in container
docker-compose -f docker-compose.dev.yml exec coordinator bash

docker-compose.dev.yml:

version: '3.8'

services:
  coordinator:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - MESH_JWT_SECRET=dev-secret
      - REDIS_URL=redis://redis:6379
    ports:
      - "3000:3000"
      - "9229:9229"  # Debug port
    command: npm run dev

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  worker-1:
    build:
      context: .
      dockerfile: Dockerfile.dev
    environment:
      - AGENT_ID=dev-worker-1
      - AGENT_TYPE=worker
    depends_on:
      - coordinator

Hot Reloading

Using tsx for instant TypeScript reloading:

# Watch and rebuild on changes
npm run dev

# Watch specific file
npx tsx watch src/services/agent-mesh/mesh-coordinator.service.ts

Testing

Unit Tests

# Run all unit tests
npm test

# Run specific test file
npm test -- mesh-coordinator.service.test.ts

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

Example Unit Test:

// tests/services/mesh-coordinator.service.test.ts
import { MeshCoordinatorService } from '../../src/services/agent-mesh/mesh-coordinator.service';
import { createMeshDiscoveryService } from '../../src/services/agent-mesh/mesh-discovery.service';

describe('MeshCoordinatorService', () => {
  let coordinator: MeshCoordinatorService;
  let discovery: any;

  beforeEach(() => {
    discovery = createMeshDiscoveryService();
    coordinator = new MeshCoordinatorService(discovery);
  });

  it('should submit task successfully', async () => {
    const task = {
      taskId: 'test-001',
      taskType: 'test',
      payload: { data: 'test' },
      requiredCapabilities: [],
      priority: 'medium' as const,
      timeout: 30000,
      retries: 3
    };

    const result = await coordinator.submitTask(task);
    expect(result.success).toBe(true);
    expect(result.taskId).toBe('test-001');
  });

  it('should handle no available agents', async () => {
    const task = {
      taskId: 'test-002',
      taskType: 'test',
      payload: {},
      requiredCapabilities: ['non-existent'],
      priority: 'medium' as const,
      timeout: 30000,
      retries: 3
    };

    const result = await coordinator.submitTask(task);
    expect(result.success).toBe(false);
  });
});

Integration Tests

# Run integration tests
npm run test:integration

# Run specific integration test
npm run test:integration -- mesh-integration.test.ts

# Integration tests with verbose output
TEST_VERBOSE=1 npm run test:integration

Example Integration Test:

// tests/integration/mesh-integration.test.ts
import { createMeshDiscoveryService } from '../../src/services/agent-mesh/mesh-discovery.service';
import { createMeshCoordinatorService } from '../../src/services/agent-mesh/mesh-coordinator.service';

describe('Agent Mesh Integration', () => {
  it('should complete end-to-end task flow', async () => {
    // 1. Setup services
    const discovery = createMeshDiscoveryService();
    const coordinator = createMeshCoordinatorService(discovery);

    // 2. Register agent
    const registration = await discovery.registerAgent({
      agentId: 'integration-worker',
      agentName: 'Integration Worker',
      agentType: 'worker',
      namespace: 'test',
      capabilities: ['integration-test'],
      version: '1.0.0',
      port: 3003,
      healthCheckPath: '/health',
      heartbeatIntervalMs: 30000
    });

    expect(registration.success).toBe(true);

    // 3. Submit task
    const task = {
      taskId: 'integration-001',
      taskType: 'integration-test',
      payload: { test: true },
      requiredCapabilities: ['integration-test'],
      priority: 'high' as const,
      timeout: 30000,
      retries: 1
    };

    const result = await coordinator.submitTask(task);
    expect(result.success).toBe(true);

    // 4. Wait for completion
    await new Promise(resolve => setTimeout(resolve, 2000));

    const status = await coordinator.getTaskStatus(task.taskId);
    expect(status?.status).toBe('completed');
  }, 10000);
});

Manual Testing

Test Discovery

# Register test agent
npm run cli -- agent:mesh deploy \
  --agent-id test-agent-1 \
  --agent-name "Test Agent" \
  --agent-type worker \
  --namespace test

# Discover agents
npm run cli -- agent:mesh discover --namespace test

# Find specific agent
npm run cli -- agent:mesh discover --agent-id test-agent-1

Test Task Routing

# Test round-robin
for i in {1..5}; do
  npm run cli -- agent:mesh execute \
    --task-id "test-$i" \
    --task-type test \
    --payload "{\"index\": $i}"
done

# Check workload distribution
npm run cli -- agent:mesh workload

Test Fault Tolerance

# Submit task
npm run cli -- agent:mesh execute \
  --task-id fault-test \
  --task-type test \
  --retries 5 &

# Kill agent mid-execution
# Task should automatically retry on another agent

Debugging

VS Code Debug Configuration

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Coordinator",
      "runtimeExecutable": "node",
      "runtimeArgs": [
        "--loader", "tsx",
        "--inspect"
      ],
      "program": "${workspaceFolder}/src/services/agent-mesh/mesh-coordinator.service.ts",
      "console": "integratedTerminal",
      "skipFiles": ["<node_internals>/**"],
      "env": {
        "NODE_ENV": "development",
        "LOG_LEVEL": "debug"
      }
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Debug CLI",
      "runtimeExecutable": "node",
      "runtimeArgs": ["--loader", "tsx"],
      "program": "${workspaceFolder}/src/cli/index.ts",
      "args": ["agent:mesh", "status"],
      "console": "integratedTerminal",
      "skipFiles": ["<node_internals>/**"]
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Tests",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["--runInBand", "--no-cache"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

Debug Logging

Enable debug logging:

# Set log level
export LOG_LEVEL=debug

# Run with debug output
DEBUG=agent-mesh:* npm run dev

# View specific service logs
DEBUG=agent-mesh:coordinator npm run dev

Inspect Network Traffic

# Monitor Tailscale connections
tailscale status --json | jq

# Watch HTTP traffic (requires Charles Proxy or similar)
# Set HTTP_PROXY environment variable
export HTTP_PROXY=http://localhost:8888

Memory Profiling

# Profile memory usage
node --inspect --expose-gc dist/cli/index.js agent:mesh status

# Connect Chrome DevTools
# Navigate to chrome://inspect
# Click "inspect" under target
# Go to Memory tab and take heap snapshot

Code Style and Standards

TypeScript Guidelines

Good Example:

interface AgentConfig {
  agentId: string;
  agentType: AgentType;
  capabilities: string[];
}

async function registerAgent(config: AgentConfig): Promise<RegistrationResult> {
  const validated = AgentConfigSchema.parse(config);
  // Implementation
  return { success: true, agentId: validated.agentId };
}

Code Formatting

# Format all files
npm run format

# Check formatting
npm run format:check

# Auto-fix on save (VS Code)
# Add to settings.json:
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

Linting

# Run ESLint
npm run lint

# Auto-fix issues
npm run lint:fix

# Check architecture rules
npm run lint:architecture

.eslintrc.json:

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/no-explicit-any": "warn",
    "@typescript-eslint/explicit-function-return-type": "error",
    "no-console": "warn"
  }
}

Project Structure

agent-buildkit/
├── src/
│   ├── services/
│   │   └── agent-mesh/
│   │       ├── mesh-coordinator.service.ts
│   │       ├── mesh-discovery.service.ts
│   │       ├── mesh-transport.service.ts
│   │       └── mesh-auth.service.ts
│   ├── cli/
│   │   └── commands/
│   │       └── agent-mesh.command.ts
│   ├── types/
│   │   └── agent-mesh.types.ts
│   └── utils/
│       └── logging/
├── tests/
│   ├── unit/
│   │   └── services/
│   │       └── agent-mesh/
│   ├── integration/
│   │   └── mesh-integration.test.ts
│   └── fixtures/
├── docs/
│   └── packages/
│       └── agent-mesh.md
├── config/
│   ├── development.json
│   ├── production.json
│   └── test.json
├── package.json
├── tsconfig.json
└── jest.config.js

Adding New Features

1. Create Feature Branch

git checkout -b feature/your-feature-name

2. Implement Feature

Follow TDD approach:

  1. Write failing test
  2. Implement minimal code to pass
  3. Refactor
  4. Repeat

3. Add Documentation

Update relevant documentation: - Update wiki pages - Add JSDoc comments - Update README if needed

4. Test Thoroughly

# Run all tests
npm run test:all

# Check coverage
npm run test:coverage

# Verify types
npm run typecheck

5. Commit Changes

Follow commit message convention:

# Format: <type>(<scope>): <subject>

git add .
git commit -m "feat(mesh): add custom load balancing strategy"
git commit -m "fix(coordinator): handle empty agent list"
git commit -m "docs(mesh): update architecture diagrams"

Commit Types: - feat: New feature - fix: Bug fix - docs: Documentation only - style: Formatting changes - refactor: Code restructuring - test: Adding tests - chore: Maintenance tasks

6. Push and Create MR

# Push to remote
git push origin feature/your-feature-name

# Create merge request on GitLab
# Fill in description, link related issues

Common Development Tasks

Adding New Agent Type

  1. Update type definition:
// src/types/agent-mesh.types.ts
export type AgentType =
  | 'orchestrator'
  | 'worker'
  | 'monitor'
  | 'integrator'
  | 'governor'
  | 'critic'
  | 'your-new-type';  // Add here
  1. Add ACL policy:
// src/services/agent-mesh/mesh-auth.service.ts
this.aclPolicies.set('your-new-type', {
  agentType: 'your-new-type',
  allowedActions: ['read', 'write'],
  allowedResources: ['your-resources'],
});
  1. Add tests:
// tests/unit/services/mesh-auth.service.test.ts
it('should enforce ACL for new agent type', async () => {
  // Test implementation
});

Adding New Load Balancing Strategy

  1. Add to strategy enum:
const LoadBalancingStrategySchema = z.enum([
  'round-robin',
  'least-loaded',
  'capability-match',
  'random',
  'your-strategy'  // Add here
]);
  1. Implement strategy:
// src/services/agent-mesh/mesh-coordinator.service.ts
private selectAgentByStrategy(agents: MeshAgent[]): MeshAgent {
  switch (this.loadBalancingStrategy) {
    // ... existing cases
    case 'your-strategy':
      return this.yourStrategyLogic(agents);
  }
}
  1. Add tests:
it('should route using your-strategy', async () => {
  coordinator.setLoadBalancingStrategy('your-strategy');
  // Test implementation
});

Adding New CLI Command

  1. Create command:
// src/cli/commands/agent-mesh.command.ts
agentMeshCommand
  .command('your-command')
  .description('Your command description')
  .option('--option <value>', 'Option description')
  .action(async (options) => {
    // Implementation
  });
  1. Add tests:
// tests/unit/cli/agent-mesh.command.test.ts
it('should execute your-command', async () => {
  // Test implementation
});

Performance Testing

Load Testing

# Install k6
brew install k6  # macOS
# or download from https://k6.io/

# Run load test
k6 run tests/load/mesh-load-test.js

Example Load Test:

// tests/load/mesh-load-test.js
import http from 'k6/http';
import { check } from 'k6';

export let options = {
  stages: [
    { duration: '2m', target: 100 },  // Ramp up to 100 users
    { duration: '5m', target: 100 },  // Stay at 100 users
    { duration: '2m', target: 0 },    // Ramp down
  ],
};

export default function () {
  let res = http.post('http://localhost:3000/mesh/tasks', JSON.stringify({
    taskId: `load-test-${__VU}-${__ITER}`,
    taskType: 'load-test',
    payload: { data: 'test' }
  }));

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });
}

Benchmark Tests

// tests/benchmark/coordinator-benchmark.ts
import Benchmark from 'benchmark';

const suite = new Benchmark.Suite();

suite
  .add('Task submission', async () => {
    await coordinator.submitTask(task);
  })
  .add('Agent discovery', async () => {
    await discovery.discoverAgents();
  })
  .on('cycle', (event) => {
    console.log(String(event.target));
  })
  .on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })
  .run({ async: true });

Troubleshooting Development Issues

TypeScript Errors

# Clear TypeScript cache
rm -rf node_modules/.cache

# Rebuild
npm run clean
npm run build

Tailscale Connection Issues

# Restart Tailscale
sudo tailscale down
sudo tailscale up

# Check status
tailscale status
tailscale ping <hostname>

Redis Connection Issues

# Start Redis
redis-server

# Test connection
redis-cli ping

# Clear all data
redis-cli FLUSHALL

Port Already in Use

# Find process using port
lsof -i :3000

# Kill process
kill -9 <PID>

Contributing Guidelines

Before Submitting

Merge Request Checklist

Code Review Process

  1. Automated CI/CD checks run
  2. Two approvals required
  3. No unresolved discussions
  4. All tests passing
  5. Merge to development

Resources

Documentation

External Resources

Community


Happy coding! Thank you for contributing to Agent Mesh.