Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ixo.world/llms.txt

Use this file to discover all available pages before exploring further.

getSharedState() returns a flat map of key → (state, runCtx) => value. Consumers read those values on ctx.shared.<key>.
1

Keep the value somewhere the plugin owns

Shared state is read-only by design. The owner plugin writes; consumers only read. A per-session Map is the simplest store.
import { OraclePlugin } from '@ixo/oracle-runtime';

export interface LastWeatherQuery {
  city: string;
  latitude: number;
  longitude: number;
  queriedAt: string;
}

export class WeatherPlugin extends OraclePlugin {
  private readonly lastBySession = new Map<string, LastWeatherQuery>();
  // tools write into lastBySession after a successful lookup
}
Canonical source: weather.plugin.ts.
2

Expose it via getSharedState()

Each entry is a function (state, runCtx) => unknown. The key becomes the field on ctx.shared. Keep accessors cheap — they’re called every time a consumer reads.
import type { RuntimeContext } from '@ixo/oracle-runtime';

override getSharedState(): Record<
  string,
  (state: unknown, runCtx: RuntimeContext) => unknown
> {
  return {
    lastWeatherQuery: (_state, runCtx) =>
      this.lastBySession.get(runCtx.session.id),
  };
}
See getSharedState in weather.plugin.ts.
3

Consume it from another plugin via ctx.shared

Any tool handler can read rtCtx.shared.<key>. Treat the value as possibly undefined because the producing plugin may not be loaded.
import { OraclePlugin, tool, z, type RuntimeContext } from '@ixo/oracle-runtime';

export class TripAdvisorPlugin extends OraclePlugin {
  readonly name = 'trip-advisor';
  readonly softDependsOn = ['weather'];

  override getTools() {
    return [
      tool(
        async (args, rtCtx: RuntimeContext) => {
          const lastQuery = rtCtx.shared.lastWeatherQuery;
          if (lastQuery) {
            rtCtx.logger.log(`prior lookup: ${JSON.stringify(lastQuery)}`);
          }
          // ...
          return 'done';
        },
        {
          name: 'suggest_trip',
          description: 'Suggest a trip based on recent weather.',
          schema: z.object({}),
        },
      ),
    ];
  }
}
Pair shared state with softDependsOn so the dependency is explicit and discoverable.
4

Add declaration merging for typed reads (optional)

SharedAccessors is an open interface. Extend it so consumers see the right type on ctx.shared.<key>.
declare module '@ixo/oracle-runtime' {
  interface SharedAccessors {
    lastWeatherQuery?: LastWeatherQuery;
  }
}
Without this, the key types as unknown. Skip declaration merging for ad-hoc keys.

What to know before shipping

  • The key namespace is flat. Two plugins registering the same key fail boot. Rename one.
  • Accessors run on every read — memoise expensive computations inside the producer (e.g. by session.id).
  • Shared state cannot be mutated by the consumer. To update the value, mutate via the owner’s tool or middleware.
  • A consumer that runs without the producer loaded gets undefined. Guard with if (lastQuery) or ctx.availablePlugins.has('weather').
  • Don’t expose large blobs. Either compute lazily in the accessor or split into smaller derived keys.

Declare dependencies

Pair shared state with softDependsOn.

RuntimeContext reference

The ctx.shared field on every tool handler.