Crux
GuidesConvex

Setup

Install @use-crux/convex, register the component, and create shared Crux storage helpers.

Install the runtime packages you need on the server:

pnpm add @use-crux/core @use-crux/ai @use-crux/convex @ai-sdk/openai zod

If you use the Convex Agent component, also install it:

pnpm add @convex-dev/agent

Install The Component

@use-crux/convex ships a Convex component for Crux-owned persistence such as memory records and experimental cross-action swarm state.

convex/convex.config.ts
import { defineApp } from "convex/server";
import crux from "@use-crux/convex/convex.config";

const app = defineApp();
app.use(crux);

export default app;

Run Convex codegen after adding the component so components.crux exists:

npx convex dev

The packaged component already uses Convex-valid module paths, so no consumer-side rewriting is needed before codegen or deployment.

Create A Record Helper

Create one small helper and reuse it everywhere you need Crux records.

convex/crux/storage.ts
import type { ActionCtx, MutationCtx } from "../_generated/server";
import { components } from "../_generated/api";
import { convexRecordStore } from "@use-crux/convex";

export function cruxRecords(ctx: ActionCtx | MutationCtx) {
  return convexRecordStore({ component: components.crux, ctx });
}

Use these records for memory blocks, blackboards, plans, prompt cache data, and workspace metadata. Use a separate dedicated component instance or vector namespace for semantic cache entries if you need isolated vector search behavior.

Create An Agent Profile

If you use the Convex Agent component, create one profile that owns both component references. This is the preferred boundary when Crux should own the profile-backed prompt, memory, skills, tools, and post-turn persistence lifecycle.

convex/crux/profile.ts
import { createCruxConvex } from "@use-crux/convex";
import { components } from "../_generated/api";

export const crux = createCruxConvex({
  components: {
    crux: components.crux,
    agent: components.agent,
  },
});

Use crux.convexAgent({ prompt, languageModel, ... }) when Crux should resolve the prompt for each Convex Agent turn. Use crux.storage(ctx) for request-scoped storage and crux.run(ctx, target, fn) for lower-level integrations that need Convex-bound memory/tools outside the profile-backed helper.

If tests, migrations, or alternate storage need to replace the default component-backed storage, configure one profile-level storage factory:

convex/crux/profile.ts
export const crux = createCruxConvex({
  components: { crux: components.crux, agent: components.agent },
  storage: {
    create(ctx, defaults) {
      return defaults.createComponentStorage(ctx);
    },
  },
});

Lower-Level Runtime Work

Use createCruxConvex().run(ctx, target, fn) when custom Convex actions or normal Convex Agent-shaped code need Crux runtime plumbing without the profile-backed convexAgent() helper. The same profile exposes storage(ctx) and bridge(http, cruxConfig) for lower-level storage and devtools integration.

Runtime Layout

Keep definitions portable and boundaries explicit:

convex/
  prompts/
    support.ts          # prompt(), context(), agent() definitions
  crux/
    storage.ts          # cruxRecords(ctx) for record-only code
    profile.ts          # createCruxConvex({ components }) for profile-backed and lower-level runtime code
  chat/
    actions.ts          # @use-crux/convex/server action() entrypoints
  agent/
    tools.ts            # @use-crux/convex/agent tools
  workflows/
    writerFlow.ts       # @use-crux/convex/server flow()

Node Runtime

Actions that import AI SDK providers, OpenAI clients, or other Node-only packages need 'use node':

convex/chat/actions.ts
"use node";

import { action } from "@use-crux/convex/server";
import { generate } from "@use-crux/ai";
import { openai } from "@ai-sdk/openai";

Queries and mutations that only read/write Convex data can stay in the default Convex runtime.

Best Practices

  • Install the component once and access it through components.crux.
  • Put prompt/context/agent definitions in regular modules so they remain testable outside Convex.
  • Put AI execution entrypoints behind @use-crux/convex/server boundaries.
  • Keep tenant checks, auth, and app table writes in your app, not in reusable Crux helpers.

Devtools Runtime Bridge

For local development, Convex exposes Runtime Bridge commands over HTTP instead of holding a long-lived WebSocket inside actions.

convex/http.ts
import { httpRouter } from "convex/server";
import { cruxConfig } from "./crux/config";
import { crux } from "./crux/profile";

const http = httpRouter();

crux.bridge(http, cruxConfig);

export default http;

This registers GET /crux/bridge, POST /crux/bridge, and OPTIONS /crux/bridge. The Go devtools backend calls that endpoint for read-only live-runtime commands such as store.read. The profile bridge uses the same request-scoped storage path as crux.run() and crux.convexAgent(), so memory and blackboard resources can be inspected by resource id without separately registering every store. The manifest uses the actual HTTP Actions URL from the request unless you pass an explicit url, and invalid command bodies return structured bridge errors. Treat the bridge as trusted local-dev infrastructure; do not expose it as a public application RPC surface.

Next

On this page