How to Integrate Custom Storage Solutions with OpenMAIC: A Complete Guide

OpenMAIC is storage-agnostic and allows you to integrate any custom storage solution by implementing the StorageProvider interface defined in packages/@openmaic/dsl/src/storage.ts and registering your implementation in configs/storage.ts.

OpenMAIC (THU-MAIC/OpenMAIC) is designed as a storage-agnostic platform that decouples persistence logic from application code through a clean abstraction layer. Rather than hard-coding dependencies on specific databases or storage backends, the platform exposes a minimal TypeScript interface that you can implement to connect IndexedDB, PostgreSQL, cloud object stores, or custom REST APIs. This guide explains how to integrate custom storage solutions with OpenMAIC using the provider pattern and runtime configuration system.

Understanding the Storage Architecture

The OpenMAIC storage system relies on three core components that separate concerns between interface definition, runtime injection, and high-level consumption.

The StorageProvider Interface

At packages/@openmaic/dsl/src/storage.ts, OpenMAIC declares the storage contract that all backends must satisfy. This TypeScript interface requires only four asynchronous methods:

interface StorageProvider {
  getItem(key: string): Promise<string | null>;
  setItem(key: string, value: string): Promise<void>;
  removeItem(key: string): Promise<void>;
  clear?(): Promise<void>;
}

Because the contract is pure TypeScript with no external dependencies, you can implement it using virtually any key-value store, document database, or remote API.

Runtime Configuration

The platform injects the concrete storage implementation at startup through configs/storage.ts. This file exports the storage instance that the entire application consumes:

// configs/storage.ts
export const storage: StorageProvider = /* your implementation */;

By modifying this configuration—or supplying a custom config at startup—you tell OpenMAIC which provider to use for the current deployment without touching business logic.

High-Level Storage Utilities

OpenMAIC provides utility wrappers like lib/utils/chat-storage.ts and lib/utils/stage-storage.ts that handle domain-specific persistence for chats, stages, and assets. These utilities delegate all I/O operations to the injected StorageProvider, meaning they automatically work with any backend that respects the interface.

Implementing a Custom Storage Provider

To integrate a custom storage solution, create a class that implements the StorageProvider interface. Below is a complete example using IndexedDB via Dexie for browser-based persistence.

Example: IndexedDB/Dexie Provider

Create a new file for your implementation:

// my-custom-storage.ts
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';
import Dexie from 'dexie';

export class IndexedDBStorage implements StorageProvider {
  private db: Dexie;

  constructor() {
    this.db = new Dexie('openmaic-db');
    this.db.version(1).stores({
      kv: 'key,value',
    });
  }

  async getItem(key: string): Promise<string | null> {
    const record = await (this.db as any).kv.get({ key });
    return record ? record.value : null;
  }

  async setItem(key: string, value: string): Promise<void> {
    await (this.db as any).kv.put({ key, value });
  }

  async removeItem(key: string): Promise<void> {
    await (this.db as any).kv.delete(key);
  }

  async clear(): Promise<void> {
    await (this.db as any).kv.clear();
  }
}

Your class only needs to provide the four methods; the rest of the OpenMAIC codebase will interact with your storage through this uniform contract.

Registering Your Custom Storage with OpenMAIC

After implementing the interface, wire your provider into the runtime by updating the central configuration file.

Wiring into configs/storage.ts

Import your custom class and instantiate it in configs/storage.ts:

// configs/storage.ts
import { IndexedDBStorage } from '@/my-custom-storage';
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';

export const storage: StorageProvider = new IndexedDBStorage();

Now every component that calls chat-storage.ts, stage-storage.ts, or any other utility will delegate to your IndexedDBStorage instance. No other code changes are required.

Direct Usage in Application Code

If you need direct access to the storage—for example, in migration scripts or custom services—you can import the configured instance:

import { storage } from '@/configs/storage';

await storage.setItem('session-id', 'abc-123');
const value = await storage.getItem('session-id'); // → 'abc-123'

Advanced Example: Remote REST Storage

You can also implement the interface to delegate persistence to a remote HTTP API. This approach lets you use OpenMAIC with proprietary backends or serverless functions.

// rest-storage.ts
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';

export class RestStorage implements StorageProvider {
  constructor(private baseUrl: string) {}

  async getItem(key: string): Promise<string | null> {
    const response = await fetch(`${this.baseUrl}/kv/${key}`);
    if (!response.ok) return null;
    return response.text();
  }

  async setItem(key: string, value: string): Promise<void> {
    await fetch(`${this.baseUrl}/kv/${key}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ value }),
    });
  }

  async removeItem(key: string): Promise<void> {
    await fetch(`${this.baseUrl}/kv/${key}`, { method: 'DELETE' });
  }
}

Register new RestStorage('https://api.example.com') in configs/storage.ts, and OpenMAIC will persist all session data, chat history, and assets to your custom REST endpoint.

Summary

  • Implement the interface: Create a class that satisfies the StorageProvider contract from packages/@openmaic/dsl/src/storage.ts with getItem, setItem, removeItem, and optionally clear.
  • Configure the runtime: Export your instance from configs/storage.ts to inject it into the OpenMAIC server-side runtime.
  • Leverage existing utilities: High-level helpers like lib/utils/chat-storage.ts work transparently with your custom backend without modification.
  • Support any backend: Because the interface requires only basic key-value operations, you can integrate IndexedDB, PostgreSQL, Redis, S3, or custom REST APIs.

Frequently Asked Questions

What methods must a custom StorageProvider implement?

According to the source code in packages/@openmaic/dsl/src/storage.ts, you must implement three required methods: getItem(key: string), setItem(key: string, value: string), and removeItem(key: string). The clear() method is optional. All methods return Promise objects since OpenMAIC expects asynchronous storage operations.

Can I use OpenMAIC with cloud storage services like S3?

Yes. You can integrate AWS S3, Google Cloud Storage, or Azure Blob Storage by implementing the StorageProvider interface using the respective cloud SDKs. Map getItem to download operations, setItem to uploads, and removeItem to delete operations. Register your cloud-backed provider in configs/storage.ts just like any other implementation.

Where do I configure which storage provider OpenMAIC uses?

You specify the active storage implementation in configs/storage.ts. This file serves as the central registry where you import your custom class, instantiate it, and export it as the storage object. The OpenMAIC runtime imports this export and passes it to all persistence utilities throughout the application.

Do I need to modify chat-storage.ts or stage-storage.ts to use custom storage?

No. Files like lib/utils/chat-storage.ts and lib/utils/stage-storage.ts are designed to consume the abstract StorageProvider interface rather than concrete implementations. They import the storage instance from configs/storage.ts and delegate all read/write operations to it. This design ensures that switching storage backends requires changes only to the configuration file, not to domain-specific storage logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →