Boatman Ecosystem documentation is live!
BoatmanMode CLI
Event System

Event System

BoatmanMode emits structured JSON events to stdout during workflow execution, enabling real-time integration with external tools like the Boatman Desktop application.

Overview

Events are emitted as newline-delimited JSON (NDJSON) to stdout, allowing real-time tracking of the multi-agent orchestration workflow. Each event represents a significant state change.


Event Format

All events follow this JSON structure:

{
  "type": "string",           // Event type (required)
  "id": "string",             // Unique identifier (optional)
  "name": "string",           // Human-readable name (optional)
  "description": "string",    // Detailed description (optional)
  "status": "string",         // "success" or "failed" (optional)
  "message": "string",        // Progress message (optional)
  "data": {}                  // Additional metadata (optional)
}

Event Types

agent_started

Emitted when an agent begins execution.

{
  "type": "agent_started",
  "id": "planning-ENG-123",
  "name": "Planning & Analysis",
  "description": "Analyzing codebase and creating implementation plan"
}

agent_completed

Emitted when an agent finishes execution.

{
  "type": "agent_completed",
  "id": "planning-ENG-123",
  "name": "Planning & Analysis",
  "status": "success"
}

progress

General progress message not tied to a specific agent.

{
  "type": "progress",
  "message": "Review & refactor iteration 2 of 3"
}

task_created (Reserved)

Not currently emitted by BoatmanMode, reserved for future use by the event system for external integrations.

task_updated (Reserved)

Not currently emitted by BoatmanMode, reserved for future use.


Agent ID Format

Agent IDs follow a consistent pattern for tracking:

StepAgent ID PatternExample
Prepareprepare-{taskID}prepare-ENG-123
Worktreeworktree-{taskID}worktree-ENG-123
Planningplanning-{taskID}planning-ENG-123
Preflightpreflight-{taskID}preflight-ENG-123
Executeexecute-{taskID}execute-ENG-123
Testtest-{taskID}test-ENG-123
Reviewreview-{iteration}-{taskID}review-1-ENG-123
Refactorrefactor-{iteration}-{taskID}refactor-2-ENG-123
Commitcommit-{taskID}commit-ENG-123
PRpr-{taskID}pr-ENG-123

Example Event Flow

A typical event sequence for a successful workflow:

{"type":"agent_started","id":"prepare-ENG-123","name":"Preparing Task"}
{"type":"agent_completed","id":"prepare-ENG-123","name":"Preparing Task","status":"success"}
{"type":"agent_started","id":"worktree-ENG-123","name":"Setup Worktree"}
{"type":"agent_completed","id":"worktree-ENG-123","name":"Setup Worktree","status":"success"}
{"type":"agent_started","id":"planning-ENG-123","name":"Planning & Analysis"}
{"type":"agent_completed","id":"planning-ENG-123","name":"Planning & Analysis","status":"success"}
{"type":"agent_started","id":"preflight-ENG-123","name":"Pre-flight Validation"}
{"type":"agent_completed","id":"preflight-ENG-123","name":"Pre-flight Validation","status":"success"}
{"type":"agent_started","id":"execute-ENG-123","name":"Execution"}
{"type":"agent_completed","id":"execute-ENG-123","name":"Execution","status":"success"}
{"type":"agent_started","id":"test-ENG-123","name":"Running Tests"}
{"type":"agent_started","id":"review-1-ENG-123","name":"Code Review #1"}
{"type":"agent_completed","id":"test-ENG-123","name":"Running Tests","status":"success"}
{"type":"agent_completed","id":"review-1-ENG-123","name":"Code Review #1","status":"failed"}
{"type":"progress","message":"Review & refactor iteration 1 of 3"}
{"type":"agent_started","id":"refactor-1-ENG-123","name":"Refactoring #1"}
{"type":"agent_completed","id":"refactor-1-ENG-123","name":"Refactoring #1","status":"success"}
{"type":"agent_started","id":"commit-ENG-123","name":"Commit & Push"}
{"type":"agent_completed","id":"commit-ENG-123","name":"Commit & Push","status":"success"}
{"type":"agent_started","id":"pr-ENG-123","name":"Create PR"}
{"type":"agent_completed","id":"pr-ENG-123","name":"Create PR","status":"success"}

Consuming Events

Command Line

boatman work ENG-123 | grep '^{' | jq

Go Integration

package main
 
import (
    "bufio"
    "encoding/json"
    "log"
    "os/exec"
)
 
type Event struct {
    Type        string `json:"type"`
    ID          string `json:"id,omitempty"`
    Name        string `json:"name,omitempty"`
    Description string `json:"description,omitempty"`
    Status      string `json:"status,omitempty"`
    Message     string `json:"message,omitempty"`
}
 
func main() {
    cmd := exec.Command("boatman", "work", "ENG-123")
    stdout, _ := cmd.StdoutPipe()
    cmd.Start()
 
    scanner := bufio.NewScanner(stdout)
    for scanner.Scan() {
        line := scanner.Text()
 
        var event Event
        if err := json.Unmarshal([]byte(line), &event); err == nil {
            log.Printf("Event: %s - %s [%s]", event.Type, event.Name, event.Status)
        }
    }
 
    cmd.Wait()
}

Implementation Details

Events are emitted using the internal/events package:

import "github.com/philjestin/boatmanmode/internal/events"
 
// Start an agent
events.AgentStarted("execute-ENG-123", "Execution", "Implementing code changes")
 
// Complete an agent
events.AgentCompleted("execute-ENG-123", "Execution", "success")
 
// Progress update
events.Progress("Running tests...")

All events are flushed to stdout immediately for real-time updates.


Design Decisions

DecisionChoiceRationale
Output channelstdoutSimple, works with standard pipes
FormatNDJSONStreaming-friendly, standard format
Agent IDs{step}-{taskID}Unique, traceable, human-readable
EmissionAlways onConsistent behavior, easily filtered

Performance Impact

  • Synchronous emission (no goroutines needed)
  • JSON marshaling < 1ms per event
  • ~20-30 events per workflow execution
  • Negligible overhead