Skip to main content

Overview

ArgentOS is migrating from SQLite to PostgreSQL 17 + Redis for its storage backend. The migration enables concurrent multi-agent access, shared knowledge across agents, and inter-agent communication via Redis Streams and pub/sub. The migration follows a three-phase zero-downtime strategy using a abstraction that routes reads and writes to the correct backend based on configuration.

Why PG+Redis

ProblemSQLite LimitationPG+Redis Solution
Multi-agent accessSingle-writer lockConnection pool with concurrent writes
Shared knowledgePer-agent databasesShared tables with agent_id scoping + RLS
Inter-agent communicationNo built-in mechanismRedis Streams + pub/sub
Vector search at scalesqlite-vec extension (limited)pgvector with HNSW indexes
Full-text searchFTS5 (good but single-process)tsvector with GIN indexes
Hot state for dashboardFile pollingRedis key/value with pub/sub

Three-Phase Migration

1

Phase 1: Dual-Write (SQLite Reads)

Both databases receive all writes. SQLite serves reads. This validates PG write path without risk.
{
  "storage": {
    "backend": "dual",
    "readFrom": "sqlite",
    "writeTo": ["sqlite", "postgres"]
  }
}
2

Phase 2: Dual-Write (PostgreSQL Reads)

Flip readFrom to "postgres". SQLite still receives writes as a safety net. Verify PG serves all reads correctly.
{
  "storage": {
    "backend": "dual",
    "readFrom": "postgres",
    "writeTo": ["sqlite", "postgres"]
  }
}
3

Phase 3: PostgreSQL Only

SQLite becomes historical backup. All reads and writes go through PostgreSQL.
{
  "storage": {
    "backend": "postgres"
  }
}

StorageAdapter Interface

The StorageAdapter interface in src/data/adapter.ts defines the unified API that all backend implementations conform to:
interface StorageAdapter {
  memory: MemoryAdapter;    // Memory CRUD, search, embeddings
  tasks: TaskAdapter;       // Task CRUD, FTS, dependencies
  teams: TeamAdapter;       // Team management
  isReady(): boolean;       // Health check
  close(): Promise<void>;   // Cleanup
}

MemoryAdapter

Covers all memory operations:
  • createItem() / getItem() / deleteItem() — CRUD
  • searchItems() — Hybrid keyword + vector search
  • createEntity() / getEntity() — Entity management
  • createReflection() / createLesson() — SIS substrates
  • embedItem() — Embedding storage
  • getStats() — Storage statistics

TaskAdapter

Full task lifecycle:
  • createTask() / updateTask() / deleteTask() — CRUD
  • listTasks() / searchTasks() — Listing and FTS
  • getTasksByProject() — Project grouping
  • Dependencies and priority ordering

TeamAdapter

Team and member management for multi-agent workflows.

Adapter Implementations

Wraps the existing MemuStore and DataAPI modules. This is the battle-tested default backend that has served ArgentOS since day one.Source: src/data/sqlite-adapter.ts

Storage Factory

src/data/storage-factory.ts creates the correct adapter based on configuration:
const adapter = await getStorageAdapter();
// Returns SQLiteAdapter, DualAdapter, or PgAdapter
// based on storage.backend in argent.json
The factory is a singleton — subsequent calls return the same adapter instance.

PostgreSQL Schema

The PostgreSQL schema is defined in src/data/pg/schema.ts using Drizzle ORM. It contains 20 tables:

Core Tables

TableDescription
agentsAgent registry (multi-agent family)
memory_itemsDurable memory facts
entitiesNamed entities with profiles
reflectionsPeriodic summaries
lessonsSIS-derived actionable patterns
resourcesResource metadata
categoriesMemory categories
item_categoriesItem-category junction

Knowledge Tables

TableDescription
knowledge_collectionsNamed document buckets
knowledge_collection_grantsPer-agent ACL grants

Task Tables

TableDescription
tasksTask records with status, priority
teamsTeam definitions
team_membersTeam membership

Infrastructure Tables

TableDescription
service_keysEncrypted credential storage
observationsSession event capture (Memo)
model_feedbackModel performance tracking
live_candidatesMemory deduplication candidates

Indexes

pgvector HNSW indexes for approximate nearest-neighbor embedding search:
CREATE INDEX idx_memory_items_embedding_hnsw
ON memory_items USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
tsvector GIN indexes for full-text search:
CREATE INDEX idx_memory_items_fts
ON memory_items USING gin (to_tsvector('english', summary));

Row-Level Security (RLS)

RLS policies isolate agent data in shared tables:
ALTER TABLE memory_items ENABLE ROW LEVEL SECURITY;

CREATE POLICY agent_isolation ON memory_items
  USING (agent_id = current_setting('app.agent_id'));
The PG adapter sets the app.agent_id session variable on each connection from the pool, ensuring agents can only access their own data unless explicitly granted cross-agent access.

Redis Usage

Redis (port 6380) provides hot-path state and inter-agent communication:
FeatureRedis StructurePurpose
Agent stateKey/valueDashboard displays current agent state
PresenceKey with TTLTrack which agents are online
Pub/subChannelsReal-time event broadcasting
StreamsConsumer groupsInter-agent message queues
Heartbeat locksKeys with TTLPrevent duplicate heartbeat runs

Connection

import { getRedisClient } from "./data/redis-client.ts";

const redis = getRedisClient();
await redis.set("agent:main:state", JSON.stringify(state));

PG Write Mirror

The pg-write-mirror.ts module intercepts writes to the existing MemuStore (SQLite) and mirrors them to PostgreSQL. This enables gradual migration without changing all callers at once:
import { enablePgWriteMirror } from "./data/pg-write-mirror.ts";

// Call at gateway startup to begin mirroring
await enablePgWriteMirror();

Configuration

Full storage configuration in ~/.argentos/argent.json:
{
  "storage": {
    "backend": "sqlite",
    "readFrom": "sqlite",
    "writeTo": ["sqlite"],
    "postgres": {
      "connectionString": "postgres://localhost:5433/argentos",
      "maxConnections": 10
    },
    "redis": {
      "host": "localhost",
      "port": 6380,
      "db": 0
    }
  }
}

Non-Default Ports

ArgentOS uses non-standard ports to avoid conflicts with other services:
ServiceArgentOS PortDefault Port
PostgreSQL54335432
Redis63806379

Setup Scripts

# Install and configure PostgreSQL 17 with pgvector
bash scripts/setup-postgres.sh

# Install and configure Redis with LaunchAgent
bash scripts/setup-redis.sh

# Validate SQLite/PG row count parity before cutover
node --import tsx scripts/storage-cutover-readiness.ts

PG-Only Features

Some features have no SQLite equivalent and require PostgreSQL:
  • Knowledge collections and collection grants (ACL)
  • Shared knowledge library (cross-agent)
  • Agent registry (multi-agent family)
  • Service keys and auth credentials (encrypted)
  • Session tracking and observations

What Is Already Routed Through StorageAdapter

The following operations work with all three backends:
  • All memory operations (create, search, embed, delete)
  • Task CRUD and full-text search
  • Team management
  • Knowledge ingestion, search, and ACL
  • Family workflow and multi-agent task migration

Key Files

FileLOCDescription
src/data/adapter.tsStorageAdapter interface definition
src/data/sqlite-adapter.tsSQLite implementation (wraps MemuStore)
src/data/pg-adapter.ts1,362PostgreSQL implementation (Drizzle ORM)
src/data/dual-adapter.ts618Dual-write orchestrator
src/data/storage-factory.tsConfig-driven adapter creation
src/data/storage-config.tsFeature flags and port constants
src/data/pg-write-mirror.tsMemuStore write interception
src/data/pg-client.tspostgres.js connection pool
src/data/redis-client.tsioredis connection
src/data/pg/schema.tsDrizzle ORM schema (20 tables)
src/data/pg/migrations/SQL migration files
scripts/setup-postgres.shPG17 + pgvector install
scripts/setup-redis.shRedis install + LaunchAgent