Skip to main content

GrayMatter Server & Controls Guide

GrayMatter memory fabric

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:

SurfaceRole
ValkyrAI server runtimeAuthenticates users and agents, debits credits, persists memory, mirrors selected data into content/search surfaces, and serves operational actions.
ThorAPI-generated entitiesMemoryEntry, 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 controlsThe /graymatter-memory dashboard, memory entry controls, agent setup dialog, schema graph, semantic index panel, alert feed, and action controls.
GrayMatter skill and MCP toolingInstallable 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:

EndpointMethodUse
/v1/graymatter/controlGETClient discovery for GrayMatter memory, semantic health, RBAC object graph, SwarmOps registration, and Valhalla suite clients.
/v1/graymatter/admin/controlGETAdmin/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 actions
  • objectGraph: full RBAC-visible api-0 schema source and relationship policy
  • swarm: registration/discovery/graph endpoints and the coordination-only boundary
  • clients: client profiles for Valhalla suite products and external agent families
  • endpoints: 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:

ClassResponsibility
MemoryEntryControllerPublic memory CRUD/query/bootstrap/export/clear aliases under /v1/memory, /v1/MemoryEntry, and /v1/mo.
ValkyrAIMemoryEntryServiceNormalizes entries, persists through generated repositories, preserves explicit graph relationships, attaches tags, clears caches, and triggers semantic indexing.
MemoryEntrySearchServiceOwner-scoped deterministic Criteria API search across text, title, tags, type, and source filters.
MemoryEntryTagHandlerNormalizes tags and associates generated Tag objects with memory entries.
MemoryEntitlementServiceChecks and debits credits for reads, writes, and higher-order memory actions.
MemoryEntitlementControllerExposes /v1/memory/entitlement and /v1/memory/status.
MemorySemanticIndexControllerExposes /v1/memory/semantic-index for dashboard inspection.
SemanticIndexServiceMaintains semantic index metadata for memory entries.
MemoryApiDelegateOverrideImplements generated ThorAPI memory operations such as stats, runs, compact, reindex, prune, and expand.
GrayMatterControlSurfaceControllerExposes /v1/graymatter/control and /v1/graymatter/admin/control for suite clients and agents.
GrayMatterControlSurfaceServiceBuilds the Valhalla suite contract, endpoint map, memory boundary, RBAC object graph policy, and client profiles.

Request Lifecycle

For normal memory writes and reads:

  1. A human or agent authenticates through ValkyrAI auth.
  2. The server resolves the current Principal.
  3. RBAC requires an allowed role such as USER, ADMIN, or SYSTEM.
  4. MemoryEntitlementService checks whether the principal can read or write.
  5. Credits are debited through the usage ledger.
  6. The controller normalizes aliases and request shapes.
  7. The service persists through generated ThorAPI repositories.
  8. Search/cache/semantic-index side effects run after persistence.
  9. 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:

EndpointMethodUse
/v1/memoryPOSTCreate a memory entry.
/v1/memory/writePOSTAgent-friendly write alias.
/v1/memoryGETQuery/list entries with query parameters.
/v1/memory/queryPOSTQuery entries from a JSON body.
/v1/memory/readPOSTRead/query alias for agent tools.
/v1/memory/listGET, POSTList entries with filters.
/v1/memory/bootstrapGET, POSTReturn startup context for agents.
/v1/memory/bootstrap/digestGETReturn a compact startup digest.
/v1/memory/usageGETReturn usage summary for the current principal.
/v1/memory/exportGET, POSTExport memory entries before audits or cleanup.
/v1/memory/clearDELETE, POSTClear matching entries with guardrails.
/v1/memory/{id}GET, PATCH, DELETERead, patch, or delete one entry.
/v1/memory/entitlementGETReturn read/write entitlement and balance state.
/v1/memory/statusGETLightweight entitlement/status alias.
/v1/memory/semantic-indexGETInspect semantic index entries for the dashboard.
/v1/memory/semantic-healthGETInspect embedding provider quality and reindex guidance.
/v1/memory/statsGETMemory dashboard metrics.
/v1/memory/runsGETRecent memory operation records.
/v1/memory/compactPOSTCreate a compaction/action checkpoint.
/v1/memory/reindexPOSTReindex memory semantic metadata.
/v1/memory/prunePOSTPrune expired, duplicate, or low-signal entries.
/v1/memory/expandPOSTRecord capacity-expansion intent/checkpoint.
/v1/graymatter/controlGETDiscover the GrayMatter/Valhalla control surface.
/v1/graymatter/admin/controlGETAdmin/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:

  1. The controller accepts either generated entity shape or agent-friendly aliases.
  2. The server requires a non-empty useful body unless the request is explicitly allowed as low signal.
  3. Text is capped at 65,535 characters.
  4. The default entry type is context when no type is supplied.
  5. Tags are normalized and lowercased.
  6. The entry is owner-scoped to the current principal.
  7. The generated MemoryEntryRepository persists the entry.
  8. Tags are attached using generated Tag surfaces.
  9. Explicit graph relationships, including any intentionally related ContentData, are preserved without creating shadow copies.
  10. 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:

FilterBehavior
q, query, keywordSearch title and text.
tag, tagsFilter by normalized tags. Multiple tags are treated as an AND filter.
typeFilter by generated MemoryEntryTypeEnum values such as context, decision, todo, artifact, or preference.
sourceFilter by source channel, such as codex, openclaw, valor, or workflow.
page, size, offset, maxResults, max_resultsControl 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:

FieldMeaning
skuCurrent memory usage SKU, currently memory_usage_prepaid.
stateactive, grace, or inactive.
canReadWhether reads are currently allowed.
canWriteWhether writes are currently allowed.
balance fieldsThe 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.

GrayMatter memory ops console

ActionWhat It Does
statsBuilds dashboard telemetry from memory entries, semantic index records, and usage transactions.
runsReturns recent memory operation records for operational review.
compactPersists a compaction checkpoint/action record so operators and agents have an auditable optimization event.
reindexRebuilds semantic index metadata through ValkyrAIMemoryEntryService.
pruneRemoves expired, duplicate, or low-signal entries inside current guardrails.
expandRecords 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.

ControlPurpose
Mode toggleSwitches between focused "Vibe" and deeper "Pro" operating modes.
Docs stripLinks operators to GrayMatter docs, memory operations, and playbooks.
Stats cardsShows context usage, hit rate, waste, burn, and related health signals.
AlertsShows generated recommendations and warnings from the stats response.
Action buttonsRuns compact, reindex, prune, or expand through memoryApi.ts.
Entry type filtersLimits action requests to selected entry types.
Semantic index status filterFilters semantic index rows by active, stale, deleted, or all.
Schema graphVisualizes OpenAPI/ThorAPI schema relationships and memory distribution.
Agent setup dialogShows one-shot agent activation, API endpoint, MCP contract, and environment values.
WebSocket updatesAccepts 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:

ControlBehavior
Title/text/type formCreates a new MemoryEntry with generated mutation hooks.
Type filterFilters the entry list by generated enum values.
FeedShows recent entries from useGetMemoryEntrysPagedQuery.
Mark adaptedUpdates an entry title through generated update mutation.
DeleteUses 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, or support.
  • Use tags for durable retrieval, but remember multiple tag filters are ANDed.
  • Query before writing when you might duplicate an existing decision.
  • Use bootstrap/digest when an agent needs compact startup context.
  • Export before running broad clear/prune operations.
  • Keep product and architecture invariants in preference or decision entries so future agents retrieve them.
  • Treat the dashboard action result as the proof, not the button click.
  • Prefer gm-activate over 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/thorapi first. The generator is the contract.

Gotchas

GotchaWhat To Do
Credits are requiredIf reads or writes fail with entitlement errors, check starter credits, balance, and /v1/memory/entitlement.
clear has guardrailsClear operations are rate-limited per user and capped; use export first.
Tags are normalizedQuery lowercase normalized tags, not display variants.
Multiple tags are ANDedA query for launch,graymatter only returns entries with both tags.
Text has a hard capKeep MemoryEntry.text under 65,535 characters.
Low-signal writes may be skippedDo not persist "ok", "thanks", or empty tool chatter unless deliberately capturing a transcript.
WebSocket telemetry is best effortPolling and server state remain the source of truth.
Semantic index state may lag writesUse reindex or inspect /v1/memory/semantic-index if dashboard rows look stale.
Generated names can be awkwardUse generated ThorAPI names exactly; do not create cleaner shadow clients.
Visibility is not permissionAn agent can appear in the directory but still be limited by RBAC, account, and credits.

FAQ

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