GrayMatter Server & Controls Guide

GrayMatter is the durable memory and operating context layer for ValkyrAI, ValorIDE, OpenClaw, Codex, Claude adapters, native agents, and customer workflows. It is not a side-channel note system. It is implemented through ValkyrAI's ThorAPI-generated object model and exposed through authenticated, RBAC-scoped server endpoints, generated frontend clients, and a dedicated memory operations dashboard.
This guide explains the server-side flow, the frontend controls, how agents should use GrayMatter, and the operational practices that keep memory useful, secure, and cost-controlled.
Non-Negotiable Architecture Rule
GrayMatter runs inside the ThorAPI product architecture.
- Backend entity models, persistence, repositories, and CRUD surfaces come from ThorAPI-generated code.
- Custom Java belongs around generated ThorAPI surfaces: controllers, services, delegates, workflow modules, guards, orchestration, and model extensions only when absolutely necessary.
- Frontend entity CRUD uses generated ThorAPI model types and RTK Query services in
src/thorapi. - Custom React and custom RTK services are allowed for product orchestration, dashboard aggregation, and runtime actions, but not as parallel hand-coded CRUD systems for ThorAPI entities.
That rule is what keeps GrayMatter portable across generated applications instead of turning it into one-off Spring or React code.
What GrayMatter Is
GrayMatter has four cooperating surfaces:
| Surface | Role |
|---|---|
| ValkyrAI server runtime | Authenticates users and agents, debits credits, persists memory, mirrors selected data into content/search surfaces, and serves operational actions. |
| ThorAPI-generated entities | MemoryEntry, GrayMatter, SemanticIndexEntry, Agent, Tag, ContentData, credits, principal/account objects, and the generated client contracts around them. The broader RBAC-visible schema is available as object graph context. |
| Frontend controls | The /graymatter-memory dashboard, memory entry controls, agent setup dialog, schema graph, semantic index panel, alert feed, and action controls. |
| GrayMatter skill and MCP tooling | Installable agent workflow with activation, login, query/write, agent registration, and OpenAPI sync helpers. |
The intended mental model is simple: agents and humans write compact, meaningful operating context into GrayMatter; GrayMatter stores it as typed, owner-scoped memory; the dashboard makes quality and spend visible; SWARM and Agent Directory make participants visible. SwarmOps is coordination state, not a memory primitive.
Valhalla Control Surface
ValkyrAI exposes an authenticated control document for GrayMatter-aware clients:
| Endpoint | Method | Use |
|---|---|---|
/v1/graymatter/control | GET | Client discovery for GrayMatter memory, semantic health, RBAC object graph, SwarmOps registration, and Valhalla suite clients. |
/v1/graymatter/admin/control | GET | Admin/control alias for the same RBAC-scoped contract. |
ValorIDE, Valor, CODEX, OpenClaw, Claude adapters, and Sheetster Grid should load this document before falling back to /v1/api-docs. Gridheim Runes appear through the RBAC-visible object graph as generated calculated properties rather than as a standalone GrayMatter client. The response declares:
memory: primitives (MemoryEntry,GrayMatter,SemanticIndexEntry), entry types, entitlement, usage, and admin actionsobjectGraph: full RBAC-visible api-0 schema source and relationship policyswarm: registration/discovery/graph endpoints and the coordination-only boundaryclients: client profiles for Valhalla suite products and external agent familiesendpoints: canonical memory, schema, SwarmOps, Agent, GrayMatter, and MCP endpoint map
Server-Side Flow
The main runtime lives in ValkyrAI, under:
valkyrai/src/main/java/com/valkyrlabs/valkyrai/memory
valkyrai/src/main/java/com/valkyrlabs/valkyrai/api/MemoryApiDelegateOverride.java
The key server classes are:
| Class | Responsibility |
|---|---|
MemoryEntryController | Public memory CRUD/query/bootstrap/export/clear aliases under /v1/memory, /v1/MemoryEntry, and /v1/mo. |
ValkyrAIMemoryEntryService | Normalizes entries, persists through generated repositories, preserves explicit graph relationships, attaches tags, clears caches, and triggers semantic indexing. |
MemoryEntrySearchService | Owner-scoped deterministic Criteria API search across text, title, tags, type, and source filters. |
MemoryEntryTagHandler | Normalizes tags and associates generated Tag objects with memory entries. |
MemoryEntitlementService | Checks and debits credits for reads, writes, and higher-order memory actions. |
MemoryEntitlementController | Exposes /v1/memory/entitlement and /v1/memory/status. |
MemorySemanticIndexController | Exposes /v1/memory/semantic-index for dashboard inspection. |
SemanticIndexService | Maintains semantic index metadata for memory entries. |
MemoryApiDelegateOverride | Implements generated ThorAPI memory operations such as stats, runs, compact, reindex, prune, and expand. |
GrayMatterControlSurfaceController | Exposes /v1/graymatter/control and /v1/graymatter/admin/control for suite clients and agents. |
GrayMatterControlSurfaceService | Builds the Valhalla suite contract, endpoint map, memory boundary, RBAC object graph policy, and client profiles. |
Request Lifecycle
For normal memory writes and reads:
- A human or agent authenticates through ValkyrAI auth.
- The server resolves the current
Principal. - RBAC requires an allowed role such as
USER,ADMIN, orSYSTEM. MemoryEntitlementServicechecks whether the principal can read or write.- Credits are debited through the usage ledger.
- The controller normalizes aliases and request shapes.
- The service persists through generated ThorAPI repositories.
- Search/cache/semantic-index side effects run after persistence.
- The response returns the saved entry, search result, status, or action result.
Endpoint Map
The memory controller intentionally supports both polished public paths and compatibility aliases:
| Endpoint | Method | Use |
|---|---|---|
/v1/memory | POST | Create a memory entry. |
/v1/memory/write | POST | Agent-friendly write alias. |
/v1/memory | GET | Query/list entries with query parameters. |
/v1/memory/query | POST | Query entries from a JSON body. |
/v1/memory/read | POST | Read/query alias for agent tools. |
/v1/memory/list | GET, POST | List entries with filters. |
/v1/memory/bootstrap | GET, POST | Return startup context for agents. |
/v1/memory/bootstrap/digest | GET | Return a compact startup digest. |
/v1/memory/usage | GET | Return usage summary for the current principal. |
/v1/memory/export | GET, POST | Export memory entries before audits or cleanup. |
/v1/memory/clear | DELETE, POST | Clear matching entries with guardrails. |
/v1/memory/{id} | GET, PATCH, DELETE | Read, patch, or delete one entry. |
/v1/memory/entitlement | GET | Return read/write entitlement and balance state. |
/v1/memory/status | GET | Lightweight entitlement/status alias. |
/v1/memory/semantic-index | GET | Inspect semantic index entries for the dashboard. |
/v1/memory/semantic-health | GET | Inspect embedding provider quality and reindex guidance. |
/v1/memory/stats | GET | Memory dashboard metrics. |
/v1/memory/runs | GET | Recent memory operation records. |
/v1/memory/compact | POST | Create a compaction/action checkpoint. |
/v1/memory/reindex | POST | Reindex memory semantic metadata. |
/v1/memory/prune | POST | Prune expired, duplicate, or low-signal entries. |
/v1/memory/expand | POST | Record capacity-expansion intent/checkpoint. |
/v1/graymatter/control | GET | Discover the GrayMatter/Valhalla control surface. |
/v1/graymatter/admin/control | GET | Admin/control alias for the same control surface. |
The same entry controller also accepts /v1/MemoryEntry, /v1/mo, and /v1/mo/entries for compatibility with generated clients and agent conventions.
Memory Write Lifecycle
A memory write should be small, intentional, and reusable.
When a client writes memory:
- The controller accepts either generated entity shape or agent-friendly aliases.
- The server requires a non-empty useful body unless the request is explicitly allowed as low signal.
- Text is capped at
65,535characters. - The default entry type is
contextwhen no type is supplied. - Tags are normalized and lowercased.
- The entry is owner-scoped to the current principal.
- The generated
MemoryEntryRepositorypersists the entry. - Tags are attached using generated
Tagsurfaces. - Explicit graph relationships, including any intentionally related
ContentData, are preserved without creating shadow copies. - Semantic index metadata is refreshed.
ContentData is reserved for content artifacts and related/overflow details that need its own schema fields. Agents should not stuff memory metadata into contentData; use category, tags, metadata, and first-class relationships instead.
Low-signal write protection is deliberate. Agent transcripts often contain "ok", "thanks", repeated tool chatter, or empty operational status. GrayMatter should keep durable signal, not burn credits preserving noise. If an agent intentionally needs raw transcript capture, it should set an explicit low-signal allowance rather than bypassing the guard.
Query and Read Lifecycle
The deterministic memory query path is database-backed and owner-scoped.
Supported filters include:
| Filter | Behavior |
|---|---|
q, query, keyword | Search title and text. |
tag, tags | Filter by normalized tags. Multiple tags are treated as an AND filter. |
type | Filter by generated MemoryEntryTypeEnum values such as context, decision, todo, artifact, or preference. |
source | Filter by source channel, such as codex, openclaw, valor, or workflow. |
page, size, offset, maxResults, max_results | Control pagination and result count. |
Query results are not a global memory dump. They are scoped to the authenticated principal/account and filtered before they reach the caller.
Entitlements and Credits
GrayMatter memory is gated by credits. The code reads configurable properties for memory usage pricing:
billing.usage.memory-read-credits
billing.usage.memory-write-credits
The runtime defaults are intentionally configurable so staging, enterprise contracts, and launch experiments can change pricing without forking memory code. New GrayMatter signups should receive starter credits, and the dashboard should make balance and usage visible before higher-throughput operations are run.
The entitlement snapshot reports:
| Field | Meaning |
|---|---|
sku | Current memory usage SKU, currently memory_usage_prepaid. |
state | active, grace, or inactive. |
canRead | Whether reads are currently allowed. |
canWrite | Whether writes are currently allowed. |
| balance fields | The current credit state used by the dashboard and payment surfaces. |
If credits are exhausted, GrayMatter should degrade loudly and clearly. Agents should not pretend durable memory succeeded when the server rejected the read or write.
Operational Actions
Operational actions are implemented through MemoryApiDelegateOverride, which overrides the generated ThorAPI delegate for memory runtime behavior.

| Action | What It Does |
|---|---|
stats | Builds dashboard telemetry from memory entries, semantic index records, and usage transactions. |
runs | Returns recent memory operation records for operational review. |
compact | Persists a compaction checkpoint/action record so operators and agents have an auditable optimization event. |
reindex | Rebuilds semantic index metadata through ValkyrAIMemoryEntryService. |
prune | Removes expired, duplicate, or low-signal entries inside current guardrails. |
expand | Records capacity-expansion intent and creates checkpoint context. |
Stats are operational heuristics derived from real platform state. They are not magic model scores. Treat them as decision support: if hit rate drops, waste rises, or burn rate spikes, the dashboard points operators toward the next reasonable action.
Frontend Controls
The main user surface is the GrayMatter memory dashboard, implemented in:
web/typescript/valkyr_labs_com/src/components/memory/MemoryDashboard.tsx
web/typescript/valkyr_labs_com/src/components/memory/MemoryEntryControls.tsx
web/typescript/valkyr_labs_com/src/components/memory/AgentSetupDialog.tsx
web/typescript/valkyr_labs_com/src/services/memoryApi.ts
Dashboard Controls
The dashboard combines generated ThorAPI types with runtime memory operations.
| Control | Purpose |
|---|---|
| Mode toggle | Switches between focused "Vibe" and deeper "Pro" operating modes. |
| Docs strip | Links operators to GrayMatter docs, memory operations, and playbooks. |
| Stats cards | Shows context usage, hit rate, waste, burn, and related health signals. |
| Alerts | Shows generated recommendations and warnings from the stats response. |
| Action buttons | Runs compact, reindex, prune, or expand through memoryApi.ts. |
| Entry type filters | Limits action requests to selected entry types. |
| Semantic index status filter | Filters semantic index rows by active, stale, deleted, or all. |
| Schema graph | Visualizes OpenAPI/ThorAPI schema relationships and memory distribution. |
| Agent setup dialog | Shows one-shot agent activation, API endpoint, MCP contract, and environment values. |
| WebSocket updates | Accepts live memory and credit telemetry, with polling/cache as the durable fallback. |
The dashboard caches stats in session storage for a short period so page transitions do not feel blank, then refreshes from the API.
Generated CRUD Controls
MemoryEntryControls.tsx is the canonical pattern for frontend entity CRUD:
import { MemoryEntryTypeEnum } from "@thorapi/model/MemoryEntry";
import {
useAddMemoryEntryMutation,
useDeleteMemoryEntryCascadeMutation,
useGetMemoryEntrysPagedQuery,
useUpdateMemoryEntryMutation,
} from "@thorapi/redux/services/MemoryEntryService";
The generated hook spelling follows ThorAPI output. Do not "fix" generated names by creating parallel services. Compose better UI around the generated hooks instead.
The memory entry controls currently provide:
| Control | Behavior |
|---|---|
| Title/text/type form | Creates a new MemoryEntry with generated mutation hooks. |
| Type filter | Filters the entry list by generated enum values. |
| Feed | Shows recent entries from useGetMemoryEntrysPagedQuery. |
| Mark adapted | Updates an entry title through generated update mutation. |
| Delete | Uses generated cascade delete mutation with trash/cascade options. |
Runtime Dashboard Service
src/services/memoryApi.ts is intentionally different from generated entity CRUD. It wraps runtime operational endpoints for dashboard actions while still importing generated model types and the shared ThorAPI base query:
import type { MemoryActionRequest } from "@thorapi/model/MemoryActionRequest";
import type { MemoryStats } from "@thorapi/model/MemoryStats";
import { customBaseQuery } from "@thorapi/redux/customBaseQuery";
Use this pattern only for product-level runtime orchestration: stats, runs, semantic-index inspection, compact, reindex, prune, and expand. Use generated src/thorapi services for normal entity CRUD.
Agent and MCP Usage
The GrayMatter repo is the installable skill/tooling package:
GrayMatter/
README.md
SKILL.md
scripts/gm-activate
scripts/gm-login
scripts/gm-install-check
scripts/gm-smoke
scripts/gm-openapi-sync
scripts/gm-openapi-summary
scripts/gm-query
scripts/gm-write
scripts/gm-graph
scripts/gm-entity
First-run agent setup should use:
scripts/gm-activate
That flow logs in, stores the session securely, validates install readiness, runs a smoke test, registers the agent in the Agent Directory, syncs the live OpenAPI schema, and prints a schema summary.
Day-to-day examples:
# Query durable memory
scripts/gm-query "customer onboarding preferences" 10
# Write durable context
scripts/gm-write context "Use ThorAPI-generated CRUD surfaces for GrayMatter frontend entity operations."
# Register or refresh the current agent record
scripts/gm-register-agent
# Sync live schema awareness
scripts/gm-openapi-sync
scripts/gm-openapi-summary
Agents should register before doing durable work. Humans and other agents need visibility into who is touching ValkyrAI, what capabilities they claim, and which SWARM events they publish.
Tips and Tricks
- Write decisions, preferences, todos, artifacts, and context as separate durable entries. One clear memory beats a giant transcript.
- Use stable source channels such as
codex,openclaw,valor,valklaw,valoride,workflow, orsupport. - Use tags for durable retrieval, but remember multiple tag filters are ANDed.
- Query before writing when you might duplicate an existing decision.
- Use
bootstrap/digestwhen an agent needs compact startup context. - Export before running broad clear/prune operations.
- Keep product and architecture invariants in
preferenceordecisionentries so future agents retrieve them. - Treat the dashboard action result as the proof, not the button click.
- Prefer
gm-activateover manual token work. Tokens should live in secure local storage, not in chat history or docs. - When a generated hook name looks odd, check
src/thorapifirst. The generator is the contract.
Gotchas
| Gotcha | What To Do |
|---|---|
| Credits are required | If reads or writes fail with entitlement errors, check starter credits, balance, and /v1/memory/entitlement. |
clear has guardrails | Clear operations are rate-limited per user and capped; use export first. |
| Tags are normalized | Query lowercase normalized tags, not display variants. |
| Multiple tags are ANDed | A query for launch,graymatter only returns entries with both tags. |
| Text has a hard cap | Keep MemoryEntry.text under 65,535 characters. |
| Low-signal writes may be skipped | Do not persist "ok", "thanks", or empty tool chatter unless deliberately capturing a transcript. |
| WebSocket telemetry is best effort | Polling and server state remain the source of truth. |
| Semantic index state may lag writes | Use reindex or inspect /v1/memory/semantic-index if dashboard rows look stale. |
| Generated names can be awkward | Use generated ThorAPI names exactly; do not create cleaner shadow clients. |
| Visibility is not permission | An agent can appear in the directory but still be limited by RBAC, account, and credits. |
FAQ
Is GrayMatter just vector search?
No. GrayMatter is durable, typed, RBAC-scoped memory plus generated ThorAPI object graph access, dashboard operations, credits, semantic index metadata, and SWARM/Agent visibility. Vector-style retrieval can help, but it is not the whole product.
Why are there /v1/memory, /v1/MemoryEntry, and /v1/mo paths?
They exist for compatibility across generated clients, agent tooling, and concise MCP/operator workflows. New user-facing integrations should prefer /v1/memory unless a generated client or installed skill expects a specific alias.
What happens when credits run out?
The entitlement service moves the account toward a degraded state. Reads and writes can fail, and the caller should surface the failure. New signups should receive starter credits so first-run memory works without a payment step.
Where do agents register?
Agents create or refresh durable Agent records through ValkyrAI agent endpoints, then register live presence through /v1/swarm-ops/register. The setup dialog and GrayMatter agent registration command are the normal entry points.
Should a frontend developer call /v1/memory directly?
For generated entity CRUD, no. Use generated ThorAPI services in src/thorapi/redux/services. Direct or custom RTK calls are reserved for runtime dashboard orchestration such as stats/actions, and should still use generated model types plus the shared ThorAPI base query.
Why does useGetMemoryEntrysPagedQuery have that spelling?
It is generated. Keep it. If the generated contract changes, regenerate through ThorAPI instead of hand-coding a nicer local service.
How do I debug missing memory?
Check the authenticated principal, entitlement status, source filter, type filter, tag AND behavior, result limit, and whether the entry was skipped as low signal. Then inspect /v1/memory/export or the dashboard semantic index panel.
How do I safely clean up memory?
Export first, filter narrowly, clear or prune with limits, then re-query. Avoid broad cleanup from an unverified account context.
Does GrayMatter replace the database?
No. GrayMatter uses the generated ValkyrAI/ThorAPI database-backed object model. It gives agents and humans a durable memory and coordination layer over that generated application schema.
Is SwarmOps part of GrayMatter memory?
No. SwarmOps is the agent registration, discovery, command, graph, and telemetry surface. GrayMatter memory operations are scoped to MemoryEntry, GrayMatter, and semantic index state. The full RBAC-visible schema, including SwarmOps, can still be used as object graph context when the authenticated principal is allowed to see it.
How should Codex, OpenClaw, Valor, and Valklaw use it?
Register as agents, query durable memory before major work, write only durable decisions or useful context, and publish SWARM events through the protocol when coordination matters.
File Map
Server-side implementation:
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/memory/MemoryEntryController.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/memory/ValkyrAIMemoryEntryService.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/memory/MemoryEntrySearchService.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/service/memory/MemoryEntitlementService.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/memory/MemorySemanticIndexController.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/api/MemoryApiDelegateOverride.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/controller/GrayMatterControlSurfaceController.java
ValkyrAI/valkyrai/src/main/java/com/valkyrlabs/valkyrai/graymatter/GrayMatterControlSurfaceService.java
Frontend controls:
ValkyrAI/web/typescript/valkyr_labs_com/src/components/memory/MemoryDashboard.tsx
ValkyrAI/web/typescript/valkyr_labs_com/src/components/memory/MemoryEntryControls.tsx
ValkyrAI/web/typescript/valkyr_labs_com/src/components/memory/AgentSetupDialog.tsx
ValkyrAI/web/typescript/valkyr_labs_com/src/services/memoryApi.ts
ValkyrAI/web/typescript/valkyr_labs_com/src/thorapi/redux/services/MemoryEntryService.tsx
ValkyrAI/web/typescript/valkyr_labs_com/src/thorapi/redux/services/GrayMatterService.tsx
Agent tooling:
GrayMatter/README.md
GrayMatter/SKILL.md
GrayMatter/docs/architecture.md
GrayMatter/docs/thorapi-integration.md
GrayMatter/scripts/gm-activate
GrayMatter/scripts/gm-query
GrayMatter/scripts/gm-write
GrayMatter/scripts/gm-openapi-sync