ragtime-cli 0.2.1__tar.gz → 0.2.3__tar.gz
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.
- {ragtime_cli-0.2.1/ragtime_cli.egg-info → ragtime_cli-0.2.3}/PKG-INFO +1 -1
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/pyproject.toml +1 -1
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3/ragtime_cli.egg-info}/PKG-INFO +1 -1
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/ragtime_cli.egg-info/SOURCES.txt +2 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/cli.py +264 -7
- ragtime_cli-0.2.3/src/commands/create-pr.md +389 -0
- ragtime_cli-0.2.3/src/commands/import-docs.md +259 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/pr-graduate.md +7 -2
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/config.py +19 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/LICENSE +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/README.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/ragtime_cli.egg-info/dependency_links.txt +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/ragtime_cli.egg-info/entry_points.txt +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/ragtime_cli.egg-info/requires.txt +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/ragtime_cli.egg-info/top_level.txt +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/setup.cfg +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/__init__.py +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/audit.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/handoff.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/recall.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/remember.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/save.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/commands/start.md +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/db.py +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/indexers/__init__.py +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/indexers/docs.py +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/mcp_server.py +0 -0
- {ragtime_cli-0.2.1 → ragtime_cli-0.2.3}/src/memory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ragtime-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Local-first memory and RAG system for Claude Code - semantic search over code, docs, and team knowledge
|
|
5
5
|
Author-email: Bret Martineau <bretwardjames@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ragtime-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Local-first memory and RAG system for Claude Code - semantic search over code, docs, and team knowledge
|
|
5
5
|
Author-email: Bret Martineau <bretwardjames@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -166,7 +166,7 @@ def get_remote_branches_with_ragtime(path: Path) -> list[str]:
|
|
|
166
166
|
|
|
167
167
|
|
|
168
168
|
@click.group()
|
|
169
|
-
@click.version_option(version="0.2.
|
|
169
|
+
@click.version_option(version="0.2.3")
|
|
170
170
|
def main():
|
|
171
171
|
"""Ragtime - semantic search over code and documentation."""
|
|
172
172
|
pass
|
|
@@ -206,11 +206,45 @@ index/
|
|
|
206
206
|
"""
|
|
207
207
|
gitignore_path.write_text(gitignore_content)
|
|
208
208
|
|
|
209
|
+
# Create conventions file template
|
|
210
|
+
conventions_file = ragtime_dir / "CONVENTIONS.md"
|
|
211
|
+
if not conventions_file.exists():
|
|
212
|
+
conventions_file.write_text("""# Team Conventions
|
|
213
|
+
|
|
214
|
+
Rules and patterns that code must follow. These are checked by `/create-pr`.
|
|
215
|
+
|
|
216
|
+
## Code Style
|
|
217
|
+
|
|
218
|
+
- [ ] Example: Use async/await, not .then() chains
|
|
219
|
+
- [ ] Example: All API endpoints must use auth middleware
|
|
220
|
+
|
|
221
|
+
## Architecture
|
|
222
|
+
|
|
223
|
+
- [ ] Example: Services should not directly access repositories from other domains
|
|
224
|
+
|
|
225
|
+
## Security
|
|
226
|
+
|
|
227
|
+
- [ ] Example: Never commit .env or credentials files
|
|
228
|
+
- [ ] Example: All user input must be validated
|
|
229
|
+
|
|
230
|
+
## Testing
|
|
231
|
+
|
|
232
|
+
- [ ] Example: All new features need unit tests
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
Add your team's conventions above. Each rule should be:
|
|
237
|
+
- Clear and specific
|
|
238
|
+
- Checkable against code
|
|
239
|
+
- Actionable (what to do, not just what not to do)
|
|
240
|
+
""")
|
|
241
|
+
|
|
209
242
|
click.echo(f"\nCreated .ragtime/ structure:")
|
|
210
|
-
click.echo(f" app/
|
|
211
|
-
click.echo(f" team/
|
|
212
|
-
click.echo(f" branches/
|
|
213
|
-
click.echo(f" archive/
|
|
243
|
+
click.echo(f" app/ - Graduated knowledge (tracked)")
|
|
244
|
+
click.echo(f" team/ - Team conventions (tracked)")
|
|
245
|
+
click.echo(f" branches/ - Active branches (yours tracked, synced gitignored)")
|
|
246
|
+
click.echo(f" archive/ - Completed branches (tracked)")
|
|
247
|
+
click.echo(f" CONVENTIONS.md - Team rules checked by /create-pr")
|
|
214
248
|
|
|
215
249
|
# Check for ghp-cli
|
|
216
250
|
if check_ghp_installed():
|
|
@@ -362,6 +396,9 @@ def config(path: Path):
|
|
|
362
396
|
click.echo(f" Paths: {cfg.code.paths}")
|
|
363
397
|
click.echo(f" Languages: {cfg.code.languages}")
|
|
364
398
|
click.echo(f" Exclude: {cfg.code.exclude}")
|
|
399
|
+
click.echo("\nConventions:")
|
|
400
|
+
click.echo(f" Files: {cfg.conventions.files}")
|
|
401
|
+
click.echo(f" Also search memories: {cfg.conventions.also_search_memories}")
|
|
365
402
|
|
|
366
403
|
|
|
367
404
|
# ============================================================================
|
|
@@ -709,21 +746,54 @@ def install_commands(global_install: bool, workspace_install: bool, list_command
|
|
|
709
746
|
target_dir.mkdir(parents=True, exist_ok=True)
|
|
710
747
|
commands_dir = get_commands_dir()
|
|
711
748
|
installed = 0
|
|
749
|
+
skipped = 0
|
|
750
|
+
namespaced = 0
|
|
712
751
|
|
|
713
752
|
for cmd in to_install:
|
|
714
753
|
source = commands_dir / f"{cmd}.md"
|
|
715
754
|
target = target_dir / f"{cmd}.md"
|
|
755
|
+
namespaced_target = target_dir / f"ragtime-{cmd}.md"
|
|
716
756
|
|
|
717
757
|
if target.exists() and not force:
|
|
718
|
-
if
|
|
758
|
+
# Check if it's our file (contains ragtime marker)
|
|
759
|
+
existing_content = target.read_text()
|
|
760
|
+
is_ragtime_file = "ragtime" in existing_content.lower() and "mcp__ragtime" in existing_content
|
|
761
|
+
|
|
762
|
+
if is_ragtime_file:
|
|
763
|
+
# It's our file, safe to overwrite
|
|
719
764
|
target.write_text(source.read_text())
|
|
765
|
+
click.echo(f" ✓ {cmd}.md (updated)")
|
|
720
766
|
installed += 1
|
|
767
|
+
else:
|
|
768
|
+
# Conflict with non-ragtime command
|
|
769
|
+
click.echo(f"\n⚠️ Conflict: {cmd}.md already exists (not a ragtime command)")
|
|
770
|
+
click.echo(f" 1. Overwrite with ragtime's version")
|
|
771
|
+
click.echo(f" 2. Skip (keep existing)")
|
|
772
|
+
click.echo(f" 3. Install as ragtime-{cmd}.md")
|
|
773
|
+
|
|
774
|
+
choice = click.prompt(" Choice", type=click.Choice(["1", "2", "3"]), default="2")
|
|
775
|
+
|
|
776
|
+
if choice == "1":
|
|
777
|
+
target.write_text(source.read_text())
|
|
778
|
+
click.echo(f" ✓ {cmd}.md (overwritten)")
|
|
779
|
+
installed += 1
|
|
780
|
+
elif choice == "2":
|
|
781
|
+
click.echo(f" • {cmd}.md (skipped)")
|
|
782
|
+
skipped += 1
|
|
783
|
+
else:
|
|
784
|
+
namespaced_target.write_text(source.read_text())
|
|
785
|
+
click.echo(f" ✓ ragtime-{cmd}.md")
|
|
786
|
+
namespaced += 1
|
|
721
787
|
else:
|
|
722
788
|
target.write_text(source.read_text())
|
|
723
789
|
click.echo(f" ✓ {cmd}.md")
|
|
724
790
|
installed += 1
|
|
725
791
|
|
|
726
792
|
click.echo(f"\nInstalled {installed} commands to {target_dir}")
|
|
793
|
+
if namespaced:
|
|
794
|
+
click.echo(f" ({namespaced} installed with ragtime- prefix)")
|
|
795
|
+
if skipped:
|
|
796
|
+
click.echo(f" ({skipped} skipped due to conflicts)")
|
|
727
797
|
|
|
728
798
|
|
|
729
799
|
@main.command("setup-ghp")
|
|
@@ -1105,6 +1175,193 @@ def daemon_status(path: Path):
|
|
|
1105
1175
|
pid_file.unlink()
|
|
1106
1176
|
|
|
1107
1177
|
|
|
1178
|
+
@main.command()
|
|
1179
|
+
@click.argument("docs_path", type=click.Path(exists=True, path_type=Path), default="docs")
|
|
1180
|
+
@click.option("--path", type=click.Path(exists=True, path_type=Path), default=".")
|
|
1181
|
+
@click.option("--fix", is_flag=True, help="Interactively add frontmatter to files")
|
|
1182
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
1183
|
+
def audit(docs_path: Path, path: Path, fix: bool, as_json: bool):
|
|
1184
|
+
"""Audit docs for ragtime-compatible frontmatter.
|
|
1185
|
+
|
|
1186
|
+
Scans markdown files and suggests metadata for better indexing.
|
|
1187
|
+
|
|
1188
|
+
Examples:
|
|
1189
|
+
ragtime audit docs/ # Audit docs folder
|
|
1190
|
+
ragtime audit docs/ --fix # Interactively add frontmatter
|
|
1191
|
+
ragtime audit . --json # Output suggestions as JSON
|
|
1192
|
+
"""
|
|
1193
|
+
import re
|
|
1194
|
+
import json as json_module
|
|
1195
|
+
|
|
1196
|
+
path = Path(path).resolve()
|
|
1197
|
+
docs_path = Path(docs_path).resolve()
|
|
1198
|
+
|
|
1199
|
+
if not docs_path.exists():
|
|
1200
|
+
click.echo(f"✗ Path not found: {docs_path}", err=True)
|
|
1201
|
+
return
|
|
1202
|
+
|
|
1203
|
+
# Find all markdown files
|
|
1204
|
+
md_files = list(docs_path.rglob("*.md"))
|
|
1205
|
+
|
|
1206
|
+
if not md_files:
|
|
1207
|
+
click.echo(f"No markdown files found in {docs_path}")
|
|
1208
|
+
return
|
|
1209
|
+
|
|
1210
|
+
results = []
|
|
1211
|
+
|
|
1212
|
+
for md_file in md_files:
|
|
1213
|
+
content = md_file.read_text()
|
|
1214
|
+
relative = md_file.relative_to(path) if md_file.is_relative_to(path) else md_file
|
|
1215
|
+
|
|
1216
|
+
# Check for existing frontmatter
|
|
1217
|
+
has_frontmatter = content.startswith("---")
|
|
1218
|
+
existing_meta = {}
|
|
1219
|
+
|
|
1220
|
+
if has_frontmatter:
|
|
1221
|
+
try:
|
|
1222
|
+
import yaml
|
|
1223
|
+
parts = content.split("---", 2)
|
|
1224
|
+
if len(parts) >= 3:
|
|
1225
|
+
existing_meta = yaml.safe_load(parts[1]) or {}
|
|
1226
|
+
except:
|
|
1227
|
+
pass
|
|
1228
|
+
|
|
1229
|
+
# Analyze file for suggestions
|
|
1230
|
+
suggestions = analyze_doc_for_metadata(md_file, content, existing_meta)
|
|
1231
|
+
|
|
1232
|
+
status = "ok" if not suggestions["missing"] else "needs_update"
|
|
1233
|
+
if not has_frontmatter:
|
|
1234
|
+
status = "no_frontmatter"
|
|
1235
|
+
|
|
1236
|
+
results.append({
|
|
1237
|
+
"file": str(relative),
|
|
1238
|
+
"status": status,
|
|
1239
|
+
"has_frontmatter": has_frontmatter,
|
|
1240
|
+
"existing": existing_meta,
|
|
1241
|
+
"suggestions": suggestions,
|
|
1242
|
+
})
|
|
1243
|
+
|
|
1244
|
+
if as_json:
|
|
1245
|
+
click.echo(json_module.dumps(results, indent=2))
|
|
1246
|
+
return
|
|
1247
|
+
|
|
1248
|
+
# Summary
|
|
1249
|
+
no_fm = [r for r in results if r["status"] == "no_frontmatter"]
|
|
1250
|
+
needs_update = [r for r in results if r["status"] == "needs_update"]
|
|
1251
|
+
ok = [r for r in results if r["status"] == "ok"]
|
|
1252
|
+
|
|
1253
|
+
click.echo(f"\nAudited {len(md_files)} files in {docs_path.name}/\n")
|
|
1254
|
+
|
|
1255
|
+
if ok:
|
|
1256
|
+
click.echo(f"✓ {len(ok)} files have complete frontmatter")
|
|
1257
|
+
|
|
1258
|
+
if needs_update:
|
|
1259
|
+
click.echo(f"• {len(needs_update)} files could use more metadata")
|
|
1260
|
+
|
|
1261
|
+
if no_fm:
|
|
1262
|
+
click.echo(f"✗ {len(no_fm)} files have no frontmatter\n")
|
|
1263
|
+
|
|
1264
|
+
for r in no_fm[:10]: # Show first 10
|
|
1265
|
+
click.echo(f"{'─' * 60}")
|
|
1266
|
+
click.echo(f" {r['file']}")
|
|
1267
|
+
s = r["suggestions"]
|
|
1268
|
+
click.echo(f" Suggested frontmatter:")
|
|
1269
|
+
click.echo(f" namespace: {s.get('namespace', 'app')}")
|
|
1270
|
+
click.echo(f" type: {s.get('type', 'document')}")
|
|
1271
|
+
if s.get("component"):
|
|
1272
|
+
click.echo(f" component: {s['component']}")
|
|
1273
|
+
|
|
1274
|
+
if len(no_fm) > 10:
|
|
1275
|
+
click.echo(f"\n ... and {len(no_fm) - 10} more files")
|
|
1276
|
+
|
|
1277
|
+
if fix and no_fm:
|
|
1278
|
+
click.echo(f"\n{'─' * 60}")
|
|
1279
|
+
if click.confirm(f"\nAdd frontmatter to {len(no_fm)} files?"):
|
|
1280
|
+
added = 0
|
|
1281
|
+
for r in no_fm:
|
|
1282
|
+
file_path = path / r["file"]
|
|
1283
|
+
content = file_path.read_text()
|
|
1284
|
+
s = r["suggestions"]
|
|
1285
|
+
|
|
1286
|
+
# Build frontmatter
|
|
1287
|
+
fm_lines = ["---"]
|
|
1288
|
+
fm_lines.append(f"namespace: {s.get('namespace', 'app')}")
|
|
1289
|
+
fm_lines.append(f"type: {s.get('type', 'document')}")
|
|
1290
|
+
if s.get("component"):
|
|
1291
|
+
fm_lines.append(f"component: {s['component']}")
|
|
1292
|
+
fm_lines.append("---")
|
|
1293
|
+
fm_lines.append("")
|
|
1294
|
+
|
|
1295
|
+
new_content = "\n".join(fm_lines) + content
|
|
1296
|
+
file_path.write_text(new_content)
|
|
1297
|
+
added += 1
|
|
1298
|
+
click.echo(f" ✓ {r['file']}")
|
|
1299
|
+
|
|
1300
|
+
click.echo(f"\n✓ Added frontmatter to {added} files")
|
|
1301
|
+
click.echo(f" Run 'ragtime reindex' to update the search index")
|
|
1302
|
+
|
|
1303
|
+
|
|
1304
|
+
def analyze_doc_for_metadata(file_path: Path, content: str, existing: dict) -> dict:
|
|
1305
|
+
"""Analyze a document and suggest metadata."""
|
|
1306
|
+
import re
|
|
1307
|
+
|
|
1308
|
+
suggestions = {}
|
|
1309
|
+
missing = []
|
|
1310
|
+
|
|
1311
|
+
# Infer from path
|
|
1312
|
+
parts = file_path.parts
|
|
1313
|
+
path_lower = str(file_path).lower()
|
|
1314
|
+
|
|
1315
|
+
# Namespace inference
|
|
1316
|
+
if "namespace" not in existing:
|
|
1317
|
+
missing.append("namespace")
|
|
1318
|
+
if ".ragtime" in path_lower or "memory" in path_lower:
|
|
1319
|
+
suggestions["namespace"] = "app"
|
|
1320
|
+
elif "team" in path_lower or "convention" in path_lower:
|
|
1321
|
+
suggestions["namespace"] = "team"
|
|
1322
|
+
else:
|
|
1323
|
+
suggestions["namespace"] = "app"
|
|
1324
|
+
|
|
1325
|
+
# Type inference
|
|
1326
|
+
if "type" not in existing:
|
|
1327
|
+
missing.append("type")
|
|
1328
|
+
|
|
1329
|
+
# Check content for clues
|
|
1330
|
+
content_lower = content.lower()
|
|
1331
|
+
|
|
1332
|
+
if "api" in path_lower or "endpoint" in content_lower:
|
|
1333
|
+
suggestions["type"] = "architecture"
|
|
1334
|
+
elif "decision" in path_lower or "adr" in path_lower or "we decided" in content_lower:
|
|
1335
|
+
suggestions["type"] = "decision"
|
|
1336
|
+
elif "guide" in path_lower or "how to" in content_lower:
|
|
1337
|
+
suggestions["type"] = "pattern"
|
|
1338
|
+
elif "setup" in path_lower or "install" in path_lower:
|
|
1339
|
+
suggestions["type"] = "convention"
|
|
1340
|
+
elif "readme" in path_lower:
|
|
1341
|
+
suggestions["type"] = "document"
|
|
1342
|
+
elif "changelog" in path_lower or "release" in path_lower:
|
|
1343
|
+
suggestions["type"] = "document"
|
|
1344
|
+
else:
|
|
1345
|
+
suggestions["type"] = "document"
|
|
1346
|
+
|
|
1347
|
+
# Component inference from path
|
|
1348
|
+
if "component" not in existing:
|
|
1349
|
+
# Look for component-like folder names
|
|
1350
|
+
component_candidates = []
|
|
1351
|
+
skip = {"docs", "src", "lib", "app", "pages", "components", "memory", ".ragtime"}
|
|
1352
|
+
|
|
1353
|
+
for part in parts[:-1]: # Exclude filename
|
|
1354
|
+
if part.lower() not in skip and not part.startswith("."):
|
|
1355
|
+
component_candidates.append(part.lower())
|
|
1356
|
+
|
|
1357
|
+
if component_candidates:
|
|
1358
|
+
suggestions["component"] = component_candidates[-1] # Most specific
|
|
1359
|
+
missing.append("component")
|
|
1360
|
+
|
|
1361
|
+
suggestions["missing"] = missing
|
|
1362
|
+
return suggestions
|
|
1363
|
+
|
|
1364
|
+
|
|
1108
1365
|
@main.command()
|
|
1109
1366
|
@click.option("--check", is_flag=True, help="Only check for updates, don't install")
|
|
1110
1367
|
def update(check: bool):
|
|
@@ -1113,7 +1370,7 @@ def update(check: bool):
|
|
|
1113
1370
|
from urllib.request import urlopen
|
|
1114
1371
|
from urllib.error import URLError
|
|
1115
1372
|
|
|
1116
|
-
current = "0.2.
|
|
1373
|
+
current = "0.2.3"
|
|
1117
1374
|
|
|
1118
1375
|
click.echo(f"Current version: {current}")
|
|
1119
1376
|
click.echo("Checking PyPI for updates...")
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a PR with convention checks and graduated knowledge
|
|
3
|
+
allowed-arguments: optional PR title
|
|
4
|
+
allowed-tools: Bash, Read, Write, Edit, AskUserQuestion, mcp__ragtime__search, mcp__ragtime__memories
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Create PR
|
|
8
|
+
|
|
9
|
+
Create a pull request with branch knowledge graduated and committed alongside the code.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
- `/create-pr` - Interactive PR creation with memory curation
|
|
13
|
+
- `/create-pr "Add authentication flow"` - With suggested title
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
This command ensures code follows team standards and knowledge gets merged with the code:
|
|
18
|
+
|
|
19
|
+
1. Check code against team conventions and app patterns
|
|
20
|
+
2. Review branch memories and decide what graduates to `app/`
|
|
21
|
+
3. Check for conflicts with existing app knowledge
|
|
22
|
+
4. Commit graduated memories as part of the PR
|
|
23
|
+
5. Create the pull request
|
|
24
|
+
|
|
25
|
+
## Step 1: Gather Context
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
BRANCH=$(git branch --show-current)
|
|
29
|
+
BRANCH_SLUG=$(echo "$BRANCH" | tr '/' '-')
|
|
30
|
+
|
|
31
|
+
echo "Branch: $BRANCH"
|
|
32
|
+
|
|
33
|
+
# Check for uncommitted changes
|
|
34
|
+
git status --short
|
|
35
|
+
|
|
36
|
+
# Get commits on this branch
|
|
37
|
+
git log main..HEAD --oneline
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Step 2: Check Code Against Team Conventions
|
|
41
|
+
|
|
42
|
+
Before creating the PR, verify the code follows team standards.
|
|
43
|
+
|
|
44
|
+
### Load conventions config
|
|
45
|
+
|
|
46
|
+
Check `.ragtime/config.yaml` for conventions settings:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
# Default config (if not specified):
|
|
50
|
+
conventions:
|
|
51
|
+
files:
|
|
52
|
+
- ".ragtime/CONVENTIONS.md"
|
|
53
|
+
also_search_memories: true
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Read conventions files
|
|
57
|
+
|
|
58
|
+
For each file in `conventions.files`, read it if it exists:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Check for conventions files
|
|
62
|
+
cat .ragtime/CONVENTIONS.md 2>/dev/null
|
|
63
|
+
# Or other configured files like docs/CODING_STANDARDS.md
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The conventions doc should contain clear, checkable rules like:
|
|
67
|
+
- "All API endpoints must use auth middleware"
|
|
68
|
+
- "Use async/await, not .then() chains"
|
|
69
|
+
- "Never commit .env files"
|
|
70
|
+
|
|
71
|
+
### Also search memories (if enabled)
|
|
72
|
+
|
|
73
|
+
If `also_search_memories: true` (default), also search for convention memories:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
mcp__ragtime__search:
|
|
77
|
+
query: "convention standard pattern rule always never"
|
|
78
|
+
namespace: "team"
|
|
79
|
+
limit: 20
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
mcp__ragtime__search:
|
|
84
|
+
query: "pattern architecture convention"
|
|
85
|
+
namespace: "app"
|
|
86
|
+
type: "convention,pattern"
|
|
87
|
+
limit: 20
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Get changed files
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Files changed in this branch
|
|
94
|
+
git diff --name-only main...HEAD
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Review code against conventions
|
|
98
|
+
|
|
99
|
+
For each relevant convention/pattern found, check if the changed code follows it:
|
|
100
|
+
|
|
101
|
+
1. Read the convention/pattern memory
|
|
102
|
+
2. Read the relevant changed files
|
|
103
|
+
3. Check for compliance
|
|
104
|
+
|
|
105
|
+
Present findings:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
───────────────────────────────────────────
|
|
109
|
+
🔍 CONVENTION CHECK
|
|
110
|
+
───────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
Checked {file_count} changed files against {convention_count} team conventions.
|
|
113
|
+
|
|
114
|
+
✅ PASSING:
|
|
115
|
+
- "Use async/await, not .then()" - All async code uses await
|
|
116
|
+
- "Error responses use ApiError class" - Verified in api/routes.ts
|
|
117
|
+
|
|
118
|
+
⚠️ POTENTIAL ISSUES:
|
|
119
|
+
- "All API endpoints need auth middleware"
|
|
120
|
+
→ src/api/newEndpoint.ts:15 - No auth middleware detected
|
|
121
|
+
|
|
122
|
+
- "Use logger.error(), not console.error()"
|
|
123
|
+
→ src/services/auth.ts:42 - Found console.error()
|
|
124
|
+
|
|
125
|
+
❌ VIOLATIONS:
|
|
126
|
+
- "Never commit .env files"
|
|
127
|
+
→ .env.local is staged
|
|
128
|
+
───────────────────────────────────────────
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Handle issues
|
|
132
|
+
|
|
133
|
+
If issues found:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Found {issue_count} potential issues.
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
1. **Fix now** - I'll help fix these before creating PR
|
|
140
|
+
2. **Ignore** - Create PR anyway (add justification comment)
|
|
141
|
+
3. **Review each** - Go through issues one by one
|
|
142
|
+
4. **Cancel** - Fix manually and try again
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If "Fix now": Help the user fix each issue before proceeding.
|
|
146
|
+
|
|
147
|
+
If "Ignore": Ask for justification to include in PR description.
|
|
148
|
+
|
|
149
|
+
**Only proceed to memory curation after issues are resolved or acknowledged.**
|
|
150
|
+
|
|
151
|
+
## Step 3: Check for Branch Memories
|
|
152
|
+
|
|
153
|
+
Search for memories in this branch's namespace:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Check .ragtime/branches/{branch-slug}/ for memory files
|
|
157
|
+
ls -la .ragtime/branches/$BRANCH_SLUG/ 2>/dev/null || echo "No branch memories found"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Also search the index:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
mcp__ragtime__search:
|
|
164
|
+
query: "*"
|
|
165
|
+
namespace: "branch-{branch-slug}"
|
|
166
|
+
limit: 50
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**If no branch memories found:** Skip to Step 8 (Create PR).
|
|
170
|
+
|
|
171
|
+
**If memories found:** Continue to Step 4.
|
|
172
|
+
|
|
173
|
+
## Step 4: Present Memories for Curation
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
───────────────────────────────────────────
|
|
177
|
+
📋 BRANCH KNOWLEDGE REVIEW
|
|
178
|
+
───────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
Before creating the PR, let's review knowledge from this branch.
|
|
181
|
+
|
|
182
|
+
Graduated memories will be:
|
|
183
|
+
- Moved to app/ or team/ namespace
|
|
184
|
+
- Committed as part of this PR
|
|
185
|
+
- Merged with your code changes
|
|
186
|
+
|
|
187
|
+
Found {count} memories in branch-{branch}:
|
|
188
|
+
|
|
189
|
+
───────────────────────────────────────────
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
For each memory, show:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
**Memory {n} of {count}:**
|
|
196
|
+
|
|
197
|
+
"{content preview - first 150 chars}..."
|
|
198
|
+
|
|
199
|
+
Type: {type} | Component: {component}
|
|
200
|
+
File: {relative_path}
|
|
201
|
+
|
|
202
|
+
Action?
|
|
203
|
+
1. ✅ Graduate to app/
|
|
204
|
+
2. 🏛️ Graduate to team/ (conventions/standards)
|
|
205
|
+
3. 📚 Keep in branch (don't include in PR)
|
|
206
|
+
4. ❌ Abandon (mark as noise)
|
|
207
|
+
5. 👀 Show full content
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Step 5: Check for Conflicts
|
|
211
|
+
|
|
212
|
+
For each memory being graduated, search for similar content in app/:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
mcp__ragtime__search:
|
|
216
|
+
query: "{memory content keywords}"
|
|
217
|
+
namespace: "app"
|
|
218
|
+
limit: 5
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If similar memories exist (similarity > 0.8), present:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
⚠️ POTENTIAL CONFLICT
|
|
225
|
+
|
|
226
|
+
Graduating: "{new memory preview}..."
|
|
227
|
+
|
|
228
|
+
Similar existing memory in app/:
|
|
229
|
+
"{existing memory preview}..."
|
|
230
|
+
File: {existing_file}
|
|
231
|
+
|
|
232
|
+
Options:
|
|
233
|
+
1. **Keep both** - They're different enough
|
|
234
|
+
2. **Replace existing** - New one is better/more current
|
|
235
|
+
3. **Merge** - Combine into one comprehensive memory
|
|
236
|
+
4. **Skip graduation** - Existing one is sufficient
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### If merging:
|
|
240
|
+
|
|
241
|
+
Ask the user to provide the merged content, or offer to draft it:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
I can draft a merged version combining both. Want me to try?
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
If yes, present the draft for approval before saving.
|
|
248
|
+
|
|
249
|
+
## Step 6: Execute Graduation
|
|
250
|
+
|
|
251
|
+
For each memory to graduate:
|
|
252
|
+
|
|
253
|
+
### Move the file
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# From: .ragtime/branches/{branch-slug}/{id}-{slug}.md
|
|
257
|
+
# To: .ragtime/app/{component}/{id}-{slug}.md (or .ragtime/team/)
|
|
258
|
+
|
|
259
|
+
mkdir -p .ragtime/app/{component}
|
|
260
|
+
mv .ragtime/branches/{branch-slug}/{id}-{slug}.md .ragtime/app/{component}/
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Update the frontmatter
|
|
264
|
+
|
|
265
|
+
Edit the file to update:
|
|
266
|
+
- `namespace: app` (or `team`)
|
|
267
|
+
- `confidence: high`
|
|
268
|
+
- `confidence_reason: pr-graduate`
|
|
269
|
+
- `source: pr-graduate`
|
|
270
|
+
- Add `graduated_from: branch-{branch}`
|
|
271
|
+
|
|
272
|
+
### Stage the changes
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
git add .ragtime/app/
|
|
276
|
+
git add .ragtime/team/
|
|
277
|
+
# Don't stage branch/ folder - it stays local or gets cleaned up later
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Step 7: Commit Knowledge (if any graduated)
|
|
281
|
+
|
|
282
|
+
If memories were graduated:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
git add .ragtime/app/ .ragtime/team/
|
|
286
|
+
|
|
287
|
+
git commit -m "docs: graduate branch knowledge to app
|
|
288
|
+
|
|
289
|
+
Graduated {count} memories from branch-{branch}:
|
|
290
|
+
- {memory1 summary}
|
|
291
|
+
- {memory2 summary}
|
|
292
|
+
..."
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Step 8: Create the PR
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Check if we need to push
|
|
299
|
+
git push -u origin $BRANCH 2>/dev/null || git push
|
|
300
|
+
|
|
301
|
+
# Create PR
|
|
302
|
+
gh pr create --title "{title}" --body "$(cat <<'EOF'
|
|
303
|
+
## Summary
|
|
304
|
+
|
|
305
|
+
{summary from commits and context}
|
|
306
|
+
|
|
307
|
+
## Convention Compliance
|
|
308
|
+
|
|
309
|
+
{if all passed}
|
|
310
|
+
✅ All team conventions verified
|
|
311
|
+
|
|
312
|
+
{if issues were acknowledged}
|
|
313
|
+
⚠️ Known deviations:
|
|
314
|
+
- {issue}: {justification}
|
|
315
|
+
|
|
316
|
+
## Knowledge Added
|
|
317
|
+
|
|
318
|
+
{if memories were graduated}
|
|
319
|
+
This PR includes {count} graduated memories:
|
|
320
|
+
- {list of graduated memories with types}
|
|
321
|
+
|
|
322
|
+
## Test Plan
|
|
323
|
+
|
|
324
|
+
- [ ] {test items}
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
🤖 Generated with [Claude Code](https://claude.ai/code)
|
|
328
|
+
EOF
|
|
329
|
+
)"
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Step 9: Summary
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
───────────────────────────────────────────
|
|
336
|
+
✅ PR CREATED
|
|
337
|
+
───────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
PR: {url}
|
|
340
|
+
Branch: {branch}
|
|
341
|
+
|
|
342
|
+
Knowledge graduated: {count}
|
|
343
|
+
→ app/: {app_count}
|
|
344
|
+
→ team/: {team_count}
|
|
345
|
+
|
|
346
|
+
Remaining in branch/: {kept_count}
|
|
347
|
+
Abandoned: {abandoned_count}
|
|
348
|
+
|
|
349
|
+
The graduated knowledge is now part of your PR.
|
|
350
|
+
Reviewers will see it alongside your code changes.
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Quick Mode
|
|
354
|
+
|
|
355
|
+
For branches with few memories, offer quick mode:
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
Found {count} branch memories.
|
|
359
|
+
|
|
360
|
+
1. **Review each** - Curate one by one
|
|
361
|
+
2. **Quick mode** - I'll propose what to graduate
|
|
362
|
+
3. **Graduate all to app/** - Promote everything
|
|
363
|
+
4. **Skip knowledge** - Create PR without graduating
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Quick mode analyzes content and proposes:
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
## Quick Mode Proposal
|
|
370
|
+
|
|
371
|
+
**Graduate to app/:**
|
|
372
|
+
- "Auth uses JWT with 15-min expiry" (architecture)
|
|
373
|
+
- "Redis chosen for session storage" (decision)
|
|
374
|
+
|
|
375
|
+
**Keep in branch:**
|
|
376
|
+
- "Debug notes: token refresh" (task-state)
|
|
377
|
+
|
|
378
|
+
**Abandon:**
|
|
379
|
+
- "TODO: fix later" (noise)
|
|
380
|
+
|
|
381
|
+
Approve this? (yes / review each / edit)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Notes
|
|
385
|
+
|
|
386
|
+
- Graduated memories are committed as part of the PR, so reviewers see them
|
|
387
|
+
- Branch memories that aren't graduated stay in `.ragtime/branches/` for reference
|
|
388
|
+
- After PR merges, run `ragtime prune` to clean up synced branch folders
|
|
389
|
+
- The old `/pr-graduate` command can still be used if you forget to graduate before PR
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Migrate existing docs into ragtime memory structure with AI-assisted classification
|
|
3
|
+
allowed-arguments: path to docs folder (e.g., /import-docs docs/)
|
|
4
|
+
allowed-tools: Bash, Read, Write, Edit, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Import Docs
|
|
8
|
+
|
|
9
|
+
Analyze an existing docs folder and migrate content into the ragtime memory structure.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
- `/import-docs docs/` - Analyze docs folder and create memories
|
|
13
|
+
- `/import-docs` - Interactive mode, asks for path
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
This command helps teams that have existing documentation migrate into ragtime's structured memory system. It:
|
|
18
|
+
|
|
19
|
+
1. Scans all markdown files using `ragtime audit --json`
|
|
20
|
+
2. Analyzes each document's content to classify properly
|
|
21
|
+
3. Determines what should become memories vs. stay as indexed docs
|
|
22
|
+
4. Creates memories in `.ragtime/app/` or `.ragtime/team/` as appropriate
|
|
23
|
+
|
|
24
|
+
## Step 1: Get the Docs Path
|
|
25
|
+
|
|
26
|
+
**If `$ARGUMENTS` provided:**
|
|
27
|
+
- Use it as the docs path
|
|
28
|
+
|
|
29
|
+
**If no arguments:**
|
|
30
|
+
- Ask: "What docs folder should I analyze? (e.g., docs/, documentation/)"
|
|
31
|
+
|
|
32
|
+
## Step 2: Run Audit
|
|
33
|
+
|
|
34
|
+
Run the ragtime audit command to get a structured view of all docs:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ragtime audit {docs_path} --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Parse the JSON output to get the list of files and initial suggestions.
|
|
41
|
+
|
|
42
|
+
## Step 3: Analyze Documents
|
|
43
|
+
|
|
44
|
+
For each document (or batch), read the content and classify:
|
|
45
|
+
|
|
46
|
+
### Classification Questions
|
|
47
|
+
|
|
48
|
+
For each doc, determine:
|
|
49
|
+
|
|
50
|
+
1. **Is this memory-worthy or just reference?**
|
|
51
|
+
- Memory-worthy: Contains decisions, patterns, architecture insights, conventions
|
|
52
|
+
- Reference: API docs, changelogs, auto-generated content, raw specs
|
|
53
|
+
|
|
54
|
+
2. **What type of knowledge is it?**
|
|
55
|
+
- `architecture` - How systems/components work
|
|
56
|
+
- `decision` - Why we chose X over Y (look for "we decided", "because", trade-off discussion)
|
|
57
|
+
- `convention` - Team rules, coding standards, process docs
|
|
58
|
+
- `pattern` - Reusable solutions, "how to do X"
|
|
59
|
+
- `integration` - How external services connect
|
|
60
|
+
- `feature` - Feature documentation
|
|
61
|
+
|
|
62
|
+
3. **What namespace?**
|
|
63
|
+
- `app` - Technical knowledge about this codebase
|
|
64
|
+
- `team` - Team conventions, process, standards
|
|
65
|
+
|
|
66
|
+
4. **What component?** (infer from path and content)
|
|
67
|
+
|
|
68
|
+
5. **Should this doc be split?**
|
|
69
|
+
- Large docs with multiple distinct sections may become multiple memories
|
|
70
|
+
- Each memory should be focused on ONE concept
|
|
71
|
+
|
|
72
|
+
### Classification Hints
|
|
73
|
+
|
|
74
|
+
Look for signals in the content:
|
|
75
|
+
|
|
76
|
+
| Signal | Likely Type |
|
|
77
|
+
|--------|-------------|
|
|
78
|
+
| "We decided to..." | decision |
|
|
79
|
+
| "Always do X when Y" | convention |
|
|
80
|
+
| "The {system} works by..." | architecture |
|
|
81
|
+
| "To implement X, follow these steps..." | pattern |
|
|
82
|
+
| "Integrates with {service} via..." | integration |
|
|
83
|
+
| ADR format, numbered decisions | decision |
|
|
84
|
+
| API endpoints, request/response | architecture |
|
|
85
|
+
| Setup instructions, onboarding | convention |
|
|
86
|
+
|
|
87
|
+
## Step 4: Choose Migration Strategy
|
|
88
|
+
|
|
89
|
+
Ask the user:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
How should I handle the original docs?
|
|
93
|
+
|
|
94
|
+
1. **Memories only** - Create memories in .ragtime/, leave original docs unchanged
|
|
95
|
+
2. **Frontmatter only** - Add frontmatter to original docs for better indexing, no memories
|
|
96
|
+
3. **Both** - Add frontmatter to originals AND create memories for key insights (recommended)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Based on their choice, adjust what the migration plan includes.
|
|
100
|
+
|
|
101
|
+
## Step 5: Generate Migration Plan
|
|
102
|
+
|
|
103
|
+
Create a migration plan based on the user's strategy choice:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
## Migration Plan
|
|
107
|
+
|
|
108
|
+
### Will Add Frontmatter (if strategy includes frontmatter)
|
|
109
|
+
|
|
110
|
+
| File | Namespace | Type | Component |
|
|
111
|
+
|------|-----------|------|-----------|
|
|
112
|
+
| docs/auth/JWT_DESIGN.md | app | architecture | auth |
|
|
113
|
+
| docs/CODING_STANDARDS.md | team | convention | - |
|
|
114
|
+
| ... | | | |
|
|
115
|
+
|
|
116
|
+
### Will Create Memories (if strategy includes memories)
|
|
117
|
+
|
|
118
|
+
| File | Type | Namespace | Component | Notes |
|
|
119
|
+
|------|------|-----------|-----------|-------|
|
|
120
|
+
| docs/auth/JWT_DESIGN.md | architecture | app | auth | Split into 2 memories |
|
|
121
|
+
| docs/CODING_STANDARDS.md | convention | team | - | Full doc |
|
|
122
|
+
| ... | | | | |
|
|
123
|
+
|
|
124
|
+
### Will Index Only (no memory, just frontmatter or skip)
|
|
125
|
+
|
|
126
|
+
These stay as searchable docs but don't become memories:
|
|
127
|
+
- docs/CHANGELOG.md (reference)
|
|
128
|
+
- docs/api/endpoints.md (reference, auto-generated)
|
|
129
|
+
- ...
|
|
130
|
+
|
|
131
|
+
### Will Skip (Z files)
|
|
132
|
+
|
|
133
|
+
- docs/archive/old-stuff.md (outdated)
|
|
134
|
+
- ...
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Step 6: Get Approval
|
|
138
|
+
|
|
139
|
+
Present the plan and ask:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
I've analyzed {total} docs:
|
|
143
|
+
- {X} will become memories in .ragtime/
|
|
144
|
+
- {Y} will be indexed as reference docs
|
|
145
|
+
- {Z} will be skipped
|
|
146
|
+
|
|
147
|
+
Review the plan above. Should I:
|
|
148
|
+
1. Proceed with all
|
|
149
|
+
2. Let me adjust some classifications
|
|
150
|
+
3. Show me a specific file's analysis
|
|
151
|
+
4. Cancel
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Step 7: Execute Migration
|
|
155
|
+
|
|
156
|
+
### If adding frontmatter to originals:
|
|
157
|
+
|
|
158
|
+
For each doc that needs frontmatter, prepend:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
---
|
|
162
|
+
namespace: {app|team}
|
|
163
|
+
type: {type}
|
|
164
|
+
component: {if applicable}
|
|
165
|
+
---
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This makes the original docs index better with `ragtime index`.
|
|
169
|
+
|
|
170
|
+
### If creating memories:
|
|
171
|
+
|
|
172
|
+
1. **Extract the key content** - Don't copy the whole doc verbatim unless it's focused. Extract the essential knowledge.
|
|
173
|
+
|
|
174
|
+
2. **Write the memory file** to `.ragtime/app/{component}/{id}-{slug}.md` or `.ragtime/team/{id}-{slug}.md`:
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
---
|
|
178
|
+
id: {8-char-uuid}
|
|
179
|
+
namespace: {app|team}
|
|
180
|
+
type: {type}
|
|
181
|
+
component: {if applicable}
|
|
182
|
+
confidence: medium
|
|
183
|
+
confidence_reason: import-docs
|
|
184
|
+
source: import-docs
|
|
185
|
+
status: active
|
|
186
|
+
added: {today}
|
|
187
|
+
migrated_from: {original-file-path}
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
{extracted content}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
3. **For split documents**, create multiple focused memories with related IDs.
|
|
194
|
+
|
|
195
|
+
## Step 8: Reindex
|
|
196
|
+
|
|
197
|
+
After all memories are created:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
ragtime reindex
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Step 9: Summary
|
|
204
|
+
|
|
205
|
+
Summarize based on what was done:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
## Migration Complete
|
|
209
|
+
|
|
210
|
+
### Frontmatter Added (if applicable)
|
|
211
|
+
Updated {X} docs with frontmatter for better indexing.
|
|
212
|
+
|
|
213
|
+
### Memories Created (if applicable)
|
|
214
|
+
Created {Y} memories:
|
|
215
|
+
- {N} architecture in app/
|
|
216
|
+
- {N} conventions in team/
|
|
217
|
+
- {N} decisions in app/
|
|
218
|
+
- ...
|
|
219
|
+
|
|
220
|
+
Next steps:
|
|
221
|
+
- Run 'ragtime index' to update the search index
|
|
222
|
+
- Review memories with: ragtime memories --namespace app
|
|
223
|
+
- Search with: ragtime search "your query"
|
|
224
|
+
- Edit any misclassified content in .ragtime/ or docs/
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Tips
|
|
228
|
+
|
|
229
|
+
- **Don't over-migrate**: Not every doc needs to be a memory. Reference docs are fine as indexed content.
|
|
230
|
+
- **Preserve originals**: This creates memories FROM docs, doesn't delete originals.
|
|
231
|
+
- **Review component inference**: The path-based component detection may need adjustment.
|
|
232
|
+
- **Batch by folder**: For large doc sets, consider migrating one folder at a time.
|
|
233
|
+
|
|
234
|
+
## Example Session
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
User: /import-docs docs/
|
|
238
|
+
|
|
239
|
+
Claude: I'll analyze your docs folder...
|
|
240
|
+
|
|
241
|
+
Running: ragtime audit docs/ --json
|
|
242
|
+
|
|
243
|
+
Found 45 markdown files. Let me analyze each one...
|
|
244
|
+
|
|
245
|
+
[Analyzes docs/auth/JWT_DESIGN.md]
|
|
246
|
+
This is an architecture doc about JWT implementation. Key insights:
|
|
247
|
+
- 15-minute access token expiry
|
|
248
|
+
- Refresh token rotation strategy
|
|
249
|
+
- Why we chose asymmetric keys
|
|
250
|
+
|
|
251
|
+
I'll create 1 memory in app/auth/ for this.
|
|
252
|
+
|
|
253
|
+
[Continues for other files...]
|
|
254
|
+
|
|
255
|
+
## Migration Plan
|
|
256
|
+
...
|
|
257
|
+
|
|
258
|
+
Proceed? (yes/adjust/cancel)
|
|
259
|
+
```
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Graduate branch knowledge to app after PR merge
|
|
2
|
+
description: Graduate branch knowledge to app after PR merge (fallback)
|
|
3
3
|
allowed-tools: Bash, mcp__ragtime__search, mcp__ragtime__graduate, mcp__ragtime__update_status, mcp__ragtime__remember, AskUserQuestion
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# PR Graduate: Curate Branch Knowledge
|
|
6
|
+
# PR Graduate: Curate Branch Knowledge (Post-Merge)
|
|
7
|
+
|
|
8
|
+
> **Preferred workflow:** Use `/create-pr` instead - it graduates memories *before*
|
|
9
|
+
> creating the PR so knowledge is committed alongside code.
|
|
10
|
+
>
|
|
11
|
+
> Use this command only if you already merged without graduating.
|
|
7
12
|
|
|
8
13
|
After a PR is merged, review branch memories and decide what becomes permanent app knowledge.
|
|
9
14
|
|
|
@@ -36,11 +36,19 @@ class CodeConfig:
|
|
|
36
36
|
])
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
@dataclass
|
|
40
|
+
class ConventionsConfig:
|
|
41
|
+
"""Configuration for convention checking."""
|
|
42
|
+
files: list[str] = field(default_factory=lambda: [".ragtime/CONVENTIONS.md"])
|
|
43
|
+
also_search_memories: bool = True
|
|
44
|
+
|
|
45
|
+
|
|
39
46
|
@dataclass
|
|
40
47
|
class RagtimeConfig:
|
|
41
48
|
"""Main ragtime configuration."""
|
|
42
49
|
docs: DocsConfig = field(default_factory=DocsConfig)
|
|
43
50
|
code: CodeConfig = field(default_factory=CodeConfig)
|
|
51
|
+
conventions: ConventionsConfig = field(default_factory=ConventionsConfig)
|
|
44
52
|
|
|
45
53
|
@classmethod
|
|
46
54
|
def load(cls, project_path: Path) -> "RagtimeConfig":
|
|
@@ -58,6 +66,7 @@ class RagtimeConfig:
|
|
|
58
66
|
|
|
59
67
|
docs_data = data.get("docs", {})
|
|
60
68
|
code_data = data.get("code", {})
|
|
69
|
+
conventions_data = data.get("conventions", {})
|
|
61
70
|
|
|
62
71
|
return cls(
|
|
63
72
|
docs=DocsConfig(
|
|
@@ -70,6 +79,12 @@ class RagtimeConfig:
|
|
|
70
79
|
languages=code_data.get("languages", CodeConfig().languages),
|
|
71
80
|
exclude=code_data.get("exclude", CodeConfig().exclude),
|
|
72
81
|
),
|
|
82
|
+
conventions=ConventionsConfig(
|
|
83
|
+
files=conventions_data.get("files", ConventionsConfig().files),
|
|
84
|
+
also_search_memories=conventions_data.get(
|
|
85
|
+
"also_search_memories", ConventionsConfig().also_search_memories
|
|
86
|
+
),
|
|
87
|
+
),
|
|
73
88
|
)
|
|
74
89
|
|
|
75
90
|
def save(self, project_path: Path) -> None:
|
|
@@ -89,6 +104,10 @@ class RagtimeConfig:
|
|
|
89
104
|
"languages": self.code.languages,
|
|
90
105
|
"exclude": self.code.exclude,
|
|
91
106
|
},
|
|
107
|
+
"conventions": {
|
|
108
|
+
"files": self.conventions.files,
|
|
109
|
+
"also_search_memories": self.conventions.also_search_memories,
|
|
110
|
+
},
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
with open(config_path, "w") as f:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|