remdb 0.2.6__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.

Potentially problematic release.


This version of remdb might be problematic. Click here for more details.

Files changed (187) hide show
  1. rem/__init__.py +2 -0
  2. rem/agentic/README.md +650 -0
  3. rem/agentic/__init__.py +39 -0
  4. rem/agentic/agents/README.md +155 -0
  5. rem/agentic/agents/__init__.py +8 -0
  6. rem/agentic/context.py +148 -0
  7. rem/agentic/context_builder.py +329 -0
  8. rem/agentic/mcp/__init__.py +0 -0
  9. rem/agentic/mcp/tool_wrapper.py +107 -0
  10. rem/agentic/otel/__init__.py +5 -0
  11. rem/agentic/otel/setup.py +151 -0
  12. rem/agentic/providers/phoenix.py +674 -0
  13. rem/agentic/providers/pydantic_ai.py +572 -0
  14. rem/agentic/query.py +117 -0
  15. rem/agentic/query_helper.py +89 -0
  16. rem/agentic/schema.py +396 -0
  17. rem/agentic/serialization.py +245 -0
  18. rem/agentic/tools/__init__.py +5 -0
  19. rem/agentic/tools/rem_tools.py +231 -0
  20. rem/api/README.md +420 -0
  21. rem/api/main.py +324 -0
  22. rem/api/mcp_router/prompts.py +182 -0
  23. rem/api/mcp_router/resources.py +536 -0
  24. rem/api/mcp_router/server.py +213 -0
  25. rem/api/mcp_router/tools.py +584 -0
  26. rem/api/routers/auth.py +229 -0
  27. rem/api/routers/chat/__init__.py +5 -0
  28. rem/api/routers/chat/completions.py +281 -0
  29. rem/api/routers/chat/json_utils.py +76 -0
  30. rem/api/routers/chat/models.py +124 -0
  31. rem/api/routers/chat/streaming.py +185 -0
  32. rem/auth/README.md +258 -0
  33. rem/auth/__init__.py +26 -0
  34. rem/auth/middleware.py +100 -0
  35. rem/auth/providers/__init__.py +13 -0
  36. rem/auth/providers/base.py +376 -0
  37. rem/auth/providers/google.py +163 -0
  38. rem/auth/providers/microsoft.py +237 -0
  39. rem/cli/README.md +455 -0
  40. rem/cli/__init__.py +8 -0
  41. rem/cli/commands/README.md +126 -0
  42. rem/cli/commands/__init__.py +3 -0
  43. rem/cli/commands/ask.py +565 -0
  44. rem/cli/commands/configure.py +423 -0
  45. rem/cli/commands/db.py +493 -0
  46. rem/cli/commands/dreaming.py +324 -0
  47. rem/cli/commands/experiments.py +1124 -0
  48. rem/cli/commands/mcp.py +66 -0
  49. rem/cli/commands/process.py +245 -0
  50. rem/cli/commands/schema.py +183 -0
  51. rem/cli/commands/serve.py +106 -0
  52. rem/cli/dreaming.py +363 -0
  53. rem/cli/main.py +88 -0
  54. rem/config.py +237 -0
  55. rem/mcp_server.py +41 -0
  56. rem/models/core/__init__.py +49 -0
  57. rem/models/core/core_model.py +64 -0
  58. rem/models/core/engram.py +333 -0
  59. rem/models/core/experiment.py +628 -0
  60. rem/models/core/inline_edge.py +132 -0
  61. rem/models/core/rem_query.py +243 -0
  62. rem/models/entities/__init__.py +43 -0
  63. rem/models/entities/file.py +57 -0
  64. rem/models/entities/image_resource.py +88 -0
  65. rem/models/entities/message.py +35 -0
  66. rem/models/entities/moment.py +123 -0
  67. rem/models/entities/ontology.py +191 -0
  68. rem/models/entities/ontology_config.py +131 -0
  69. rem/models/entities/resource.py +95 -0
  70. rem/models/entities/schema.py +87 -0
  71. rem/models/entities/user.py +85 -0
  72. rem/py.typed +0 -0
  73. rem/schemas/README.md +507 -0
  74. rem/schemas/__init__.py +6 -0
  75. rem/schemas/agents/README.md +92 -0
  76. rem/schemas/agents/core/moment-builder.yaml +178 -0
  77. rem/schemas/agents/core/rem-query-agent.yaml +226 -0
  78. rem/schemas/agents/core/resource-affinity-assessor.yaml +99 -0
  79. rem/schemas/agents/core/simple-assistant.yaml +19 -0
  80. rem/schemas/agents/core/user-profile-builder.yaml +163 -0
  81. rem/schemas/agents/examples/contract-analyzer.yaml +317 -0
  82. rem/schemas/agents/examples/contract-extractor.yaml +134 -0
  83. rem/schemas/agents/examples/cv-parser.yaml +263 -0
  84. rem/schemas/agents/examples/hello-world.yaml +37 -0
  85. rem/schemas/agents/examples/query.yaml +54 -0
  86. rem/schemas/agents/examples/simple.yaml +21 -0
  87. rem/schemas/agents/examples/test.yaml +29 -0
  88. rem/schemas/agents/rem.yaml +128 -0
  89. rem/schemas/evaluators/hello-world/default.yaml +77 -0
  90. rem/schemas/evaluators/rem/faithfulness.yaml +219 -0
  91. rem/schemas/evaluators/rem/lookup-correctness.yaml +182 -0
  92. rem/schemas/evaluators/rem/retrieval-precision.yaml +199 -0
  93. rem/schemas/evaluators/rem/retrieval-recall.yaml +211 -0
  94. rem/schemas/evaluators/rem/search-correctness.yaml +192 -0
  95. rem/services/__init__.py +16 -0
  96. rem/services/audio/INTEGRATION.md +308 -0
  97. rem/services/audio/README.md +376 -0
  98. rem/services/audio/__init__.py +15 -0
  99. rem/services/audio/chunker.py +354 -0
  100. rem/services/audio/transcriber.py +259 -0
  101. rem/services/content/README.md +1269 -0
  102. rem/services/content/__init__.py +5 -0
  103. rem/services/content/providers.py +806 -0
  104. rem/services/content/service.py +657 -0
  105. rem/services/dreaming/README.md +230 -0
  106. rem/services/dreaming/__init__.py +53 -0
  107. rem/services/dreaming/affinity_service.py +336 -0
  108. rem/services/dreaming/moment_service.py +264 -0
  109. rem/services/dreaming/ontology_service.py +54 -0
  110. rem/services/dreaming/user_model_service.py +297 -0
  111. rem/services/dreaming/utils.py +39 -0
  112. rem/services/embeddings/__init__.py +11 -0
  113. rem/services/embeddings/api.py +120 -0
  114. rem/services/embeddings/worker.py +421 -0
  115. rem/services/fs/README.md +662 -0
  116. rem/services/fs/__init__.py +62 -0
  117. rem/services/fs/examples.py +206 -0
  118. rem/services/fs/examples_paths.py +204 -0
  119. rem/services/fs/git_provider.py +935 -0
  120. rem/services/fs/local_provider.py +760 -0
  121. rem/services/fs/parsing-hooks-examples.md +172 -0
  122. rem/services/fs/paths.py +276 -0
  123. rem/services/fs/provider.py +460 -0
  124. rem/services/fs/s3_provider.py +1042 -0
  125. rem/services/fs/service.py +186 -0
  126. rem/services/git/README.md +1075 -0
  127. rem/services/git/__init__.py +17 -0
  128. rem/services/git/service.py +469 -0
  129. rem/services/phoenix/EXPERIMENT_DESIGN.md +1146 -0
  130. rem/services/phoenix/README.md +453 -0
  131. rem/services/phoenix/__init__.py +46 -0
  132. rem/services/phoenix/client.py +686 -0
  133. rem/services/phoenix/config.py +88 -0
  134. rem/services/phoenix/prompt_labels.py +477 -0
  135. rem/services/postgres/README.md +575 -0
  136. rem/services/postgres/__init__.py +23 -0
  137. rem/services/postgres/migration_service.py +427 -0
  138. rem/services/postgres/pydantic_to_sqlalchemy.py +232 -0
  139. rem/services/postgres/register_type.py +352 -0
  140. rem/services/postgres/repository.py +337 -0
  141. rem/services/postgres/schema_generator.py +379 -0
  142. rem/services/postgres/service.py +802 -0
  143. rem/services/postgres/sql_builder.py +354 -0
  144. rem/services/rem/README.md +304 -0
  145. rem/services/rem/__init__.py +23 -0
  146. rem/services/rem/exceptions.py +71 -0
  147. rem/services/rem/executor.py +293 -0
  148. rem/services/rem/parser.py +145 -0
  149. rem/services/rem/queries.py +196 -0
  150. rem/services/rem/query.py +371 -0
  151. rem/services/rem/service.py +527 -0
  152. rem/services/session/README.md +374 -0
  153. rem/services/session/__init__.py +6 -0
  154. rem/services/session/compression.py +360 -0
  155. rem/services/session/reload.py +77 -0
  156. rem/settings.py +1235 -0
  157. rem/sql/002_install_models.sql +1068 -0
  158. rem/sql/background_indexes.sql +42 -0
  159. rem/sql/install_models.sql +1038 -0
  160. rem/sql/migrations/001_install.sql +503 -0
  161. rem/sql/migrations/002_install_models.sql +1202 -0
  162. rem/utils/AGENTIC_CHUNKING.md +597 -0
  163. rem/utils/README.md +583 -0
  164. rem/utils/__init__.py +43 -0
  165. rem/utils/agentic_chunking.py +622 -0
  166. rem/utils/batch_ops.py +343 -0
  167. rem/utils/chunking.py +108 -0
  168. rem/utils/clip_embeddings.py +276 -0
  169. rem/utils/dict_utils.py +98 -0
  170. rem/utils/embeddings.py +423 -0
  171. rem/utils/examples/embeddings_example.py +305 -0
  172. rem/utils/examples/sql_types_example.py +202 -0
  173. rem/utils/markdown.py +16 -0
  174. rem/utils/model_helpers.py +236 -0
  175. rem/utils/schema_loader.py +229 -0
  176. rem/utils/sql_types.py +348 -0
  177. rem/utils/user_id.py +81 -0
  178. rem/utils/vision.py +330 -0
  179. rem/workers/README.md +506 -0
  180. rem/workers/__init__.py +5 -0
  181. rem/workers/dreaming.py +502 -0
  182. rem/workers/engram_processor.py +312 -0
  183. rem/workers/sqs_file_processor.py +193 -0
  184. remdb-0.2.6.dist-info/METADATA +1191 -0
  185. remdb-0.2.6.dist-info/RECORD +187 -0
  186. remdb-0.2.6.dist-info/WHEEL +4 -0
  187. remdb-0.2.6.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,423 @@
1
+ """
2
+ REM configuration wizard.
3
+
4
+ Interactive setup wizard for configuring REM on a new installation.
5
+
6
+ Usage:
7
+ rem configure # Interactive wizard
8
+ rem configure --install # Run wizard + install database tables
9
+ rem configure --show # Show current configuration
10
+ rem configure --edit # Open config file in editor
11
+ """
12
+
13
+ import os
14
+ import subprocess
15
+ from pathlib import Path
16
+
17
+ import click
18
+ from loguru import logger
19
+
20
+ from rem.config import (
21
+ config_exists,
22
+ ensure_config_dir,
23
+ get_config_path,
24
+ get_default_config,
25
+ load_config,
26
+ save_config,
27
+ validate_config,
28
+ )
29
+
30
+
31
+ def prompt_postgres_config() -> dict:
32
+ """
33
+ Prompt user for PostgreSQL configuration.
34
+
35
+ Returns:
36
+ PostgreSQL configuration dictionary
37
+ """
38
+ click.echo("\n" + "=" * 60)
39
+ click.echo("PostgreSQL Configuration")
40
+ click.echo("=" * 60)
41
+
42
+ # Parse existing config if available
43
+ existing_conn = os.environ.get(
44
+ "POSTGRES__CONNECTION_STRING", "postgresql://rem:rem@localhost:5051/rem"
45
+ )
46
+
47
+ # Prompt for components
48
+ click.echo(
49
+ "\nEnter PostgreSQL connection details (press Enter to use default):"
50
+ )
51
+ click.echo("Default: Package users on port 5051 (docker compose -f docker-compose.prebuilt.yml up -d)")
52
+ click.echo("Developers: Change port to 5050 if using docker-compose.yml (local build)")
53
+ click.echo("Custom DB: Enter your own host/port below")
54
+
55
+ host = click.prompt("Host", default="localhost")
56
+ port = click.prompt("Port", default=5051, type=int)
57
+ database = click.prompt("Database name", default="rem")
58
+ username = click.prompt("Username", default="rem")
59
+ password = click.prompt("Password", default="rem", hide_input=True)
60
+
61
+ # Build connection string
62
+ connection_string = f"postgresql://{username}:{password}@{host}:{port}/{database}"
63
+
64
+ # Additional pool settings
65
+ click.echo("\nConnection pool settings:")
66
+ pool_min_size = click.prompt("Pool minimum size", default=5, type=int)
67
+ pool_max_size = click.prompt("Pool maximum size", default=20, type=int)
68
+
69
+ return {
70
+ "connection_string": connection_string,
71
+ "pool_min_size": pool_min_size,
72
+ "pool_max_size": pool_max_size,
73
+ }
74
+
75
+
76
+ def prompt_llm_config() -> dict:
77
+ """
78
+ Prompt user for LLM provider configuration.
79
+
80
+ Returns:
81
+ LLM configuration dictionary
82
+ """
83
+ click.echo("\n" + "=" * 60)
84
+ click.echo("LLM Provider Configuration")
85
+ click.echo("=" * 60)
86
+
87
+ config = {}
88
+
89
+ # Default model
90
+ click.echo("\nDefault LLM model (format: provider:model-id)")
91
+ click.echo("Examples:")
92
+ click.echo(" - anthropic:claude-sonnet-4-5-20250929")
93
+ click.echo(" - openai:gpt-4o")
94
+ click.echo(" - openai:gpt-4o-mini")
95
+
96
+ config["default_model"] = click.prompt(
97
+ "Default model", default="anthropic:claude-sonnet-4-5-20250929"
98
+ )
99
+
100
+ # Temperature
101
+ config["default_temperature"] = click.prompt(
102
+ "Default temperature (0.0-1.0)", default=0.5, type=float
103
+ )
104
+
105
+ # API keys
106
+ click.echo("\nAPI Keys (optional - leave empty to skip):")
107
+
108
+ openai_key = click.prompt("OpenAI API key", default="", show_default=False)
109
+ if openai_key:
110
+ config["openai_api_key"] = openai_key
111
+
112
+ anthropic_key = click.prompt("Anthropic API key", default="", show_default=False)
113
+ if anthropic_key:
114
+ config["anthropic_api_key"] = anthropic_key
115
+
116
+ return config
117
+
118
+
119
+ def prompt_s3_config() -> dict:
120
+ """
121
+ Prompt user for S3 storage configuration.
122
+
123
+ Returns:
124
+ S3 configuration dictionary
125
+ """
126
+ click.echo("\n" + "=" * 60)
127
+ click.echo("S3 Storage Configuration")
128
+ click.echo("=" * 60)
129
+
130
+ config = {}
131
+
132
+ click.echo("\nS3 storage is used for file uploads and processed content.")
133
+ use_s3 = click.confirm("Configure S3 storage?", default=True)
134
+
135
+ if not use_s3:
136
+ return {}
137
+
138
+ config["bucket_name"] = click.prompt("S3 bucket name", default="rem-storage")
139
+ config["region"] = click.prompt("AWS region", default="us-east-1")
140
+
141
+ # Optional: MinIO or LocalStack endpoint
142
+ use_custom_endpoint = click.confirm(
143
+ "Use custom S3 endpoint (MinIO, LocalStack)?", default=False
144
+ )
145
+ if use_custom_endpoint:
146
+ config["endpoint_url"] = click.prompt(
147
+ "Endpoint URL", default="http://localhost:9000"
148
+ )
149
+ config["access_key_id"] = click.prompt("Access key ID", default="minioadmin")
150
+ config["secret_access_key"] = click.prompt(
151
+ "Secret access key", default="minioadmin", hide_input=True
152
+ )
153
+
154
+ return config
155
+
156
+
157
+ def prompt_additional_env_vars() -> dict:
158
+ """
159
+ Prompt user for additional environment variables.
160
+
161
+ Returns:
162
+ Dictionary of custom environment variables
163
+ """
164
+ click.echo("\n" + "=" * 60)
165
+ click.echo("Additional Environment Variables")
166
+ click.echo("=" * 60)
167
+
168
+ env_vars: dict[str, str] = {}
169
+
170
+ add_env = click.confirm(
171
+ "Add custom environment variables?", default=False
172
+ )
173
+
174
+ if not add_env:
175
+ return env_vars
176
+
177
+ click.echo("\nEnter environment variables (empty name to finish):")
178
+ while True:
179
+ name = click.prompt("Variable name", default="", show_default=False)
180
+ if not name:
181
+ break
182
+
183
+ value = click.prompt(f"Value for {name}")
184
+ env_vars[name] = value
185
+
186
+ return env_vars
187
+
188
+
189
+ @click.command("configure")
190
+ @click.option(
191
+ "--install",
192
+ is_flag=True,
193
+ help="Install database tables after configuration",
194
+ )
195
+ @click.option(
196
+ "--claude-desktop",
197
+ is_flag=True,
198
+ help="Register REM MCP server with Claude Desktop",
199
+ )
200
+ @click.option(
201
+ "--show",
202
+ is_flag=True,
203
+ help="Show current configuration",
204
+ )
205
+ @click.option(
206
+ "--edit",
207
+ is_flag=True,
208
+ help="Open configuration file in editor",
209
+ )
210
+ def configure_command(install: bool, claude_desktop: bool, show: bool, edit: bool):
211
+ """
212
+ Configure REM installation.
213
+
214
+ Interactive wizard for setting up PostgreSQL, LLM providers, S3, and more.
215
+ Configuration is saved to ~/.rem/config.yaml and merged with environment variables.
216
+
217
+ Examples:
218
+ rem configure # Run interactive wizard
219
+ rem configure --install # Run wizard + install database tables
220
+ rem configure --show # Show current configuration
221
+ rem configure --edit # Open config in $EDITOR
222
+ """
223
+ config_path = get_config_path()
224
+
225
+ # Show current configuration
226
+ if show:
227
+ if not config_exists():
228
+ click.echo(f"No configuration file found at {config_path}")
229
+ click.echo("Run 'rem configure' to create one.")
230
+ return
231
+
232
+ config = load_config()
233
+ click.echo(f"\nConfiguration file: {config_path}")
234
+ click.echo("=" * 60)
235
+
236
+ import yaml
237
+
238
+ click.echo(yaml.dump(config, default_flow_style=False, sort_keys=False))
239
+ return
240
+
241
+ # Edit configuration file
242
+ if edit:
243
+ if not config_exists():
244
+ click.echo(f"No configuration file found at {config_path}")
245
+ click.echo("Run 'rem configure' to create one first.")
246
+ return
247
+
248
+ editor = os.environ.get("EDITOR", "vim")
249
+ try:
250
+ subprocess.run([editor, str(config_path)], check=True)
251
+ click.echo(f"\nConfiguration saved to {config_path}")
252
+ except Exception as e:
253
+ click.echo(f"Error opening editor: {e}", err=True)
254
+ click.echo(f"Manually edit: {config_path}")
255
+ return
256
+
257
+ # Run interactive wizard
258
+ click.echo("\n" + "=" * 60)
259
+ click.echo("REM Configuration Wizard")
260
+ click.echo("=" * 60)
261
+ click.echo("\nThis wizard will help you configure REM for first-time use.")
262
+ click.echo(f"Configuration will be saved to: {config_path}")
263
+
264
+ # Check if config already exists
265
+ if config_exists():
266
+ click.echo(f"\nConfiguration file already exists at {config_path}")
267
+ if not click.confirm("Overwrite existing configuration?", default=False):
268
+ click.echo("Configuration unchanged.")
269
+ return
270
+
271
+ # Build configuration
272
+ config = {}
273
+
274
+ # PostgreSQL (required)
275
+ config["postgres"] = prompt_postgres_config()
276
+
277
+ # LLM providers
278
+ config["llm"] = prompt_llm_config()
279
+
280
+ # S3 storage (optional)
281
+ s3_config = prompt_s3_config()
282
+ if s3_config:
283
+ config["s3"] = s3_config
284
+
285
+ # Additional environment variables
286
+ env_vars = prompt_additional_env_vars()
287
+ if env_vars:
288
+ config["env"] = env_vars
289
+
290
+ # Validate configuration
291
+ click.echo("\n" + "=" * 60)
292
+ click.echo("Validating Configuration")
293
+ click.echo("=" * 60)
294
+
295
+ errors = validate_config(config)
296
+ if errors:
297
+ click.echo("\nConfiguration validation failed:")
298
+ for error in errors:
299
+ click.echo(f" ❌ {error}", err=True)
300
+ click.echo("\nPlease fix these errors and try again.")
301
+ return
302
+
303
+ click.echo("✅ Configuration is valid")
304
+
305
+ # Save configuration
306
+ try:
307
+ save_config(config)
308
+ click.echo(f"\n✅ Configuration saved to {config_path}")
309
+ except Exception as e:
310
+ click.echo(f"\n❌ Failed to save configuration: {e}", err=True)
311
+ return
312
+
313
+ # Install database tables if requested
314
+ if install:
315
+ click.echo("\n" + "=" * 60)
316
+ click.echo("Database Installation")
317
+ click.echo("=" * 60)
318
+
319
+ if click.confirm("\nInstall database tables?", default=True):
320
+ try:
321
+ # Import here to ensure config is loaded first
322
+ from rem.config import merge_config_to_env
323
+
324
+ # Merge config into environment before running migrations
325
+ merge_config_to_env(config)
326
+
327
+ click.echo("\nRunning database migrations...")
328
+
329
+ # Import and run migrations
330
+ from rem.cli.commands.db import migrate
331
+
332
+ # Create a context for the command and invoke it
333
+ ctx = click.Context(migrate)
334
+ ctx.invoke(migrate, install_only=False, models_only=False,
335
+ background_indexes=False, connection=None,
336
+ sql_dir=Path("rem/sql"))
337
+
338
+ click.echo("✅ Database installation complete")
339
+
340
+ except Exception as e:
341
+ click.echo(f"\n❌ Database installation failed: {e}", err=True)
342
+ click.echo("\nYou can manually install tables later with:")
343
+ click.echo(" rem db migrate")
344
+
345
+ # Register with Claude Desktop if requested
346
+ if claude_desktop:
347
+ click.echo("\n" + "=" * 60)
348
+ click.echo("Claude Desktop Integration")
349
+ click.echo("=" * 60)
350
+
351
+ try:
352
+ import shutil
353
+ from pathlib import Path
354
+ from fastmcp.mcp_config import update_config_file, StdioMCPServer
355
+
356
+ # Find Claude Desktop config path
357
+ if os.name == "nt": # Windows
358
+ config_dir = Path.home() / "AppData/Roaming/Claude"
359
+ elif os.name == "posix":
360
+ if Path.home() / "Library/Application Support/Claude":
361
+ config_dir = Path.home() / "Library/Application Support/Claude"
362
+ else:
363
+ config_dir = Path.home() / ".config/Claude"
364
+ else:
365
+ config_dir = Path.home() / ".config/Claude"
366
+
367
+ config_path = config_dir / "claude_desktop_config.json"
368
+
369
+ # Find rem executable
370
+ rem_executable = shutil.which("rem")
371
+ if not rem_executable:
372
+ click.echo("❌ 'rem' command not found in PATH", err=True)
373
+ return
374
+
375
+ # Create server config with all necessary env vars
376
+ env_vars = {
377
+ "POSTGRES__CONNECTION_STRING": config.get("postgres", {}).get("connection_string", "")
378
+ }
379
+
380
+ # Add LLM API keys if present
381
+ llm_config = config.get("llm", {})
382
+ if llm_config.get("openai_api_key"):
383
+ env_vars["LLM__OPENAI_API_KEY"] = llm_config["openai_api_key"]
384
+ if llm_config.get("anthropic_api_key"):
385
+ env_vars["LLM__ANTHROPIC_API_KEY"] = llm_config["anthropic_api_key"]
386
+
387
+ server_config = StdioMCPServer(
388
+ command=rem_executable,
389
+ args=["mcp"],
390
+ env=env_vars
391
+ )
392
+
393
+ # Update config file using FastMCP utility
394
+ update_config_file(config_path, "rem", server_config)
395
+
396
+ click.echo(f"✅ Registered REM MCP server with Claude Desktop")
397
+ click.echo(f"Config: {config_path}")
398
+ click.echo("\nRestart Claude Desktop to use the REM server.")
399
+
400
+ except Exception as e:
401
+ click.echo(f"❌ Failed: {e}", err=True)
402
+
403
+ # Next steps
404
+ click.echo("\n" + "=" * 60)
405
+ click.echo("Next Steps")
406
+ click.echo("=" * 60)
407
+ click.echo("\n1. Verify configuration:")
408
+ click.echo(" rem configure --show")
409
+ click.echo("\n2. Edit configuration (if needed):")
410
+ click.echo(" rem configure --edit")
411
+ if not install:
412
+ click.echo("\n3. Install database tables:")
413
+ click.echo(" rem db migrate")
414
+ click.echo("\n4. Start the API server:")
415
+ click.echo(" rem dev run-server")
416
+ click.echo("\n5. Test the installation:")
417
+ click.echo(" rem ask 'Hello, REM!'")
418
+ click.echo()
419
+
420
+
421
+ def register_command(cli_group):
422
+ """Register the configure command."""
423
+ cli_group.add_command(configure_command)