Skip to content

Actors

MatrixActor is the unit of execution. Every domain capability — chat, inference, configuration, conversation persistence, gateway HTTP — is an actor or a tree of actors mounted on a MatrixRuntime. This section is the reference for writing them.

The base class lives at projects/matrix-3/packages/core/src/core/MatrixActor.ts (~3800 lines). It merges the pre-rebuild MatrixComponent and MatrixComposite into one — every actor can have children, system ops are auto-subscribed, domain ops opt in via static accepts, state is observable via setState(), and cross-root invocation goes through invoke().

Pages in this section

PageWhat you'll learn
Define an actorSubclass MatrixActor, declare accepts/emits, write on{Op} handlers.
Actor lifecycleinitialize(), dispose(), the $join/$join_ack handshake, supervision restart.
Actor opsOp naming, dispatch from $inbox, system vs domain ops, $introspect.
Actor sessionsSession-scoped state, $activity frames, $prompt and the activity stream.
Actor statesetState(), the state getter, $stateChanged, persistence scopes.
Actor testingStub transports, MockRuntime, asserting on emits and inbox traffic.

Quick start

The minimum viable actor:

ts
import { MatrixActor, MatrixRuntime, InMemoryTransport, InMemoryBroker } from '@open-matrix/core';

class Greeter extends MatrixActor {
  static accepts = {
    'greeter.hello': {
      description: 'Reply with a greeting addressed to the supplied name.',
      schema: { name: { type: 'string', description: 'Person to greet' } },
      returns: { greeting: { type: 'string', description: 'A polite hello' } },
    },
  };

  static emits = {
    'greeter.greeted': {
      description: 'Fired after every successful greeter.hello call',
      schema: { name: { type: 'string', description: 'Who was greeted' } },
      frequency: 'low',
    },
  };

  async onGreeterHello(payload: { name: string }) {
    this.emit('greeter.greeted', { name: payload.name });
    return { greeting: `Hello, ${payload.name}!` };
  }
}

const broker = new InMemoryBroker();
const transport = new InMemoryTransport(broker, { name: 'demo' });
const runtime = new MatrixRuntime({ transport });
await runtime.create(Greeter, 'greeter');

The handler-name convention is mechanical: greeter.helloonGreeterHello. The mapping happens in engine/utils/NameUtils.toHandlerCase and is exercised across every package in the tree.

Reading order

If you have not written a MatrixActor before, read Define an actor and Actor ops first. The other pages are reference material you reach for when you need them.

Source: projects/matrix-3/packages/core/src/core/MatrixActor.ts:168-300 (class declaration and static surface).