remdb 0.3.7__py3-none-any.whl → 0.3.133__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. rem/__init__.py +129 -2
  2. rem/agentic/README.md +76 -0
  3. rem/agentic/__init__.py +15 -0
  4. rem/agentic/agents/__init__.py +16 -2
  5. rem/agentic/agents/sse_simulator.py +502 -0
  6. rem/agentic/context.py +51 -25
  7. rem/agentic/llm_provider_models.py +301 -0
  8. rem/agentic/mcp/tool_wrapper.py +112 -17
  9. rem/agentic/otel/setup.py +93 -4
  10. rem/agentic/providers/phoenix.py +314 -132
  11. rem/agentic/providers/pydantic_ai.py +215 -26
  12. rem/agentic/schema.py +361 -21
  13. rem/agentic/tools/rem_tools.py +3 -3
  14. rem/api/README.md +238 -1
  15. rem/api/deps.py +255 -0
  16. rem/api/main.py +154 -37
  17. rem/api/mcp_router/resources.py +1 -1
  18. rem/api/mcp_router/server.py +26 -5
  19. rem/api/mcp_router/tools.py +465 -7
  20. rem/api/middleware/tracking.py +172 -0
  21. rem/api/routers/admin.py +494 -0
  22. rem/api/routers/auth.py +124 -0
  23. rem/api/routers/chat/completions.py +402 -20
  24. rem/api/routers/chat/models.py +88 -10
  25. rem/api/routers/chat/otel_utils.py +33 -0
  26. rem/api/routers/chat/sse_events.py +542 -0
  27. rem/api/routers/chat/streaming.py +642 -45
  28. rem/api/routers/dev.py +81 -0
  29. rem/api/routers/feedback.py +268 -0
  30. rem/api/routers/messages.py +473 -0
  31. rem/api/routers/models.py +78 -0
  32. rem/api/routers/query.py +360 -0
  33. rem/api/routers/shared_sessions.py +406 -0
  34. rem/auth/middleware.py +126 -27
  35. rem/cli/commands/README.md +237 -64
  36. rem/cli/commands/ask.py +13 -10
  37. rem/cli/commands/cluster.py +1808 -0
  38. rem/cli/commands/configure.py +5 -6
  39. rem/cli/commands/db.py +396 -139
  40. rem/cli/commands/experiments.py +469 -74
  41. rem/cli/commands/process.py +22 -15
  42. rem/cli/commands/scaffold.py +47 -0
  43. rem/cli/commands/schema.py +97 -50
  44. rem/cli/main.py +29 -6
  45. rem/config.py +10 -3
  46. rem/models/core/core_model.py +7 -1
  47. rem/models/core/experiment.py +54 -0
  48. rem/models/core/rem_query.py +5 -2
  49. rem/models/entities/__init__.py +21 -0
  50. rem/models/entities/domain_resource.py +38 -0
  51. rem/models/entities/feedback.py +123 -0
  52. rem/models/entities/message.py +30 -1
  53. rem/models/entities/session.py +83 -0
  54. rem/models/entities/shared_session.py +180 -0
  55. rem/models/entities/user.py +10 -3
  56. rem/registry.py +373 -0
  57. rem/schemas/agents/rem.yaml +7 -3
  58. rem/services/content/providers.py +92 -133
  59. rem/services/content/service.py +92 -20
  60. rem/services/dreaming/affinity_service.py +2 -16
  61. rem/services/dreaming/moment_service.py +2 -15
  62. rem/services/embeddings/api.py +24 -17
  63. rem/services/embeddings/worker.py +16 -16
  64. rem/services/phoenix/EXPERIMENT_DESIGN.md +3 -3
  65. rem/services/phoenix/client.py +302 -28
  66. rem/services/postgres/README.md +159 -15
  67. rem/services/postgres/__init__.py +2 -1
  68. rem/services/postgres/diff_service.py +531 -0
  69. rem/services/postgres/pydantic_to_sqlalchemy.py +427 -129
  70. rem/services/postgres/repository.py +132 -0
  71. rem/services/postgres/schema_generator.py +291 -9
  72. rem/services/postgres/service.py +6 -6
  73. rem/services/rate_limit.py +113 -0
  74. rem/services/rem/README.md +14 -0
  75. rem/services/rem/parser.py +44 -9
  76. rem/services/rem/service.py +36 -2
  77. rem/services/session/compression.py +24 -1
  78. rem/services/session/reload.py +1 -1
  79. rem/services/user_service.py +98 -0
  80. rem/settings.py +399 -29
  81. rem/sql/background_indexes.sql +21 -16
  82. rem/sql/migrations/001_install.sql +387 -54
  83. rem/sql/migrations/002_install_models.sql +2320 -393
  84. rem/sql/migrations/003_optional_extensions.sql +326 -0
  85. rem/sql/migrations/004_cache_system.sql +548 -0
  86. rem/utils/__init__.py +18 -0
  87. rem/utils/constants.py +97 -0
  88. rem/utils/date_utils.py +228 -0
  89. rem/utils/embeddings.py +17 -4
  90. rem/utils/files.py +167 -0
  91. rem/utils/mime_types.py +158 -0
  92. rem/utils/model_helpers.py +156 -1
  93. rem/utils/schema_loader.py +282 -35
  94. rem/utils/sql_paths.py +146 -0
  95. rem/utils/sql_types.py +3 -1
  96. rem/utils/vision.py +9 -14
  97. rem/workers/README.md +14 -14
  98. rem/workers/__init__.py +3 -1
  99. rem/workers/db_listener.py +579 -0
  100. rem/workers/db_maintainer.py +74 -0
  101. rem/workers/unlogged_maintainer.py +463 -0
  102. {remdb-0.3.7.dist-info → remdb-0.3.133.dist-info}/METADATA +460 -303
  103. {remdb-0.3.7.dist-info → remdb-0.3.133.dist-info}/RECORD +105 -74
  104. {remdb-0.3.7.dist-info → remdb-0.3.133.dist-info}/WHEEL +1 -1
  105. rem/sql/002_install_models.sql +0 -1068
  106. rem/sql/install_models.sql +0 -1038
  107. {remdb-0.3.7.dist-info → remdb-0.3.133.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remdb
3
- Version: 0.3.7
3
+ Version: 0.3.133
4
4
  Summary: Resources Entities Moments - Bio-inspired memory system for agentic AI workloads
5
5
  Project-URL: Homepage, https://github.com/Percolation-Labs/reminiscent
6
6
  Project-URL: Documentation, https://github.com/Percolation-Labs/reminiscent/blob/main/README.md
@@ -23,11 +23,10 @@ Requires-Dist: click>=8.1.0
23
23
  Requires-Dist: fastapi>=0.115.0
24
24
  Requires-Dist: fastmcp>=0.5.0
25
25
  Requires-Dist: gitpython>=3.1.45
26
- Requires-Dist: gmft
27
26
  Requires-Dist: hypercorn>=0.17.0
28
27
  Requires-Dist: itsdangerous>=2.0.0
29
28
  Requires-Dist: json-schema-to-pydantic>=0.2.0
30
- Requires-Dist: kreuzberg>=3.21.0
29
+ Requires-Dist: kreuzberg<4.0.0,>=3.21.0
31
30
  Requires-Dist: loguru>=0.7.0
32
31
  Requires-Dist: openinference-instrumentation-pydantic-ai>=0.1.0
33
32
  Requires-Dist: opentelemetry-api>=1.28.0
@@ -48,7 +47,6 @@ Requires-Dist: requests>=2.32.0
48
47
  Requires-Dist: semchunk>=2.2.0
49
48
  Requires-Dist: tenacity>=9.0.0
50
49
  Requires-Dist: tiktoken>=0.5.0
51
- Requires-Dist: torch>=2.0.0
52
50
  Requires-Dist: uvicorn[standard]>=0.32.0
53
51
  Provides-Extra: all
54
52
  Requires-Dist: ipdb>=0.13.0; extra == 'all'
@@ -103,32 +101,30 @@ Cloud-native unified memory infrastructure for agentic AI systems built with Pyd
103
101
  - **Database Layer**: PostgreSQL 18 with pgvector for multi-index memory (KV + Vector + Graph)
104
102
  - **REM Query Dialect**: Custom query language with O(1) lookups, semantic search, graph traversal
105
103
  - **Ingestion & Dreaming**: Background workers for content extraction and progressive index enrichment (0% → 100% answerable)
106
- - **Observability & Evals**: OpenTelemetry tracing + Arize Phoenix + LLM-as-a-Judge evaluation framework
104
+ - **Observability & Evals**: OpenTelemetry tracing supporting LLM-as-a-Judge evaluation frameworks
107
105
 
108
106
  ## Features
109
107
 
110
108
  | Feature | Description | Benefits |
111
109
  |---------|-------------|----------|
112
110
  | **OpenAI-Compatible Chat API** | Drop-in replacement for OpenAI chat completions API with streaming support | Use with existing OpenAI clients, switch models across providers (OpenAI, Anthropic, etc.) |
113
- | **Built-in MCP Server** | FastMCP server with 4 tools + 3 resources for memory operations | Export memory to Claude Desktop, Cursor, or any MCP-compatible host |
111
+ | **Built-in MCP Server** | FastMCP server with 4 tools + 5 resources for memory operations | Export memory to Claude Desktop, Cursor, or any MCP-compatible host |
114
112
  | **REM Query Engine** | Multi-index query system (LOOKUP, FUZZY, SEARCH, SQL, TRAVERSE) with custom dialect | O(1) lookups, semantic search, graph traversal - all tenant-isolated |
115
113
  | **Dreaming Workers** | Background workers for entity extraction, moment generation, and affinity matching | Automatic knowledge graph construction from resources (0% → 100% query answerable) |
116
114
  | **PostgreSQL + pgvector** | CloudNativePG with PostgreSQL 18, pgvector extension, streaming replication | Production-ready vector search, no external vector DB needed |
117
115
  | **AWS EKS Recipe** | Complete infrastructure-as-code with Pulumi, Karpenter, ArgoCD | Deploy to production EKS in minutes with auto-scaling and GitOps |
118
116
  | **JSON Schema Agents** | Dynamic agent creation from YAML schemas via Pydantic AI factory | Define agents declaratively, version control schemas, load dynamically |
119
- | **Content Providers** | Audio transcription (Whisper), vision (GPT-4V, Claude), PDFs, DOCX, images | Multimodal ingestion out of the box with format detection |
120
- | **Configurable Embeddings** | Provider-agnostic embedding system (OpenAI, Cohere, Jina) | Switch embedding providers via env vars, no code changes |
117
+ | **Content Providers** | Audio transcription (Whisper), vision (OpenAI, Anthropic, Gemini), PDFs, DOCX, PPTX, XLSX, images | Multimodal ingestion out of the box with format detection |
118
+ | **Configurable Embeddings** | OpenAI embedding system (text-embedding-3-small) | Production-ready embeddings, additional providers planned |
121
119
  | **Multi-Tenancy** | Tenant isolation at database level with automatic scoping | SaaS-ready with complete data separation per tenant |
122
- | **Streaming Everything** | SSE for chat, background workers for embeddings, async throughout | Real-time responses, non-blocking operations, scalable |
123
120
  | **Zero Vendor Lock-in** | Raw HTTP clients (no OpenAI SDK), swappable providers, open standards | Not tied to any vendor, easy to migrate, full control |
124
121
 
125
122
  ## Quick Start
126
123
 
127
124
  Choose your path:
128
125
 
129
- - **Option 1: Package Users with Example Data** (Recommended for first-time users) - PyPI + example datasets
130
- - **Option 2: Package Users** (Recommended for non-developers) - PyPI package + dockerized database
131
- - **Option 3: Developers** - Clone repo, local development with uv
126
+ - **Option 1: Package Users with Example Data** (Recommended) - PyPI + example datasets
127
+ - **Option 2: Developers** - Clone repo, local development with uv
132
128
 
133
129
  ---
134
130
 
@@ -137,186 +133,78 @@ Choose your path:
137
133
  **Best for**: First-time users who want to explore REM with curated example datasets.
138
134
 
139
135
  ```bash
140
- # Install system dependencies
141
- # macOS:
142
- brew install tesseract
143
-
144
- # Linux:
145
- sudo apt-get install tesseract-ocr
136
+ # Install system dependencies (tesseract for OCR)
137
+ brew install tesseract # macOS (Linux/Windows: see tesseract-ocr.github.io)
146
138
 
147
139
  # Install remdb
148
- pip install remdb[all]
140
+ pip install "remdb[all]"
149
141
 
150
142
  # Clone example datasets
151
143
  git clone https://github.com/Percolation-Labs/remstack-lab.git
152
144
  cd remstack-lab
153
145
 
154
- # Configure REM (interactive wizard)
155
- rem configure --install
146
+ # Start PostgreSQL with docker-compose
147
+ curl -O https://gist.githubusercontent.com/percolating-sirsh/d117b673bc0edfdef1a5068ccd3cf3e5/raw/docker-compose.prebuilt.yml
148
+ docker compose -f docker-compose.prebuilt.yml up -d postgres
156
149
 
157
- # Start PostgreSQL
158
- docker run -d \
159
- --name rem-postgres \
160
- -e POSTGRES_USER=rem \
161
- -e POSTGRES_PASSWORD=rem \
162
- -e POSTGRES_DB=rem \
163
- -p 5050:5432 \
164
- pgvector/pgvector:pg18
150
+ # Configure REM (creates ~/.rem/config.yaml and installs database schema)
151
+ # Add --claude-desktop to register with Claude Desktop app
152
+ rem configure --install --claude-desktop
165
153
 
166
154
  # Load quickstart dataset
167
- rem db load datasets/quickstart/sample_data.yaml --user-id demo-user
168
-
169
- # Optional: Set default LLM provider via environment variable
170
- # export LLM__DEFAULT_MODEL="openai:gpt-4.1-nano" # Fast and cheap
171
- # export LLM__DEFAULT_MODEL="anthropic:claude-sonnet-4-5-20250929" # High quality (default)
155
+ rem db load datasets/quickstart/sample_data.yaml
172
156
 
173
157
  # Ask questions
174
- rem ask --user-id demo-user "What documents exist in the system?"
175
- rem ask --user-id demo-user "Show me meetings about API design"
158
+ rem ask "What documents exist in the system?"
159
+ rem ask "Show me meetings about API design"
176
160
 
177
- # Ingest files (PDF, DOCX, images, etc.) - note: requires remstack-lab
178
- rem process ingest datasets/formats/files/bitcoin_whitepaper.pdf --user-id demo-user --category research --tags bitcoin,whitepaper
161
+ # Ingest files (PDF, DOCX, images, etc.)
162
+ rem process ingest datasets/formats/files/bitcoin_whitepaper.pdf --category research --tags bitcoin,whitepaper
179
163
 
180
164
  # Query ingested content
181
- rem ask --user-id demo-user "What is the Bitcoin whitepaper about?"
182
-
183
- # Try other datasets
184
- rem db load --file datasets/domains/recruitment/scenarios/candidate_pipeline/data.yaml --user-id my-company
185
- rem ask --user-id my-company "Show me candidates with Python experience"
165
+ rem ask "What is the Bitcoin whitepaper about?"
186
166
  ```
187
167
 
188
168
  **What you get:**
189
169
  - Quickstart: 3 users, 3 resources, 3 moments, 4 messages
190
170
  - Domain datasets: recruitment, legal, enterprise, misc
191
171
  - Format examples: engrams, documents, conversations, files
192
- - Jupyter notebooks and experiments
193
172
 
194
173
  **Learn more**: [remstack-lab repository](https://github.com/Percolation-Labs/remstack-lab)
195
174
 
196
- ---
197
-
198
- ## Option 2: Package Users (No Example Data)
175
+ ### Using the API
199
176
 
200
- **Best for**: Using REM as a service (API + CLI) without modifying code, bringing your own data.
201
-
202
- ### Step 1: Start Database and API with Docker Compose
177
+ Once configured, you can also use the OpenAI-compatible chat completions API:
203
178
 
204
179
  ```bash
205
- # Create a project directory
206
- mkdir my-rem-project && cd my-rem-project
207
-
208
- # Download docker-compose file from public gist
209
- curl -O https://gist.githubusercontent.com/percolating-sirsh/d117b673bc0edfdef1a5068ccd3cf3e5/raw/docker-compose.prebuilt.yml
210
-
211
- # IMPORTANT: Export API keys BEFORE running docker compose
212
- # Docker Compose reads env vars at startup - exporting them after won't work!
213
-
214
- # Required: OpenAI for embeddings (text-embedding-3-small)
215
- export OPENAI_API_KEY="sk-..."
216
-
217
- # Recommended: At least one chat completion provider
218
- export ANTHROPIC_API_KEY="sk-ant-..." # Claude Sonnet 4.5 (high quality)
219
- export CEREBRAS_API_KEY="csk-..." # Cerebras (fast, cheap inference)
220
-
221
- # Start PostgreSQL + API
180
+ # Start the API server (if not using docker-compose for API)
222
181
  docker compose -f docker-compose.prebuilt.yml up -d
223
182
 
224
- # Verify services are running
225
- curl http://localhost:8000/health
226
- ```
227
-
228
- This starts:
229
- - **PostgreSQL** with pgvector on port **5051** (connection: `postgresql://rem:rem@localhost:5051/rem`)
230
- - **REM API** on port **8000** with OpenAI-compatible chat completions + MCP server
231
- - Uses pre-built Docker image from Docker Hub (no local build required)
232
-
233
- ### Step 2: Install and Configure CLI (REQUIRED)
234
-
235
- **This step is required** before you can use REM - it installs the database schema and configures your LLM API keys.
236
-
237
- ```bash
238
- # Install remdb package from PyPI
239
- pip install remdb[all]
240
-
241
- # Configure REM (defaults to port 5051 for package users)
242
- rem configure --install --claude-desktop
183
+ # Test the API
184
+ curl -X POST http://localhost:8000/api/v1/chat/completions \
185
+ -H "Content-Type: application/json" \
186
+ -H "X-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
187
+ -d '{
188
+ "model": "anthropic:claude-sonnet-4-5-20250929",
189
+ "messages": [{"role": "user", "content": "What documents did Sarah Chen author?"}],
190
+ "stream": false
191
+ }'
243
192
  ```
244
193
 
245
- The interactive wizard will:
246
- 1. **Configure PostgreSQL**: Defaults to `postgresql://rem:rem@localhost:5051/rem` (prebuilt docker-compose)
247
- - Just press Enter to accept defaults
248
- - Custom database: Enter your own host/port/credentials
249
- 2. **Configure LLM providers**: Enter your OpenAI/Anthropic API keys
250
- 3. **Install database tables**: Creates schema, functions, indexes (**required for CLI/API to work**)
251
- 4. **Register with Claude Desktop**: Adds REM MCP server to Claude
252
-
253
- Configuration saved to `~/.rem/config.yaml` (can edit with `rem configure --edit`)
254
-
255
194
  **Port Guide:**
256
195
  - **5051**: Package users with `docker-compose.prebuilt.yml` (pre-built image)
257
196
  - **5050**: Developers with `docker-compose.yml` (local build)
258
- - **Custom**: Your own PostgreSQL database
259
197
 
260
198
  **Next Steps:**
261
199
  - See [CLI Reference](#cli-reference) for all available commands
262
200
  - See [REM Query Dialect](#rem-query-dialect) for query examples
263
201
  - See [API Endpoints](#api-endpoints) for OpenAI-compatible API usage
264
202
 
265
- ### Step 3: Load Sample Data (Optional but Recommended)
266
-
267
- **Option A: Clone example datasets** (Recommended - works with all README examples)
268
-
269
- ```bash
270
- # Clone datasets repository
271
- git clone https://github.com/Percolation-Labs/remstack-lab.git
272
-
273
- # Load quickstart dataset
274
- rem db load --file remstack-lab/datasets/quickstart/sample_data.yaml --user-id demo-user
275
-
276
- # Test with sample queries
277
- rem ask --user-id demo-user "What documents exist in the system?"
278
- rem ask --user-id demo-user "Show me meetings about API design"
279
- rem ask --user-id demo-user "Who is Sarah Chen?"
280
-
281
- # Try domain-specific datasets
282
- rem db load --file remstack-lab/datasets/domains/recruitment/scenarios/candidate_pipeline/data.yaml --user-id my-company
283
- rem ask --user-id my-company "Show me candidates with Python experience"
284
- ```
285
-
286
- **Option B: Bring your own data**
287
-
288
- ```bash
289
- # Ingest your own files
290
- echo "REM is a bio-inspired memory system for agentic AI workloads." > test-doc.txt
291
- rem process ingest test-doc.txt --user-id test-user --category documentation --tags rem,ai
292
-
293
- # Query your ingested data
294
- rem ask --user-id test-user "What do you know about REM from my knowledge base?"
295
- ```
296
-
297
- ### Step 4: Test the API
298
-
299
- ```bash
300
- # Test the OpenAI-compatible chat completions API
301
- curl -X POST http://localhost:8000/api/v1/chat/completions \
302
- -H "Content-Type: application/json" \
303
- -H "X-User-Id: demo-user" \
304
- -d '{
305
- "model": "anthropic:claude-sonnet-4-5-20250929",
306
- "messages": [{"role": "user", "content": "What documents did Sarah Chen author?"}],
307
- "stream": false
308
- }'
309
- ```
310
-
311
- **Available Commands:**
312
- - `rem ask` - Natural language queries to REM
313
- - `rem process ingest <file>` - Full ingestion pipeline (storage + parsing + embedding + database)
314
- - `rem process uri <file>` - READ-ONLY parsing (no database storage, useful for testing parsers)
315
- - `rem db load --file <yaml>` - Load structured datasets directly
203
+ ---
316
204
 
317
205
  ## Example Datasets
318
206
 
319
- 🎯 **Recommended**: Clone [remstack-lab](https://github.com/Percolation-Labs/remstack-lab) for curated datasets organized by domain and format.
207
+ Clone [remstack-lab](https://github.com/Percolation-Labs/remstack-lab) for curated datasets organized by domain and format.
320
208
 
321
209
  **What's included:**
322
210
  - **Quickstart**: Minimal dataset (3 users, 3 resources, 3 moments) - perfect for first-time users
@@ -329,13 +217,10 @@ curl -X POST http://localhost:8000/api/v1/chat/completions \
329
217
  cd remstack-lab
330
218
 
331
219
  # Load any dataset
332
- rem db load --file datasets/quickstart/sample_data.yaml --user-id demo-user
220
+ rem db load --file datasets/quickstart/sample_data.yaml
333
221
 
334
222
  # Explore formats
335
- rem db load --file datasets/formats/engrams/scenarios/team_meeting/team_standup_meeting.yaml --user-id demo-user
336
-
337
- # Try domain-specific examples
338
- rem db load --file datasets/domains/recruitment/scenarios/candidate_pipeline/data.yaml --user-id acme-corp
223
+ rem db load --file datasets/formats/engrams/scenarios/team_meeting/team_standup_meeting.yaml
339
224
  ```
340
225
 
341
226
  ## See Also
@@ -429,30 +314,24 @@ json_schema_extra:
429
314
  ```bash
430
315
  # Ingest the schema (stores in database schemas table)
431
316
  rem process ingest my-research-assistant.yaml \
432
- --user-id my-user \
433
317
  --category agents \
434
318
  --tags custom,research
435
319
 
436
320
  # Verify schema is in database (should show schema details)
437
- rem ask "LOOKUP 'my-research-assistant' FROM schemas" --user-id my-user
321
+ rem ask "LOOKUP 'my-research-assistant' FROM schemas"
438
322
  ```
439
323
 
440
324
  **Step 3: Use Your Custom Agent**
441
325
 
442
326
  ```bash
443
327
  # Run a query with your custom agent
444
- rem ask research-assistant "Find documents about machine learning architecture" \
445
- --user-id my-user
328
+ rem ask research-assistant "Find documents about machine learning architecture"
446
329
 
447
330
  # With streaming
448
- rem ask research-assistant "Summarize recent API design documents" \
449
- --user-id my-user \
450
- --stream
331
+ rem ask research-assistant "Summarize recent API design documents" --stream
451
332
 
452
333
  # With session continuity
453
- rem ask research-assistant "What did we discuss about ML?" \
454
- --user-id my-user \
455
- --session-id abc-123
334
+ rem ask research-assistant "What did we discuss about ML?" --session-id c3d4e5f6-a7b8-9012-cdef-345678901234
456
335
  ```
457
336
 
458
337
  ### Agent Schema Structure
@@ -495,38 +374,25 @@ REM provides **4 built-in MCP tools** your agents can use:
495
374
 
496
375
  ### Multi-User Isolation
497
376
 
498
- Custom agents are **scoped by `user_id`**, ensuring complete data isolation:
377
+ For multi-tenant deployments, custom agents are **scoped by `user_id`**, ensuring complete data isolation. Use `--user-id` flag when you need tenant separation:
499
378
 
500
379
  ```bash
501
- # User A creates a custom agent
502
- rem process ingest my-agent.yaml --user-id user-a --category agents
380
+ # Create agent for specific tenant
381
+ rem process ingest my-agent.yaml --user-id tenant-a --category agents
503
382
 
504
- # User B cannot see User A's agent
505
- rem ask my-agent "test" --user-id user-b
506
- # ❌ Error: Schema not found (LOOKUP returns no results for user-b)
507
-
508
- # User A can use their agent
509
- rem ask my-agent "test" --user-id user-a
510
- # ✅ Works - LOOKUP finds schema for user-a
383
+ # Query with tenant context
384
+ rem ask my-agent "test" --user-id tenant-a
511
385
  ```
512
386
 
513
- ### Advanced: Ontology Extractors
514
-
515
- Custom agents can also be used as **ontology extractors** to extract structured knowledge from files. See [CLAUDE.md](../CLAUDE.md#ontology-extraction-pattern) for details on:
516
- - Multi-provider testing (`provider_configs`)
517
- - Semantic search configuration (`embedding_fields`)
518
- - File matching rules (`OntologyConfig`)
519
- - Dreaming workflow integration
520
-
521
387
  ### Troubleshooting
522
388
 
523
389
  **Schema not found error:**
524
390
  ```bash
525
391
  # Check if schema was ingested correctly
526
- rem ask "SEARCH 'my-agent' FROM schemas" --user-id my-user
392
+ rem ask "SEARCH 'my-agent' FROM schemas"
527
393
 
528
- # List all schemas for your user
529
- rem ask "SELECT name, category, created_at FROM schemas ORDER BY created_at DESC LIMIT 10" --user-id my-user
394
+ # List all schemas
395
+ rem ask "SELECT name, category, created_at FROM schemas ORDER BY created_at DESC LIMIT 10"
530
396
  ```
531
397
 
532
398
  **Agent not loading tools:**
@@ -551,15 +417,15 @@ REM provides a custom query language designed for **LLM-driven iterated retrieva
551
417
  Unlike traditional single-shot SQL queries, the REM dialect is optimized for **multi-turn exploration** where LLMs participate in query planning:
552
418
 
553
419
  - **Iterated Queries**: Queries return partial results that LLMs use to refine subsequent queries
554
- - **Composable WITH Syntax**: Chain operations together (e.g., `TRAVERSE FROM ... WITH LOOKUP "..."`)
420
+ - **Composable WITH Syntax**: Chain operations together (e.g., `TRAVERSE edge_type WITH LOOKUP "..."`)
555
421
  - **Mixed Indexes**: Combines exact lookups (O(1)), semantic search (vector), and graph traversal
556
422
  - **Query Planner Participation**: Results include metadata for LLMs to decide next steps
557
423
 
558
424
  **Example Multi-Turn Flow**:
559
425
  ```
560
426
  Turn 1: LOOKUP "sarah-chen" → Returns entity + available edge types
561
- Turn 2: TRAVERSE FROM "sarah-chen" TYPE "authored_by" DEPTH 1 → Returns connected documents
562
- Turn 3: SEARCH "architecture decisions" WITH TRAVERSE FROM "sarah-chen" Combines semantic + graph
427
+ Turn 2: TRAVERSE authored_by WITH LOOKUP "sarah-chen" DEPTH 1 → Returns connected documents
428
+ Turn 3: SEARCH "architecture decisions" Semantic search, then explore graph from results
563
429
  ```
564
430
 
565
431
  This enables LLMs to **progressively build context** rather than requiring perfect queries upfront.
@@ -612,8 +478,8 @@ SEARCH "contract disputes" FROM resources WHERE tags @> ARRAY['legal'] LIMIT 5
612
478
  Follow `graph_edges` relationships across the knowledge graph.
613
479
 
614
480
  ```sql
615
- TRAVERSE FROM "sarah-chen" TYPE "authored_by" DEPTH 2
616
- TRAVERSE FROM "api-design-v2" TYPE "references,depends_on" DEPTH 3
481
+ TRAVERSE authored_by WITH LOOKUP "sarah-chen" DEPTH 2
482
+ TRAVERSE references,depends_on WITH LOOKUP "api-design-v2" DEPTH 3
617
483
  ```
618
484
 
619
485
  **Features**:
@@ -706,7 +572,7 @@ SEARCH "API migration planning" FROM resources LIMIT 5
706
572
  LOOKUP "tidb-migration-spec" FROM resources
707
573
 
708
574
  # Query 3: Find related people
709
- TRAVERSE FROM "tidb-migration-spec" TYPE "authored_by,reviewed_by" DEPTH 1
575
+ TRAVERSE authored_by,reviewed_by WITH LOOKUP "tidb-migration-spec" DEPTH 1
710
576
 
711
577
  # Query 4: Recent activity
712
578
  SELECT * FROM moments WHERE
@@ -723,7 +589,7 @@ All queries automatically scoped by `user_id` for complete data isolation:
723
589
  SEARCH "contracts" FROM resources LIMIT 10
724
590
 
725
591
  -- No cross-user data leakage
726
- TRAVERSE FROM "project-x" TYPE "references" DEPTH 3
592
+ TRAVERSE references WITH LOOKUP "project-x" DEPTH 3
727
593
  ```
728
594
 
729
595
  ## API Endpoints
@@ -735,8 +601,8 @@ POST /api/v1/chat/completions
735
601
  ```
736
602
 
737
603
  **Headers**:
738
- - `X-Tenant-Id`: Tenant identifier (required for REM)
739
- - `X-User-Id`: User identifier
604
+ - `X-User-Id`: User identifier (required for data isolation, uses default if not provided)
605
+ - `X-Tenant-Id`: Deprecated - use `X-User-Id` instead (kept for backwards compatibility)
740
606
  - `X-Session-Id`: Session/conversation identifier
741
607
  - `X-Agent-Schema`: Agent schema URI to use
742
608
 
@@ -875,81 +741,144 @@ rem serve --log-level debug
875
741
 
876
742
  ### Database Management
877
743
 
878
- #### `rem db migrate` - Run Migrations
744
+ REM uses a **code-as-source-of-truth** approach for database schema management. Pydantic models define the schema, and the database is kept in sync via diff-based migrations.
879
745
 
880
- Apply database migrations (install.sql and install_models.sql).
746
+ #### Schema Management Philosophy
747
+
748
+ **Two migration files only:**
749
+ - `001_install.sql` - Core infrastructure (extensions, functions, KV store)
750
+ - `002_install_models.sql` - Entity tables (auto-generated from Pydantic models)
751
+
752
+ **No incremental migrations** (003, 004, etc.) - the models file is always regenerated to match code.
753
+
754
+ #### `rem db schema generate` - Regenerate Schema SQL
755
+
756
+ Generate `002_install_models.sql` from registered Pydantic models.
881
757
 
882
758
  ```bash
883
- # Apply all migrations
884
- rem db migrate
759
+ # Regenerate from model registry
760
+ rem db schema generate
761
+
762
+ # Output: src/rem/sql/migrations/002_install_models.sql
763
+ ```
885
764
 
886
- # Core infrastructure only (extensions, functions)
887
- rem db migrate --install
765
+ This generates:
766
+ - CREATE TABLE statements for each registered entity
767
+ - Embeddings tables (`embeddings_<table>`)
768
+ - KV_STORE triggers for cache maintenance
769
+ - Foreground indexes (GIN for JSONB, B-tree for lookups)
888
770
 
889
- # Entity tables only (Resource, Message, etc.)
890
- rem db migrate --models
771
+ #### `rem db diff` - Detect Schema Drift
891
772
 
892
- # Background indexes (HNSW for vectors)
893
- rem db migrate --background-indexes
773
+ Compare Pydantic models against the live database using Alembic autogenerate.
774
+
775
+ ```bash
776
+ # Show additive changes only (default, safe for production)
777
+ rem db diff
778
+
779
+ # Show all changes including drops
780
+ rem db diff --strategy full
781
+
782
+ # Show additive + safe type widenings
783
+ rem db diff --strategy safe
894
784
 
895
- # Custom connection string
896
- rem db migrate --connection "postgresql://user:pass@host:5432/db"
785
+ # CI mode: exit 1 if drift detected
786
+ rem db diff --check
897
787
 
898
- # Custom SQL directory
899
- rem db migrate --sql-dir /path/to/sql
788
+ # Generate migration SQL for changes
789
+ rem db diff --generate
900
790
  ```
901
791
 
902
- #### `rem db status` - Migration Status
792
+ **Migration Strategies:**
793
+ | Strategy | Description |
794
+ |----------|-------------|
795
+ | `additive` | Only ADD columns/tables/indexes (safe, no data loss) - **default** |
796
+ | `full` | All changes including DROPs (use with caution) |
797
+ | `safe` | Additive + safe column type widenings (e.g., VARCHAR(50) → VARCHAR(256)) |
903
798
 
904
- Show applied migrations and execution times.
799
+ **Output shows:**
800
+ - `+ ADD COLUMN` - Column in model but not in DB
801
+ - `- DROP COLUMN` - Column in DB but not in model (only with `--strategy full`)
802
+ - `~ ALTER COLUMN` - Column type or constraints differ
803
+ - `+ CREATE TABLE` / `- DROP TABLE` - Table additions/removals
804
+
805
+ #### `rem db apply` - Apply SQL Directly
806
+
807
+ Apply a SQL file directly to the database (bypasses migration tracking).
905
808
 
906
809
  ```bash
907
- rem db status
810
+ # Apply with audit logging (default)
811
+ rem db apply src/rem/sql/migrations/002_install_models.sql
812
+
813
+ # Preview without executing
814
+ rem db apply --dry-run src/rem/sql/migrations/002_install_models.sql
815
+
816
+ # Apply without audit logging
817
+ rem db apply --no-log src/rem/sql/migrations/002_install_models.sql
908
818
  ```
909
819
 
910
- #### `rem db rebuild-cache` - Rebuild KV Cache
820
+ #### `rem db migrate` - Initial Setup
911
821
 
912
- Rebuild KV_STORE cache from entity tables (after database restart or bulk imports).
822
+ Apply standard migrations (001 + 002). Use for initial setup only.
913
823
 
914
824
  ```bash
915
- rem db rebuild-cache
825
+ # Apply infrastructure + entity tables
826
+ rem db migrate
827
+
828
+ # Include background indexes (HNSW for vectors)
829
+ rem db migrate --background-indexes
916
830
  ```
917
831
 
918
- ### Schema Management
832
+ #### Database Workflows
919
833
 
920
- #### `rem db schema generate` - Generate SQL Schema
834
+ **Initial Setup (Local):**
835
+ ```bash
836
+ rem db schema generate # Generate from models
837
+ rem db migrate # Apply 001 + 002
838
+ rem db diff # Verify no drift
839
+ ```
921
840
 
922
- Generate database schema from Pydantic models.
841
+ **Adding/Modifying Models:**
842
+ ```bash
843
+ # 1. Edit models in src/rem/models/entities/
844
+ # 2. Register new models in src/rem/registry.py
845
+ rem db schema generate # Regenerate schema
846
+ rem db diff # See what changed
847
+ rem db apply src/rem/sql/migrations/002_install_models.sql
848
+ ```
849
+
850
+ **CI/CD Pipeline:**
851
+ ```bash
852
+ rem db diff --check # Fail build if drift detected
853
+ ```
923
854
 
855
+ **Remote Database (Production/Staging):**
924
856
  ```bash
925
- # Generate install_models.sql from entity models
926
- rem db schema generate \
927
- --models src/rem/models/entities \
928
- --output rem/src/rem/sql/install_models.sql
857
+ # Port-forward to cluster database
858
+ kubectl port-forward -n <namespace> svc/rem-postgres-rw 5433:5432 &
859
+
860
+ # Override connection for diff check
861
+ POSTGRES__CONNECTION_STRING="postgresql://rem:rem@localhost:5433/rem" rem db diff
929
862
 
930
- # Generate migration file
931
- rem db schema generate \
932
- --models src/rem/models/entities \
933
- --output rem/src/rem/sql/migrations/003_add_fields.sql
863
+ # Apply changes if needed
864
+ POSTGRES__CONNECTION_STRING="postgresql://rem:rem@localhost:5433/rem" \
865
+ rem db apply src/rem/sql/migrations/002_install_models.sql
934
866
  ```
935
867
 
936
- #### `rem db schema indexes` - Generate Background Indexes
868
+ #### `rem db rebuild-cache` - Rebuild KV Cache
937
869
 
938
- Generate SQL for background index creation (HNSW for vectors).
870
+ Rebuild KV_STORE cache from entity tables (after database restart or bulk imports).
939
871
 
940
872
  ```bash
941
- # Generate background_indexes.sql
942
- rem db schema indexes \
943
- --models src/rem/models/entities \
944
- --output rem/src/rem/sql/background_indexes.sql
873
+ rem db rebuild-cache
945
874
  ```
946
875
 
947
876
  #### `rem db schema validate` - Validate Models
948
877
 
949
- Validate Pydantic models for schema generation.
878
+ Validate registered Pydantic models for schema generation.
950
879
 
951
880
  ```bash
952
- rem db schema validate --models src/rem/models/entities
881
+ rem db schema validate
953
882
  ```
954
883
 
955
884
  ### File Processing
@@ -959,22 +888,14 @@ rem db schema validate --models src/rem/models/entities
959
888
  Process files with optional custom extractor (ontology extraction).
960
889
 
961
890
  ```bash
962
- # Process all completed files for tenant
963
- rem process files \
964
- --tenant-id acme-corp \
965
- --status completed \
966
- --limit 10
891
+ # Process all completed files
892
+ rem process files --status completed --limit 10
967
893
 
968
894
  # Process with custom extractor
969
- rem process files \
970
- --tenant-id acme-corp \
971
- --extractor cv-parser-v1 \
972
- --limit 50
895
+ rem process files --extractor cv-parser-v1 --limit 50
973
896
 
974
- # Process files from the last 7 days
975
- rem process files \
976
- --tenant-id acme-corp \
977
- --lookback-hours 168
897
+ # Process files for specific user
898
+ rem process files --user-id user-123 --status completed
978
899
  ```
979
900
 
980
901
  #### `rem process ingest` - Ingest File into REM
@@ -982,14 +903,13 @@ rem process files \
982
903
  Ingest a file into REM with full pipeline (storage + parsing + embedding + database).
983
904
 
984
905
  ```bash
985
- # Ingest local file
906
+ # Ingest local file with metadata
986
907
  rem process ingest /path/to/document.pdf \
987
- --user-id user-123 \
988
908
  --category legal \
989
909
  --tags contract,2024
990
910
 
991
911
  # Ingest with minimal options
992
- rem process ingest ./meeting-notes.md --user-id user-123
912
+ rem process ingest ./meeting-notes.md
993
913
  ```
994
914
 
995
915
  #### `rem process uri` - Parse File (Read-Only)
@@ -1014,28 +934,17 @@ rem process uri s3://bucket/key.docx --output text
1014
934
  Run full dreaming workflow: extractors → moments → affinity → user model.
1015
935
 
1016
936
  ```bash
1017
- # Full workflow for user
1018
- rem dreaming full \
1019
- --user-id user-123 \
1020
- --tenant-id acme-corp
937
+ # Full workflow (uses default user from settings)
938
+ rem dreaming full
1021
939
 
1022
940
  # Skip ontology extractors
1023
- rem dreaming full \
1024
- --user-id user-123 \
1025
- --tenant-id acme-corp \
1026
- --skip-extractors
941
+ rem dreaming full --skip-extractors
1027
942
 
1028
943
  # Process last 24 hours only
1029
- rem dreaming full \
1030
- --user-id user-123 \
1031
- --tenant-id acme-corp \
1032
- --lookback-hours 24
944
+ rem dreaming full --lookback-hours 24
1033
945
 
1034
- # Limit resources processed
1035
- rem dreaming full \
1036
- --user-id user-123 \
1037
- --tenant-id acme-corp \
1038
- --limit 100
946
+ # Limit resources processed for specific user
947
+ rem dreaming full --user-id user-123 --limit 100
1039
948
  ```
1040
949
 
1041
950
  #### `rem dreaming custom` - Custom Extractor
@@ -1043,16 +952,11 @@ rem dreaming full \
1043
952
  Run specific ontology extractor on user's data.
1044
953
 
1045
954
  ```bash
1046
- # Run CV parser on user's files
1047
- rem dreaming custom \
1048
- --user-id user-123 \
1049
- --tenant-id acme-corp \
1050
- --extractor cv-parser-v1
955
+ # Run CV parser on files
956
+ rem dreaming custom --extractor cv-parser-v1
1051
957
 
1052
- # Process last week's files
958
+ # Process last week's files with limit
1053
959
  rem dreaming custom \
1054
- --user-id user-123 \
1055
- --tenant-id acme-corp \
1056
960
  --extractor contract-analyzer-v1 \
1057
961
  --lookback-hours 168 \
1058
962
  --limit 50
@@ -1063,17 +967,11 @@ rem dreaming custom \
1063
967
  Extract temporal narratives from resources.
1064
968
 
1065
969
  ```bash
1066
- # Generate moments for user
1067
- rem dreaming moments \
1068
- --user-id user-123 \
1069
- --tenant-id acme-corp \
1070
- --limit 50
970
+ # Generate moments
971
+ rem dreaming moments --limit 50
1071
972
 
1072
973
  # Process last 7 days
1073
- rem dreaming moments \
1074
- --user-id user-123 \
1075
- --tenant-id acme-corp \
1076
- --lookback-hours 168
974
+ rem dreaming moments --lookback-hours 168
1077
975
  ```
1078
976
 
1079
977
  #### `rem dreaming affinity` - Build Relationships
@@ -1081,17 +979,11 @@ rem dreaming moments \
1081
979
  Build semantic relationships between resources using embeddings.
1082
980
 
1083
981
  ```bash
1084
- # Build affinity graph for user
1085
- rem dreaming affinity \
1086
- --user-id user-123 \
1087
- --tenant-id acme-corp \
1088
- --limit 100
982
+ # Build affinity graph
983
+ rem dreaming affinity --limit 100
1089
984
 
1090
985
  # Process recent resources only
1091
- rem dreaming affinity \
1092
- --user-id user-123 \
1093
- --tenant-id acme-corp \
1094
- --lookback-hours 24
986
+ rem dreaming affinity --lookback-hours 24
1095
987
  ```
1096
988
 
1097
989
  #### `rem dreaming user-model` - Update User Model
@@ -1100,9 +992,7 @@ Update user model from recent activity (preferences, interests, patterns).
1100
992
 
1101
993
  ```bash
1102
994
  # Update user model
1103
- rem dreaming user-model \
1104
- --user-id user-123 \
1105
- --tenant-id acme-corp
995
+ rem dreaming user-model
1106
996
  ```
1107
997
 
1108
998
  ### Evaluation & Experiments
@@ -1194,14 +1084,11 @@ Test Pydantic AI agent with natural language queries.
1194
1084
  # Ask a question
1195
1085
  rem ask "What documents did Sarah Chen author?"
1196
1086
 
1197
- # With context headers
1198
- rem ask "Find all resources about API design" \
1199
- --user-id user-123 \
1200
- --tenant-id acme-corp
1201
-
1202
1087
  # Use specific agent schema
1203
- rem ask "Analyze this contract" \
1204
- --agent-schema contract-analyzer-v1
1088
+ rem ask contract-analyzer "Analyze this contract"
1089
+
1090
+ # Stream response
1091
+ rem ask "Find all resources about API design" --stream
1205
1092
  ```
1206
1093
 
1207
1094
  ### Global Options
@@ -1249,7 +1136,7 @@ export API__RELOAD=true
1249
1136
  rem serve
1250
1137
  ```
1251
1138
 
1252
- ## Development (For Contributors)
1139
+ ## Option 2: Development (For Contributors)
1253
1140
 
1254
1141
  **Best for**: Contributing to REM or customizing the codebase.
1255
1142
 
@@ -1353,6 +1240,30 @@ S3__BUCKET_NAME=rem-storage
1353
1240
  S3__REGION=us-east-1
1354
1241
  ```
1355
1242
 
1243
+ ### Building Docker Images
1244
+
1245
+ We tag Docker images with three labels for traceability:
1246
+ 1. `latest` - Always points to most recent build
1247
+ 2. `<git-sha>` - Short commit hash for exact version tracing
1248
+ 3. `<version>` - Semantic version from `pyproject.toml`
1249
+
1250
+ ```bash
1251
+ # Build and push multi-platform image to Docker Hub
1252
+ VERSION=$(grep '^version' pyproject.toml | cut -d'"' -f2) && \
1253
+ docker buildx build --platform linux/amd64,linux/arm64 \
1254
+ -t percolationlabs/rem:latest \
1255
+ -t percolationlabs/rem:$(git rev-parse --short HEAD) \
1256
+ -t percolationlabs/rem:$VERSION \
1257
+ --push \
1258
+ -f Dockerfile .
1259
+
1260
+ # Load locally for testing (single platform, no push)
1261
+ docker buildx build --platform linux/arm64 \
1262
+ -t percolationlabs/rem:latest \
1263
+ --load \
1264
+ -f Dockerfile .
1265
+ ```
1266
+
1356
1267
  ### Production Deployment (Optional)
1357
1268
 
1358
1269
  For production deployment to AWS EKS with Kubernetes, see the main repository README:
@@ -1468,6 +1379,252 @@ TraverseQuery ::= TRAVERSE [<edge_types:list>] WITH <initial_query:Query> [DEPTH
1468
1379
 
1469
1380
  **Stage 4** (100% answerable): Mature graph with rich historical data. All query types fully functional with high-quality results.
1470
1381
 
1382
+ ## Troubleshooting
1383
+
1384
+ ### Apple Silicon Mac: "Failed to build kreuzberg" Error
1385
+
1386
+ **Problem**: Installation fails with `ERROR: Failed building wheel for kreuzberg` on Apple Silicon Macs.
1387
+
1388
+ **Root Cause**: REM uses `kreuzberg>=4.0.0rc1` for document parsing with native ONNX/Rust table extraction. Kreuzberg 4.0.0rc1 provides pre-built wheels for ARM64 macOS (`macosx_14_0_arm64.whl`) but NOT for x86_64 (Intel) macOS. If you're using an x86_64 Python binary (running under Rosetta 2), pip cannot find a compatible wheel and attempts to build from source, which fails.
1389
+
1390
+ **Solution**: Use ARM64 (native) Python instead of x86_64 Python.
1391
+
1392
+ **Step 1: Verify your Python architecture**
1393
+
1394
+ ```bash
1395
+ python3 -c "import platform; print(f'Machine: {platform.machine()}')"
1396
+ ```
1397
+
1398
+ - **Correct**: `Machine: arm64` (native ARM Python)
1399
+ - **Wrong**: `Machine: x86_64` (Intel Python under Rosetta)
1400
+
1401
+ **Step 2: Install ARM Python via Homebrew** (if not already installed)
1402
+
1403
+ ```bash
1404
+ # Install ARM Python
1405
+ brew install python@3.12
1406
+
1407
+ # Verify it's ARM
1408
+ /opt/homebrew/bin/python3.12 -c "import platform; print(platform.machine())"
1409
+ # Should output: arm64
1410
+ ```
1411
+
1412
+ **Step 3: Create venv with ARM Python**
1413
+
1414
+ ```bash
1415
+ # Use full path to ARM Python
1416
+ /opt/homebrew/bin/python3.12 -m venv .venv
1417
+
1418
+ # Activate and install
1419
+ source .venv/bin/activate
1420
+ pip install "remdb[all]"
1421
+ ```
1422
+
1423
+ **Why This Happens**: Some users have both Intel Homebrew (`/usr/local`) and ARM Homebrew (`/opt/homebrew`) installed. If your system `python3` points to the Intel version at `/usr/local/bin/python3`, you'll hit this issue. The fix is to explicitly use the ARM Python from `/opt/homebrew/bin/python3.12`.
1424
+
1425
+ **Verification**: After successful installation, you should see:
1426
+ ```
1427
+ Using cached kreuzberg-4.0.0rc1-cp310-abi3-macosx_14_0_arm64.whl (19.8 MB)
1428
+ Successfully installed ... kreuzberg-4.0.0rc1 ... remdb-0.3.10
1429
+ ```
1430
+
1431
+ ## Using REM as a Library
1432
+
1433
+ REM wraps FastAPI - extend it exactly as you would any FastAPI app.
1434
+
1435
+ ### Recommended Project Structure
1436
+
1437
+ REM auto-detects `./agents/` and `./models/` folders - no configuration needed:
1438
+
1439
+ ```
1440
+ my-rem-app/
1441
+ ├── agents/ # Auto-detected for agent schemas
1442
+ │ ├── my-agent.yaml # Custom agent (rem ask my-agent "query")
1443
+ │ └── another-agent.yaml
1444
+ ├── models/ # Auto-detected if __init__.py exists
1445
+ │ └── __init__.py # Register models with @rem.register_model
1446
+ ├── routers/ # Custom FastAPI routers
1447
+ │ └── custom.py
1448
+ ├── main.py # Entry point
1449
+ └── pyproject.toml
1450
+ ```
1451
+
1452
+ ### Quick Start
1453
+
1454
+ ```python
1455
+ # main.py
1456
+ from rem import create_app
1457
+ from fastapi import APIRouter
1458
+
1459
+ # Create REM app (auto-detects ./agents/ and ./models/)
1460
+ app = create_app()
1461
+
1462
+ # Add custom router
1463
+ router = APIRouter(prefix="/custom", tags=["custom"])
1464
+
1465
+ @router.get("/hello")
1466
+ async def hello():
1467
+ return {"message": "Hello from custom router!"}
1468
+
1469
+ app.include_router(router)
1470
+
1471
+ # Add custom MCP tool
1472
+ @app.mcp_server.tool()
1473
+ async def my_tool(query: str) -> dict:
1474
+ """Custom MCP tool available to agents."""
1475
+ return {"result": query}
1476
+ ```
1477
+
1478
+ ### Custom Models (Auto-Detected)
1479
+
1480
+ ```python
1481
+ # models/__init__.py
1482
+ import rem
1483
+ from rem.models.core import CoreModel
1484
+ from pydantic import Field
1485
+
1486
+ @rem.register_model
1487
+ class MyEntity(CoreModel):
1488
+ """Custom entity - auto-registered for schema generation."""
1489
+ name: str = Field(description="Entity name")
1490
+ status: str = Field(default="active")
1491
+ ```
1492
+
1493
+ Run `rem db schema generate` to include your models in the database schema.
1494
+
1495
+ ### Custom Agents (Auto-Detected)
1496
+
1497
+ ```yaml
1498
+ # agents/my-agent.yaml
1499
+ type: object
1500
+ description: |
1501
+ You are a helpful assistant that...
1502
+
1503
+ properties:
1504
+ answer:
1505
+ type: string
1506
+ description: Your response
1507
+
1508
+ required:
1509
+ - answer
1510
+
1511
+ json_schema_extra:
1512
+ kind: agent
1513
+ name: my-agent
1514
+ version: "1.0.0"
1515
+ tools:
1516
+ - search_rem
1517
+ ```
1518
+
1519
+ Test with: `rem ask my-agent "Hello!"`
1520
+
1521
+ ### Example Custom Router
1522
+
1523
+ ```python
1524
+ # routers/analytics.py
1525
+ from fastapi import APIRouter, Depends
1526
+ from rem.services.postgres import get_postgres_service
1527
+
1528
+ router = APIRouter(prefix="/analytics", tags=["analytics"])
1529
+
1530
+ @router.get("/stats")
1531
+ async def get_stats():
1532
+ """Get database statistics."""
1533
+ db = get_postgres_service()
1534
+ if not db:
1535
+ return {"error": "Database not available"}
1536
+
1537
+ await db.connect()
1538
+ try:
1539
+ result = await db.execute(
1540
+ "SELECT COUNT(*) as count FROM resources"
1541
+ )
1542
+ return {"resource_count": result[0]["count"]}
1543
+ finally:
1544
+ await db.disconnect()
1545
+
1546
+ @router.get("/recent")
1547
+ async def get_recent(limit: int = 10):
1548
+ """Get recent resources."""
1549
+ db = get_postgres_service()
1550
+ if not db:
1551
+ return {"error": "Database not available"}
1552
+
1553
+ await db.connect()
1554
+ try:
1555
+ result = await db.execute(
1556
+ f"SELECT label, category, created_at FROM resources ORDER BY created_at DESC LIMIT {limit}"
1557
+ )
1558
+ return {"resources": result}
1559
+ finally:
1560
+ await db.disconnect()
1561
+ ```
1562
+
1563
+ Include in main.py:
1564
+
1565
+ ```python
1566
+ from routers.analytics import router as analytics_router
1567
+ app.include_router(analytics_router)
1568
+ ```
1569
+
1570
+ ### Running the App
1571
+
1572
+ ```bash
1573
+ # Development (auto-reload)
1574
+ uv run uvicorn main:app --reload --port 8000
1575
+
1576
+ # Or use rem serve
1577
+ uv run rem serve --reload
1578
+
1579
+ # Test agent
1580
+ uv run rem ask my-agent "What can you help me with?"
1581
+
1582
+ # Test custom endpoint
1583
+ curl http://localhost:8000/analytics/stats
1584
+ ```
1585
+
1586
+ ### Extension Points
1587
+
1588
+ | Extension | How |
1589
+ |-----------|-----|
1590
+ | **Routes** | `app.include_router(router)` or `@app.get()` |
1591
+ | **MCP Tools** | `@app.mcp_server.tool()` decorator or `app.mcp_server.add_tool(fn)` |
1592
+ | **MCP Resources** | `@app.mcp_server.resource("uri://...")` or `app.mcp_server.add_resource(fn)` |
1593
+ | **MCP Prompts** | `@app.mcp_server.prompt()` or `app.mcp_server.add_prompt(fn)` |
1594
+ | **Models** | `rem.register_models(Model)` then `rem db schema generate` |
1595
+ | **Agent Schemas** | `rem.register_schema_path("./schemas")` or `SCHEMA__PATHS` env var |
1596
+ | **SQL Migrations** | Place in `sql/migrations/` (auto-detected) |
1597
+
1598
+ ### Custom Migrations
1599
+
1600
+ REM automatically discovers migrations from two sources:
1601
+
1602
+ 1. **Package migrations** (001-099): Built-in migrations from the `remdb` package
1603
+ 2. **User migrations** (100+): Your custom migrations in `./sql/migrations/`
1604
+
1605
+ **Convention**: Place custom SQL files in `sql/migrations/` relative to your project root:
1606
+
1607
+ ```
1608
+ my-rem-app/
1609
+ ├── sql/
1610
+ │ └── migrations/
1611
+ │ ├── 100_custom_table.sql # Runs after package migrations
1612
+ │ ├── 101_add_indexes.sql
1613
+ │ └── 102_custom_functions.sql
1614
+ └── ...
1615
+ ```
1616
+
1617
+ **Numbering**: Use 100+ for user migrations to ensure they run after package migrations (001-099). All migrations are sorted by filename, so proper numbering ensures correct execution order.
1618
+
1619
+ **Running migrations**:
1620
+ ```bash
1621
+ # Apply all migrations (package + user)
1622
+ rem db migrate
1623
+
1624
+ # Apply with background indexes (for production)
1625
+ rem db migrate --background-indexes
1626
+ ```
1627
+
1471
1628
  ## License
1472
1629
 
1473
1630
  MIT