Skip to main content

How Modules Communicate

The corpus callosum connects all brain regions. Modules never import each other — they communicate exclusively through typed events on the corpus. This keeps the system modular, inspectable, and easy to extend.

Architecture

Built on mitt — a lightweight typed event emitter (200 bytes). Every module receives the corpus singleton in its constructor:
class MyModule {
  constructor(private corpus: Corpus) {
    this.corpus.on('input.received', this.handleInput.bind(this))
  }
}
The corpus is initialized first during startup and passed to all other modules. No module ever imports another module directly.

Usage

// Emit an event
corpus.emit('tool.called', {
  name: 'shell_exec',
  args: { command: 'ls -la' },
  taskId: 'TASK-42'
})

// Listen for an event
corpus.on('tool.completed', (payload) => {
  console.log(`${payload.name} finished in ${payload.duration}ms`)
})

// Listen for all events (wildcard)
corpus.on('*', (type, payload) => {
  log(`[${type}] ${JSON.stringify(payload)}`)
})
The wildcard handler is what produces the daily log files. Every event that flows through corpus is captured and flushed to disk.

Event Categories

Over 30 typed events are defined in the CorpusEvent enum. They group into these categories:

Input Events

EventEmitted ByPayload
input.receivedMain process{ content, channelId, conversationId }
input.classifiedPrefrontal{ intent, confidence }
input.routedPrefrontal{ provider, model }

Context Events

EventEmitted ByPayload
context.builtPrefrontal{ tokens, sections }
context.trimmedRAS{ before, after, dropped }

LLM Events

EventEmitted ByPayload
llm.responseThalamus{ provider, model, tokens }
llm.errorThalamus{ provider, error, willRetry }
llm.tokenThalamus{ delta }

Tool Events

EventEmitted ByPayload
tool.calledMotor{ name, args, taskId }
tool.completedMotor{ name, output, duration, taskId }
tool.failedMotor{ name, error, attempt, taskId }
tool.parsedWernicke{ calls }

Safety Events

EventEmitted ByPayload
safety.allowedAmygdala{ toolName, classification }
safety.blockedAmygdala{ toolName, reason }
safety.approvedAmygdala{ toolName, channelId }
safety.deniedAmygdala{ toolName, channelId }

Task Events

EventEmitted ByPayload
task.createdMotor{ taskId, toolName }
task.startedMotor{ taskId, attempt }
task.stepCompletedMotor{ taskId, step, duration }
task.completedMotor{ taskId, success, totalDuration }
task.failedMotor{ taskId, error, attempts }
task.stoppedMotor{ taskId, reason }

Memory Events

EventEmitted ByPayload
memory.savedHippocampus{ type, path }
memory.consolidatedBrainstem{ week, episodeCount }
memory.promotedBrainstem{ topic, path }

Health Events

EventEmitted ByPayload
health.okHypothalamus{ metrics }
health.warningHypothalamus{ resource, value, threshold }
health.criticalHypothalamus{ resource, value, threshold }
resource.low.contextHypothalamus{ used, max }
resource.low.memoryHypothalamus{ used, max }
resource.low.diskHypothalamus{ used, max }

Learning Events

EventEmitted ByPayload
outcome.recordedBasal Ganglia{ type, toolName, args }
preference.learnedBasal Ganglia{ pattern, preference }

System Events

EventEmitted ByPayload
scheduler.tickBrainstem{ jobName, schedule }
watcher.changedBrainstem{ path, changeType }
cortex.reindexedCortex{ path, action }

Event Logging

Every event is logged to daily markdown files at brain/corpus/YYYY-MM-DD.log.md. A 2-second buffer flush batches writes for performance:
## 2026-05-16

09:15:02 | input.received | {"content":"What PRs need review?","channelId":"desktop"}
09:15:02 | context.built | {"tokens":7842,"sections":12}
09:15:03 | input.routed | {"provider":"anthropic","model":"claude-sonnet-4-20250514"}
09:15:04 | tool.called | {"name":"github_prs","args":{"state":"open"},"taskId":"TASK-89"}
09:15:05 | safety.allowed | {"toolName":"github_prs","classification":"safe"}
09:15:06 | tool.completed | {"name":"github_prs","duration":1204,"taskId":"TASK-89"}
09:15:07 | llm.response | {"provider":"anthropic","tokens":342}
09:15:07 | memory.saved | {"type":"episode","path":"episodes/2026-05-16.md"}
Old logs are automatically cleaned after 7 days to prevent unbounded disk growth.
Read the corpus logs when debugging unexpected behavior. They show you the exact sequence of events that occurred — which module did what and when.

Subscribing and Unsubscribing

// Subscribe — returns an unsubscribe function
const off = corpus.on('task.completed', (payload) => {
  console.log('Task done:', payload.taskId)
})

// Unsubscribe when done
off()
The turn runner uses this pattern to subscribe to events for the duration of a turn, then unsubscribes in the finally block.

Adding New Events

To add a new event type:
  1. Add it to the CorpusEvent enum in src/main/runtime/corpus/corpus.ts
  2. Define its payload type in the CorpusEvents interface
  3. Emit it from the relevant module
  4. Subscribe to it from any module that needs to react
The event is automatically logged by the wildcard handler — no extra wiring needed.

Design Benefits

The event bus architecture provides:
  • Module independence: modules can be developed, tested, and upgraded independently
  • Full observability: every interaction is logged and timestamped
  • Easy extension: new modules subscribe to existing events without modifying producers
  • Testability: mock the corpus in tests and verify events are emitted correctly

Practical Example: Hypothalamus Health Monitoring

The hypothalamus demonstrates how a module uses corpus to monitor the entire system without importing any other module:
class Hypothalamus {
  private failureCount = 0
  private lastContextTokens = 0

  constructor(private corpus: Corpus) {
    // Listen for problems from other modules
    corpus.on('llm.error', () => {
      this.failureCount++
      if (this.failureCount > 5) {
        corpus.emit('health.warning', {
          resource: 'llm',
          value: this.failureCount,
          threshold: 5
        })
      }
    })

    corpus.on('context.built', (payload) => {
      this.lastContextTokens = payload.tokens
      if (payload.tokens > 180_000) {
        corpus.emit('resource.low.context', {
          used: payload.tokens,
          max: 200_000
        })
      }
    })

    corpus.on('tool.failed', (payload) => {
      if (payload.attempt >= 3) {
        corpus.emit('health.warning', {
          resource: 'tool',
          value: payload.name,
          threshold: 'max retries exceeded'
        })
      }
    })

    // Reset failure count on success
    corpus.on('llm.response', () => {
      this.failureCount = 0
    })
  }
}
The hypothalamus never touches the thalamus, motor, or prefrontal modules directly. It observes their behavior through events and raises its own events when thresholds are crossed. Any module can then react to health warnings — the UI can show an indicator, the brainstem can trigger a diagnostic job, and the prefrontal can include health context in the next prompt.
Event handlers should be fast and non-blocking. Heavy work triggered by an event should be deferred (setTimeout, queueMicrotask) to avoid slowing down the event producer.