Getting Started
Getting Started
Install Memcity and start adding AI memory to your Convex application in under 5 minutes.
What is Memcity?
Imagine your AI application has amnesia. Every time a user asks a question, it starts from scratch — no memory of past conversations, no knowledge of your company's documents, no understanding of how concepts in your data connect to each other.
Memcity fixes that. It's an AI memory component for Convex that gives your application three kinds of memory:
- Knowledge memory — Ingest your documents (PDFs, markdown, web pages, images, audio, video) and make them instantly searchable with a production-grade RAG pipeline. When a user asks "what's our refund policy?", Memcity finds the answer in your docs.
- Graph memory — Automatically extract entities (people, companies, products, concepts) and their relationships from your documents. When a user asks about "Acme Corp's CEO", Memcity connects the dots across multiple documents.
- Episodic memory — Remember things about individual users. Their preferences, past questions, and conversation history. A returning user doesn't have to re-explain themselves.
Think of it like giving your app a brain — one that reads your documents, understands how things connect, and remembers each user.
What Problems Does It Solve?
| Without Memcity | With Memcity |
|---|---|
| Your chatbot can't answer questions about your own docs | Your docs are searchable via natural language |
| Users have to re-explain context every session | The app remembers past conversations and preferences |
| Search only works with exact keyword matches | Semantic search understands meaning ("car" matches "automobile") |
| Related concepts across documents are invisible | Knowledge graph connects entities across all your content |
| No audit trail of what your AI accessed | Every search and ingestion is logged for compliance |
Prerequisites
Before you start, make sure you have:
- A Convex project — If you don't have one yet, run
npm create convex@latestto scaffold one. Memcity runs entirely on Convex's backend. - Node.js 18+ — Required for the Convex CLI and development tools.
- A Jina API key — Memcity uses Jina AI for generating embeddings (turning text into searchable vectors) and reranking results. Get a free key at jina.ai.
- An OpenRouter API key (Pro+ tiers) — Memcity uses OpenRouter as a gateway to access language models for query routing, entity extraction, and other AI features. Get a key at openrouter.ai.
Installation
Option A: shadcn Registry (Recommended)
If you use shadcn/ui, you can install Memcity components directly into your project. This gives you the source code — you own it and can customize it.
Step 1: Add the Memcity registry to your components.json:
{
"registries": {
"@memcity": {
"url": "https://memcity.dev/r/{name}.json",
"headers": {
"X-License-Key": "${MEMCITY_LICENSE_KEY}"
}
}
}
}Step 2: Install the component you need:
# Community (free) — basic vector search
npx shadcn@latest add @memcity/memory-search
# Pro ($79) — full 16-step RAG pipeline
npx shadcn@latest add @memcity/rag-pipeline
# Pro — multi-file upload with processing
npx shadcn@latest add @memcity/file-uploaderRegistry installs scaffold Convex files directly:
convex/memcity/*for installed Memcity blocksconvex/memory.tsfor a defaultMemoryclientconvex/memcity/convex.config.snippet.tsas the registration snippet
Option B: Direct Download
Download the package zip for your tier from memcity.dev:
# Community (free) — no license key needed
curl -O https://memcity.dev/download?tier=community
# Pro/Team — requires your license key
curl -O "https://memcity.dev/download?key=MEMCITY_PRO_xxxx-xxxx-xxxx"Then extract and add to your project:
unzip memcity-community.zip -d packages/memcitySetup
Step 1: Register the Component
Convex uses a component system — think of components as self-contained backend modules with their own database tables, functions, and logic. Memcity is a Convex component that you "install" by registering it in your app's configuration.
Open (or create) convex/convex.config.ts:
// convex/convex.config.ts
import { defineApp } from "convex/server";
import memcity from "memcity/convex.config.js";
const app = defineApp();
// This line installs Memcity's tables, indexes, and functions
// into your Convex deployment. It runs alongside your own code.
app.use(memcity);
export default app;Step 2: Set Environment Variables
Memcity needs API keys to access external AI services. Set them in your Convex deployment:
# Required for ALL tiers — powers embeddings and reranking
# Jina v4 turns your text into 1024-dimensional vectors for search
# Jina Reranker v3 re-scores results for higher precision
npx convex env set JINA_API_KEY your-jina-api-key-here
# Required for Pro and Team tiers — powers LLM reasoning
# Used for query routing, entity extraction, HyDE generation,
# and other AI features that need language understanding
npx convex env set OPENROUTER_API_KEY your-openrouter-key-hereWhat do these keys actually do?
-
Jina API key: When you ingest a document, Memcity breaks it into chunks and sends each chunk to Jina to generate an "embedding" — a list of 1,024 numbers that capture the meaning of the text. When you search, your query gets the same treatment, and Memcity finds chunks whose numbers are similar to your query's numbers. The reranker is a second-pass model that re-scores the top results for better precision.
-
OpenRouter API key: This gives Memcity access to language models (like Gemini, GPT, Claude) through a single gateway. The LLM is used for smart features like understanding whether a query is simple or complex, extracting entities from text, and generating hypothetical answers to improve search quality.
Step 3: Initialize the Memory Class
In your Convex backend code, create a Memory instance. This is the main entry point for all Memcity operations:
// convex/myFunctions.ts
import { Memory } from "memcity";
import { components } from "./_generated/api";
// Create a Memory instance with your desired configuration
const memory = new Memory(components.memcity, {
// Which tier you're on — controls which features are available
tier: "pro", // "community" | "pro" | "team"
// AI model configuration
ai: {
// "openrouter" routes through OpenRouter (recommended)
// "vercel" routes through Vercel AI Gateway
gateway: "openrouter",
// The model used for reasoning tasks
// (query routing, entity extraction, etc.)
// This is NOT the embedding model — embeddings always use Jina v4
model: "google/gemini-2.0-flash-001",
},
// Search behavior — sensible defaults, tune later
search: {
maxResults: 10, // How many results to return
minScore: 0.1, // Minimum relevance score (0-1)
weights: {
semantic: 0.7, // Weight for meaning-based search
bm25: 0.3, // Weight for keyword-based search
},
},
});Your First Search: A Complete Example
Let's walk through a complete example — ingest a document and search it:
// convex/example.ts
import { action } from "./_generated/server";
import { v } from "convex/values";
import { Memory } from "memcity";
import { components } from "./_generated/api";
const memory = new Memory(components.memcity, {
tier: "pro",
ai: {
gateway: "openrouter",
model: "google/gemini-2.0-flash-001",
},
});
// Ingest a document into a knowledge base
export const ingestDocument = action({
args: {},
handler: async (ctx) => {
// Create an organization (top-level container)
const orgId = await memory.createOrg(ctx, {
name: "My Company",
});
// Create a knowledge base (a collection of related documents)
const kbId = await memory.createKnowledgeBase(ctx, {
orgId,
name: "Company Policies",
description: "HR policies, handbooks, and procedures",
});
// Ingest a document — Memcity will automatically:
// 1. Split it into chunks (~512 tokens each)
// 2. Generate vector embeddings for each chunk
// 3. Index chunks for semantic and keyword search
// 4. Extract entities and relationships for the knowledge graph
await memory.ingestText(ctx, {
orgId,
knowledgeBaseId: kbId,
text: `
# Vacation Policy
All full-time employees are entitled to 20 days of paid
vacation per year. Vacation days do not roll over.
## Requesting Time Off
Submit vacation requests at least 2 weeks in advance
through the HR portal. Your manager must approve the
request within 3 business days.
## Sick Leave
Sick leave is separate from vacation. You get 10 sick
days per year. A doctor's note is required for absences
longer than 3 consecutive days.
`,
source: "vacation-policy.md",
});
return { orgId, kbId };
},
});
// Search the knowledge base
export const searchDocs = action({
args: {
query: v.string(),
orgId: v.string(),
knowledgeBaseId: v.string(),
},
handler: async (ctx, args) => {
const results = await memory.getContext(ctx, {
orgId: args.orgId,
knowledgeBaseId: args.knowledgeBaseId,
query: args.query,
});
// results.results is an array of matching chunks:
// - text: the matching text content
// - score: relevance score (0-1)
// - confidence: how confident Memcity is in this result
// - citations: page/line/heading breadcrumbs
// - source: which document this came from
return results;
},
});Now from your frontend:
// In your React component
const { orgId, kbId } = await ingestDocument();
// Ask a natural language question
const results = await searchDocs({
query: "How many vacation days do I get?",
orgId,
knowledgeBaseId: kbId,
});
// results.results[0].text →
// "All full-time employees are entitled to 20 days..."
// results.results[0].score → 0.92
// results.results[0].confidence → 0.87What Just Happened Behind the Scenes?
When you called ingestText, Memcity ran a multi-step ingestion pipeline:
-
Chunking — The vacation policy was split into overlapping chunks of ~512 tokens. Each chunk is small enough to be meaningful but has enough context to be useful.
-
Embedding — Each chunk was sent to Jina v4, which converted the text into a 1,024-dimensional vector — a list of 1,024 numbers that capture the meaning of the text. Similar concepts get similar numbers.
-
Indexing — The vectors were stored in Convex's vector index for fast similarity search. The raw text was also indexed for BM25 keyword search.
-
Entity Extraction (Pro+) — The LLM identified entities ("vacation", "sick leave", "HR portal") and relationships ("vacation policy" → "requires" → "manager approval").
When you called getContext, Memcity ran the full 16-step search pipeline:
- Your query was embedded into a vector
- That vector was compared against all chunk vectors (semantic search)
- The same query was matched using keywords (BM25 search)
- Results from both were merged using Reciprocal Rank Fusion
- A reranker re-scored the top results for precision
- The best results were returned with scores and citations
The whole process typically takes 200-800ms depending on your tier and which pipeline steps are enabled.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
JINA_API_KEY not set | Missing environment variable | npx convex env set JINA_API_KEY your-key |
OPENROUTER_API_KEY not set | Missing env var (Pro+) | npx convex env set OPENROUTER_API_KEY your-key |
Tier cannot use this feature | Using Pro/Team features on Community | Upgrade your tier or disable gated options |
Knowledge base limit reached | Community allows only 1 KB | Upgrade to Pro for unlimited KBs |
| Empty search results | Documents still indexing | Wait a few seconds after ingestion |
| Low relevance scores | Default config not tuned | See Configuration |
Next Steps
- Configuration — Tune every knob for your use case
- Search Pipeline — Understand each of the 16 pipeline steps
- Knowledge Graph — How entities and relationships enhance search
- File Ingestion — Process PDFs, images, audio, and 25+ file types
- Tiers & Pricing — Compare what each tier offers
- Use Cases — Real-world examples including how this site uses Memcity