// alpha · apache 2.0

Ship agent memory without the plumbing.

An AI-native memory graph with a single DSL — time-series, event-driven by default, multi-tenant by partition. You describe the behavior; the engine handles the rest.

Star on GitHub
no demo · no waitlist · apache 2.0
dsl/cognition/automations.memql
@enabled
@trigger(event="node.created", concept="v1:cognition:space", partition="*")
@filter(payload.active==true)
@description("On space creation, joins the creator's assistant plus any specialist agents picked at creation time. Joiners' GAs are never auto-joined.")
automation autoJoinSI {
step run {
logic autoJoinSI { event: event }
}
}
Apache 2.0 Alpha self-hostable MCP-native 4 on GitHub
built on
PostgreSQLTimescaleDBGoAnthropicOpenAIGeminiMistralGroqDeepgram
in the box
dslmemorylibraryharnessvoicecomputer usecockpitmcpcluster
01 / 09  what

What MemQL actually is.

Agent and voice deployments are integration-heavy. The engineering is mostly plumbing — vector store, orchestrator, tool registry, model provider, kept consistent by hand. MemQL collapses that plumbing into one declarative substrate on top of PostgreSQL and TimescaleDB.

A network of nodes built for three properties at once — the same three a crystal lattice gets for free. Watch.

// permanent

Append-only by default. Every row is keyed by (partition, id, createdAt)on TimescaleDB hypertables — history is a first-class index, not a log file. Data is archived via soft-delete, not destroyed.

// organized

Every node has its place. Behavior is declared, not coded — concept, query, mutation, automation, and more. Multi-tenant by partition: each customer is an isolated world; cluster-wide concepts live in _system.

// retrievable

Any node, minimum path. Each datum has an index, a context, and a query. And memory acts: every mutation emits a typed event, automations subscribe via @trigger— context reaches the agent the moment it’s needed.

// mcp· Author tools in MemQL once. They speak MCP — every tool is reachable by any MCP client.

02 / 09  the agent loop

Where agents plan, remember, and are held to account.

Storing data and reacting to events is table stakes. MemQL is where agents run whole tasks against a memory that behaves like memory — and where you can watch exactly what they did.

A plan fans into steps, each step leaves an observation, recall pulls the relevant ones back, and the whole run replays. Watch.

// the harness

Agents work through whole tasks, not just react. A structured loop — plan, step, observation — with budgets, retries, and stopping rules. The planner runs reactively (tick → route → converge), and an agent can pause to ask you via requestUserFeedback.

// memory

Consolidation turns episodic memory — what happened — into semantic knowledge: what’s true in general. recall()blends recency × relevance; semantic retrieval finds by meaning. Episodic, semantic, similarity — one memory, mechanical not metaphor.

// inspectable

trace · replay · eval. Record a run, replay it, grade it. The agent loop is glass, not a black box — the part senior engineers ask about first.

// memory, in the schema

dsl/harness/queries.memql
@enabled
@sdk
@executor("integration.harnessRecall.recall")
@args(profile="object", additionalProperties="true")
@description("Recall top-k memories of a concept (default v1:harness:observation) by a SINGLE hybrid recency x relevance score: pgvector cosine similarity + exponential time-decay over createdAt, scored and ordered server-side in one SQL statement against the MemoryNodes hypertable (no app-side merge). Owner-scoped; window prunes hypertable chunks; halfLife + wSem/wRec are tunable.")
builtin recall {
text string @required
concept string
k int
provider string
}

One hybrid score — wSem · cosine(query, memory) + wRec · exp(−ln2 · age / halfLife) — computed and ordered server-side in a single SQL statement, no app-side merge. A debugging agent raises wRec for “what just happened”; a research agent raises wSemfor “everything relevant, ever.” Memory that behaves like a mind, not a log.

dsl/harness/concepts.memql (trimmed)
// The whole agent working-state model — no external task
// table, no audit log, no state store. (trimmed: real
// concepts carry @description / @displayCard / @relationship.)
concept plan {
ownerUserId string @required
goal string @required
status enum("open", "running", "done", "failed", "cancelled") @required @default("open")
rootStepId string
input object
result object
provenanceMutation string
}
concept step {
ownerUserId string @required
planId string @required
title string @required
status enum("pending", "ready", "running", "blocked", "done", "failed") @required @default("pending")
dependsOn []string
idempotencyKey string @required
attempt int @required @default("0")
result object
}
concept observation {
ownerUserId string @required
stepId string @required
kind enum("tool_result", "error", "note", "decision") @required
content string @required
embedding []float
}

A plan, its steps (a real DAG via dependsOn, with idempotencyKey for safe replay), and every observation an agent makes — all append-only rows with automatic provenance. Invalid transitions like done → running are rejected by the engine. Observations carry an embedding, so an agent can semantically search its own history: “what did I try last time I hit this error?”

// consolidation· a scheduled per-owner pass reads new observations since a watermark, clusters them by similarity, distills each cluster into a durable belief, dedupes, decays the unreinforced, and advances the watermark. What happened becomes what’s true.

dsl/harness/automations.memql (trimmed)
@enabled
@trigger(schedule="0 45 2 * * *")
@description("Daily 02:45 UTC memory consolidation. Per owner: reads episodic nodes (plans / steps / observations) since that owner's watermark, groups them by similarity, LLM-distills stable facts, dedups against existing semantic memories, decays + prunes stale beliefs, then advances the watermark so the next run is incremental.")
automation consolidateMemory {
step run {
logic consolidateMemory { event: event }
}
}

And automations fire on clocks, not just events. This is the scheduled automation that runs that pass — 0 45 2 * * *, daily at 02:45 UTC, deliberately offset past the other nightly sweeps so they don’t contend for the same DB window. Real production scheduling, not a toy.

// tools· calendar · notes · tasks · responsibilities — each a concept, a tool, and a skill. The Library subsystem stores and faceted-queries everything they produce.

// new here? · What is an AI harness? — the model-plus-harness primer, and where memory fits.

03 / 09  architecture

Three layers. One source tree.

Plain-text DSL on top, a single Go source tree in the middle, partition-isolated time-series storage underneath. Build tags decide which binary each node becomes.

// layers

  .memql files                authored as plain text
        
  MemQL engine + SI router    one Go source tree,
                          build tags per node type
  PostgreSQL + TimescaleDB    partition-isolated
                              time-series storage

// five node binaries

  • bff
    frontend backendHTTP surface for the apps.
  • voice
    audio transportRealtime media for spoken sessions.
  • cognition
    routing / conductorRoutes events to logic and LLMs.
  • agent
    tool executionCalls tools, writes results back.
  • planner
    orchestrationMulti-step task graphs across agents.

// one binary per type. same source tree. build tags decide what’s compiled in.

04 / 09  the pitch

From a duct-taped stack to nine lines of MemQL.

A Postgres. A vector DB. An event bus. An OpenAI wrapper. A retry-logic file. Five systems, kept in sync by hand. You’ve built it. Drag the divider.

dsl/cognition/automations.memqldrag ⇆
// today · on_space_created.py
# on_space_created.py — today
from postgres import db
from pinecone import vec
from kafka import bus
from openai import OpenAI
oai = OpenAI()
def on_space_created(payload):
if not payload["active"]:
return
space_id = payload["id"]
user_id = payload["created_by"]
# join the user's default assistant
si = db.assistants.default_for(user_id)
db.memberships.insert(
space_id=space_id,
member_id=si.id,
role="assistant",
)
# ...specialist joins, audit emit, retries, idempotency,
# partition isolation, provider fallback — still TODO
// memql · automations.memql
@enabled
@trigger(event="node.created", concept="v1:cognition:space", partition="*")
@filter(payload.active==true)
@description("On space creation, joins the creator's assistant plus any specialist agents picked at creation time. Joiners' GAs are never auto-joined.")
automation autoJoinSI {
step run {
logic autoJoinSI { event: event }
}
}

today — ~40 lines, and idempotency, partition isolation, provider fallback, and audit log are all still TODO.

memql — 9 lines, declarative. Trigger, filter, partition, dispatch. The engine handles the rest.

05 / 09  composition

One event. Five constructs. Zero glue.

The fragmented Python above is the stack you assemble by hand. Here is the same outcome, declared — one write ripples through five real constructs, and the engine handles the rest.

concept
space
a row is written
event
node.created
emitted on insert
automation
autoJoinSI
@trigger subscribes
logic
logicAutoJoinSI
resolves the assistant
mutation
mutationJoinSpaceAsSI
+ session bootstrap
dsl/cognition/automations.memql
@enabled
@trigger(event="node.created", concept="v1:cognition:space", partition="*")
@filter(payload.active==true)
@description("On space creation, joins the creator's assistant plus any specialist agents picked at creation time. Joiners' GAs are never auto-joined.")
automation autoJoinSI {
step run {
logic autoJoinSI { event: event }
}
}
dsl/cognition/logic.memql (trimmed)
@description("Triggered when a v1:cognition:space is created with status='active'. Auto-joins the creator's currently-active assistant as a v1:cognition:participant. The ONLY AI participant a space carries (maxAgents=1). Idempotent. Emits 'si.auto-joined'.")
logic logicAutoJoinSI {
args {
event object @required
}
body {
getUser := queryUserById({ userId: args.event.payload.ownerUserId })
activeAssistantId := coalesce(getUser.First().payload.preferences.activeAssistantId, "")
// Exactly one of these fires, decided by activeAssistantId emptiness:
getActiveGA := if activeAssistantId != "" {
queryAgentById({ agentId: activeAssistantId })
}
getFallbackGA := if activeAssistantId == "" {
queryAssistantAgentForUser({ ownerUserId: args.event.payload.ownerUserId })
}
getGA := coalesce(getActiveGA, getFallbackGA)
// ...resolve the canonical agent id, then dispatch:
// mutationJoinSpaceAsSI (insert the SI participant)
// mutationCreateSessionForParticipant (bootstrap its session)
}
}

A user creates a space. That insert emits a typed node.createdevent. An automation is already subscribed to it. It dispatches a piece of logic that resolves the user’s assistant and writes two rows — a participant and its session. Idempotency, partition isolation, audit provenance, and retries aren’t code you wrote. They’re the substrate.

06 / 09  the language

Twelve constructs. One file format.

Every behavior in the system is described as a typed construct in a .memql file. The vocabulary is small. The system is what those twelve nouns compose into.

dsl/cognition/concepts.memql Schema. Versioned. Time-series row.
@description("A streaming text chunk emitted incrementally during AI response generation.")
concept chunk {
done bool @required
index int @required
participantId string @required
replyId string @required
spaceId string @required
text string @required
@relationship(type="parent", field="spaceId", target="v1:cognition:space")
@relationship(type="createdBy", field="participantId", target="v1:cognition:participant")
}
MemQLCockpit.
07 / 09  cockpit

A TUI that ships with the platform.

A second product, in your terminal. Terminal-native IDE and operations console for MemQL clusters — write, lint, and execute DSL; explore cluster state; manage identity and workers; observe the platform in real time. No web app. No Electron. Just gRPC to the cluster.

memql-cockpit — localhost:50050
memQL Cockpit
CLUSTERS
local *
localhost:50050 · connected
Endpointlocalhost:50050
Authauthorized
Nodes5 · all healthy
A:Add E:Edit D:Delete
TOPOLOGY
Nodes: 5 Online: 5
cognitionbffvoiceagentplanner
WASD:Pan R:Reset View X:Architecture

↑ memQL Cockpit in its real theme, a representative connected session. Node types, concept ids, policies, and providers are from the source; row-level values are illustrative. Source: znasllc-io/memql-cockpit.

// eight tabs

agentswho's joined — humans, SI, workers
authidentity · magic-link · JWKS
clientad-hoc queries + mutations
clustertopology · build tags · live events
configclusters.yaml + worker.yaml
editor.memql with linter feedback
explorergraph + time-series traversal
settingskeys · telemetry · prefs

// computer use

Run ./bin/memql-cockpit worker run and your machine joins the cluster as a per-user worker. Two modes — computer_use_headless for shell, filesystem, and HTTP; computer_use_embodied (CGO build via make cockpit-gui) for mouse, keyboard, and screenshots through RobotGo. The agent doesn’t drive a sandbox. It drives your laptop.

// install

$ make cockpit
$ ./bin/memql-cockpit

macOS LaunchAgent · Linux systemd user service · cross-compile via make cockpit-all-platforms

08 / 09  who it's for

Three readers.

// the agent product builder

You're building a product where memory matters. You've outgrown stuffing context into prompts. You've outgrown a vector DB next to a Postgres next to a custom event bus. MemQL is the system you'd build if you had a year.

// the platform engineer

Every AI feature you shipped this year needed its own storage, its own retry logic, its own event plumbing. MemQL is one substrate that handles all of it. The DSL describes behavior; the engine handles the rest.

// the agentic-os curious

The next interesting layer of infrastructure is the one between models and applications. MemQL is what that layer looks like in practice.

09 / 09  the project

MemQL and MemQL Cockpit are open source, Apache 2.0. Alpha.

Memory Query Language — built to be to AI memory what SQL is to relational data.

Docs