Skip to content

Event Bus and Webhooks

William Smith edited this page Jul 13, 2026 · 1 revision

Event Bus and Webhooks

Relevant source files

The following files were used as context for generating this wiki page:

The internal/events package provides an asynchronous, in-process event bus designed for observability and cluster-wide coordination internal/events/events.go:1-3. It serves as the central nervous system for AXIS, emitting lifecycle events for task placement, resource reservations, and daemon state changes. These events can be consumed by local listeners, propagated across the cluster via Cortex, or dispatched to external systems through webhooks internal/events/events.go:22-27, internal/events/webhooks.go:39-40.

Event Lifecycle and Constants

AXIS defines a set of standard event names that represent the state transitions of various subsystems.

Category Constant String Value Description
Task EventTaskPlacementRequested task.placement.requested Emitted before a placement decision is made internal/events/events.go:35-37.
EventTaskExecutionPre task.execution.pre Emitted immediately before a task starts internal/events/events.go:39-40.
EventTaskExecutionReserved task.execution.reserved Emitted after RAM/VRAM is committed in the ledger internal/events/events.go:42-43.
EventTaskExecutionPost task.execution.post Emitted after task completion (success/failure) internal/events/events.go:48-49.
Reservation EventReservationRequested reservation.requested Emitted when an advisory lease is requested internal/events/events.go:57-58.
EventReservationGranted reservation.granted Emitted when a reservation is recorded internal/events/events.go:60-61.
Daemon EventDaemonRefreshPost daemon.refresh.post Emitted after a snapshot refresh completes internal/events/events.go:72-73.

Sources: internal/events/events.go:30-77

Implementation and Data Flow

The event system uses a multi-tiered approach for persistence and propagation:

  1. In-Process Listeners: Synchronous registration but asynchronous execution via goroutines internal/events/events.go:162-169.
  2. Cortex Propagation: If a cortex.Client is registered via SetCortexClient, events are wrapped in a PublishEnvelope and broadcast cluster-wide internal/events/events.go:22-27, internal/events/events.go:94-98.
  3. JSONL Logging: Events are persisted to ~/.axis/events.jsonl using a monotonic sequence number allocated via a file-lock (flock) mechanism to ensure consistency across multiple processes internal/events/logger.go:37-57, internal/events/logger.go:92-106.

Event Propagation Architecture

The following diagram illustrates how an event emitted by a subsystem (e.g., the Execution Engine) moves through the system.

graph TD
    subgraph "Event Source"
        A["Subsystem (e.g. RunGuarded)"] -- "Emit()" --> B["internal/events.EmitToBuffer"]
    end

    subgraph "In-Process Dispatch"
        B --> C["listenerMu (sync.Mutex)"]
        C --> D["notifyListeners()"]
        D --> E["Goroutine per Listener"]
    end

    subgraph "External & Cluster Propagation"
        B --> F["cortexClient.PublishEvent"]
        B --> G["dispatchWebhooks()"]
    end

    subgraph "Persistence"
        B --> H["allocateSequence() (flock)"]
        H --> I["appendEventToFile()"]
        I --> J["~/.axis/events.jsonl"]
    end
    
    style J stroke-dasharray: 5 5
Loading

Sources: internal/events/events.go:124-170, internal/events/logger.go:37-57, internal/events/webhooks.go:40-44

Webhook Dispatcher

The webhook system allows AXIS to notify external HTTP endpoints of lifecycle events.

Sources: internal/events/webhooks.go:1-137, internal/events/webhooks_test.go:66-89

MCP Event Integration

The internal/events package maintains an interests registry specifically for Model Context Protocol (MCP) clients internal/events/events.go:203-211. This allows external AI agents to subscribe to specific event types.

Code Entity Mapping: MCP to Event Bus

This diagram maps the MCP Tool names used by AI agents to the internal functions in the events package.

graph LR
    subgraph "MCP Client (examples/mcp-event-client)"
        M1["CallTool('list_lifecycle_events')"]
        M2["CallTool('register_event_interest')"]
        M3["CallTool('get_recent_events')"]
    end

    subgraph "internal/events Package"
        E1["Event Name Constants"]
        E2["RegisterInterest()"]
        E3["GetRecentEvents()"]
        E4["getRecentEventsFromFile()"]
    end

    M1 --> E1
    M2 --> E2
    M3 --> E3
    E3 --> E4
Loading

Sources: internal/events/events.go:211-227, internal/events/logger.go:170-219, examples/mcp-event-client/main.go:37-62

Logging and Rotation

AXIS maintains a rolling window of events on disk to prevent unbounded storage growth.

  • Rotation: When events.jsonl exceeds 10MB, it is rotated. AXIS keeps up to 9 historical log files (events.1.jsonl through events.9.jsonl) internal/events/logger.go:121-125, internal/events/logger.go:153-166.
  • Sequence Consistency: The allocateSequence function uses syscall.Flock on event-sequence.lock to ensure that even if multiple AXIS processes (CLI and Daemon) emit events simultaneously, the sequence numbers remain strictly monotonic and unique internal/events/logger.go:37-57.

Sources: internal/events/logger.go:37-89, internal/events/logger.go:121-167


Clone this wiki locally