rbtr 2026.3.0.dev0__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.
- rbtr-2026.3.0.dev0/PKG-INFO +1135 -0
- rbtr-2026.3.0.dev0/README.md +1086 -0
- rbtr-2026.3.0.dev0/pyproject.toml +237 -0
- rbtr-2026.3.0.dev0/src/rbtr/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/cli.py +59 -0
- rbtr-2026.3.0.dev0/src/rbtr/config.py +472 -0
- rbtr-2026.3.0.dev0/src/rbtr/creds.py +83 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/connect_cmd.py +303 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/core.py +372 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/draft_cmd.py +235 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/index_cmd.py +508 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/indexing.py +160 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/memory_cmd.py +118 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/model_cmd.py +178 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/publish.py +642 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/reload_cmd.py +74 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/review_cmd.py +345 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/session_cmd.py +378 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/setup.py +122 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/shell.py +81 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/skill_cmd.py +75 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/stats_cmd.py +340 -0
- rbtr-2026.3.0.dev0/src/rbtr/engine/types.py +72 -0
- rbtr-2026.3.0.dev0/src/rbtr/events.py +267 -0
- rbtr-2026.3.0.dev0/src/rbtr/exceptions.py +13 -0
- rbtr-2026.3.0.dev0/src/rbtr/git/__init__.py +41 -0
- rbtr-2026.3.0.dev0/src/rbtr/git/filters.py +57 -0
- rbtr-2026.3.0.dev0/src/rbtr/git/objects.py +588 -0
- rbtr-2026.3.0.dev0/src/rbtr/git/repo.py +125 -0
- rbtr-2026.3.0.dev0/src/rbtr/github/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/github/auth.py +80 -0
- rbtr-2026.3.0.dev0/src/rbtr/github/client.py +648 -0
- rbtr-2026.3.0.dev0/src/rbtr/github/draft.py +474 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/arrow.py +125 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/chunks.py +116 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/edges.py +495 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/embeddings.py +221 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/languages.py +49 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/models.py +162 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/orchestrator.py +487 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/search.py +381 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/clear_embeddings.sql +3 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/count_orphan_chunks.sql +9 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/delete_edges.sql +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/delete_snapshots.sql +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/diff_added.sql +24 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/diff_modified.sql +23 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/get_chunks.sql +25 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/get_edges.sql +10 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/has_blob.sql +4 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/inbound_degree.sql +8 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/insert_edges.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/insert_snapshot.sql +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/prune_chunks.sql +8 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/prune_edges.sql +3 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/schema.sql +43 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/search_by_name.sql +23 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/search_fulltext.sql +31 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/search_similar.sql +25 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/update_embedding.sql +3 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/update_embeddings.sql +4 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/upsert_chunks.sql +28 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/sql/upsert_snapshots.sql +6 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/store.py +748 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/tokenise.py +77 -0
- rbtr-2026.3.0.dev0/src/rbtr/index/treesitter.py +176 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/agent.py +123 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/compact.py +310 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/context.py +63 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/costs.py +86 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/deps.py +26 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/errors.py +53 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/history.py +810 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/memory.py +608 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/operational_prompts.py +46 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/stream.py +1049 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/__init__.py +6 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/common.py +234 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/discussion.py +99 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/draft.py +332 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/file.py +547 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/git.py +188 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/index.py +329 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/memory.py +80 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/notes.py +70 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/tools/shell.py +138 -0
- rbtr-2026.3.0.dev0/src/rbtr/llm/types.py +16 -0
- rbtr-2026.3.0.dev0/src/rbtr/log.py +69 -0
- rbtr-2026.3.0.dev0/src/rbtr/models.py +266 -0
- rbtr-2026.3.0.dev0/src/rbtr/oauth.py +329 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/README.md +454 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/__init__.py +6 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/bash.py +58 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/c.py +80 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/cpp.py +79 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/defaults.py +119 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/go.py +134 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/hookspec.py +394 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/java.py +107 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/javascript.py +192 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/manager.py +371 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/python.py +143 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/ruby.py +95 -0
- rbtr-2026.3.0.dev0/src/rbtr/plugins/rust.py +177 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/.rumdl.toml +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/__init__.py +222 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/compact.md +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/index_status.md +20 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/memory_existing_facts.md +9 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/memory_extract.md +59 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/review.md +108 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/skills.md +16 -0
- rbtr-2026.3.0.dev0/src/rbtr/prompts/system.md +34 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/__init__.py +113 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/claude.py +294 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/endpoint.py +257 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/fireworks.py +71 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/google.py +474 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/openai.py +71 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/openai_codex.py +356 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/openrouter.py +76 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/shared.py +74 -0
- rbtr-2026.3.0.dev0/src/rbtr/providers/types.py +49 -0
- rbtr-2026.3.0.dev0/src/rbtr/scripts/__init__.py +0 -0
- rbtr-2026.3.0.dev0/src/rbtr/scripts/bash_complete.sh +88 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/incidents.py +186 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/kinds.py +178 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/migrations.py +77 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/overhead.py +54 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/scrub.py +42 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/serialise.py +380 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/.sqlfluff +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/compact_mark_message.sql +8 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/complete_message.sql +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/delete_fact.sql +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/delete_message.sql +6 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/delete_old_facts.sql +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/delete_old_sessions.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/delete_session.sql +2 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/fact_counts.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/fact_scopes.sql +3 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/finalize_request_complete.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/finalize_request_header.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/find_fact_by_content.sql +16 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/find_latest_summary.sql +13 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/first_kept_timestamp.sql +10 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/get_created_at.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/get_fact.sql +11 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_incident_failure_stats.sql +20 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_incident_repair_stats.sql +9 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_model_stats.sql +15 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_overhead_stats.sql +59 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_stats.sql +13 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/global_tool_stats.sql +23 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/has_messages_after.sql +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/has_repair_incident.sql +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/incident_failure_stats.sql +24 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/incident_repair_stats.sql +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/insert_fact.sql +4 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/insert_fragment.sql +13 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/list_sessions.sql +19 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/load_active_facts.sql +14 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/load_all_facts.sql +14 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/load_message_ids.sql +14 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/load_messages.sql +12 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/migrate_2026030301_to_2026030801.sql +42 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/migrate_2026030801_find_inverted_pairs.sql +33 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/migrate_2026030801_swap_created_at.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/reset_compaction.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/schema.sql +82 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/search_facts_fts.sql +17 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/search_history.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/session_history.sql +7 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/session_overhead_stats.sql +61 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/session_started_at.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/session_token_stats.sql +82 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/supersede_fact.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/tool_stats.sql +34 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/update_fact_confirmed.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/sql/update_fragment.sql +5 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/stats.py +391 -0
- rbtr-2026.3.0.dev0/src/rbtr/sessions/store.py +1041 -0
- rbtr-2026.3.0.dev0/src/rbtr/shell_exec.py +214 -0
- rbtr-2026.3.0.dev0/src/rbtr/skills/__init__.py +10 -0
- rbtr-2026.3.0.dev0/src/rbtr/skills/discovery.py +204 -0
- rbtr-2026.3.0.dev0/src/rbtr/skills/registry.py +86 -0
- rbtr-2026.3.0.dev0/src/rbtr/state.py +91 -0
- rbtr-2026.3.0.dev0/src/rbtr/styles.py +99 -0
- rbtr-2026.3.0.dev0/src/rbtr/tui/__init__.py +1 -0
- rbtr-2026.3.0.dev0/src/rbtr/tui/footer.py +176 -0
- rbtr-2026.3.0.dev0/src/rbtr/tui/input.py +1019 -0
- rbtr-2026.3.0.dev0/src/rbtr/tui/key_encoding.py +110 -0
- rbtr-2026.3.0.dev0/src/rbtr/tui/ui.py +1297 -0
- rbtr-2026.3.0.dev0/src/rbtr/usage.py +280 -0
- rbtr-2026.3.0.dev0/src/rbtr/workspace.py +48 -0
|
@@ -0,0 +1,1135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rbtr
|
|
3
|
+
Version: 2026.3.0.dev0
|
|
4
|
+
Summary: rbtr — Interactive LLM-powered PR review workbench
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Dist: anyio>=4.0
|
|
7
|
+
Requires-Dist: httpx
|
|
8
|
+
Requires-Dist: pydantic>=2.12.5
|
|
9
|
+
Requires-Dist: pydantic-ai
|
|
10
|
+
Requires-Dist: pydantic-settings[toml]>=2.12.0
|
|
11
|
+
Requires-Dist: tomli-w
|
|
12
|
+
Requires-Dist: pygithub
|
|
13
|
+
Requires-Dist: pygit2
|
|
14
|
+
Requires-Dist: rich
|
|
15
|
+
Requires-Dist: prompt-toolkit>=3.0
|
|
16
|
+
Requires-Dist: minijinja>=2.15.1
|
|
17
|
+
Requires-Dist: tree-sitter>=0.24
|
|
18
|
+
Requires-Dist: tree-sitter-python
|
|
19
|
+
Requires-Dist: tree-sitter-json
|
|
20
|
+
Requires-Dist: tree-sitter-yaml
|
|
21
|
+
Requires-Dist: tree-sitter-toml
|
|
22
|
+
Requires-Dist: tree-sitter-bash
|
|
23
|
+
Requires-Dist: duckdb>=1.0
|
|
24
|
+
Requires-Dist: pyarrow>=17.0
|
|
25
|
+
Requires-Dist: llama-cpp-python
|
|
26
|
+
Requires-Dist: huggingface-hub
|
|
27
|
+
Requires-Dist: pluggy>=1.6.0
|
|
28
|
+
Requires-Dist: uuid-utils>=0.14.1
|
|
29
|
+
Requires-Dist: ruamel-yaml>=0.19.1
|
|
30
|
+
Requires-Dist: python-frontmatter>=1.1.0
|
|
31
|
+
Requires-Dist: tree-sitter-c ; extra == 'languages'
|
|
32
|
+
Requires-Dist: tree-sitter-c-sharp ; extra == 'languages'
|
|
33
|
+
Requires-Dist: tree-sitter-cpp ; extra == 'languages'
|
|
34
|
+
Requires-Dist: tree-sitter-css ; extra == 'languages'
|
|
35
|
+
Requires-Dist: tree-sitter-go ; extra == 'languages'
|
|
36
|
+
Requires-Dist: tree-sitter-hcl ; extra == 'languages'
|
|
37
|
+
Requires-Dist: tree-sitter-html ; extra == 'languages'
|
|
38
|
+
Requires-Dist: tree-sitter-java ; extra == 'languages'
|
|
39
|
+
Requires-Dist: tree-sitter-javascript ; extra == 'languages'
|
|
40
|
+
Requires-Dist: tree-sitter-kotlin ; extra == 'languages'
|
|
41
|
+
Requires-Dist: tree-sitter-ruby ; extra == 'languages'
|
|
42
|
+
Requires-Dist: tree-sitter-rust ; extra == 'languages'
|
|
43
|
+
Requires-Dist: tree-sitter-scala ; extra == 'languages'
|
|
44
|
+
Requires-Dist: tree-sitter-swift ; extra == 'languages'
|
|
45
|
+
Requires-Dist: tree-sitter-typescript ; extra == 'languages'
|
|
46
|
+
Requires-Python: >=3.13
|
|
47
|
+
Provides-Extra: languages
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# rbtr
|
|
51
|
+
|
|
52
|
+
An agentic code review harness in the terminal. rbtr
|
|
53
|
+
indexes your repository, reads the diff, understands the
|
|
54
|
+
structure of the code — commit messages, PR description,
|
|
55
|
+
existing discussion — and helps you reason through the
|
|
56
|
+
changes. It writes structured review comments and posts
|
|
57
|
+
them to GitHub.
|
|
58
|
+
|
|
59
|
+
It connects to Claude, GPT, Gemini, and any OpenAI-compatible
|
|
60
|
+
endpoint. Conversations are saved automatically and survive
|
|
61
|
+
crashes. Long sessions compact themselves so the model never
|
|
62
|
+
loses context.
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Requires Python 3.13+
|
|
68
|
+
uv tool install -e .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Your first review
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
rbtr # launch in a git repo
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Connect a provider, select a PR, and ask the model to review:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
you: /connect claude
|
|
81
|
+
Opening browser to sign in with your Claude account…
|
|
82
|
+
Connected to Claude. LLM is ready.
|
|
83
|
+
|
|
84
|
+
you: /review 42
|
|
85
|
+
Fetching PR #42…
|
|
86
|
+
⟳ indexing 177 files…
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The model has 20 tools — it reads files, searches the index,
|
|
90
|
+
inspects the diff, and follows references across the codebase.
|
|
91
|
+
Ask it anything about the changes:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
you: explain the nature of the changes, focus on error handling
|
|
95
|
+
|
|
96
|
+
claude: [reads diff, searches for retry logic, reads related files]
|
|
97
|
+
|
|
98
|
+
The PR adds retry logic to the HTTP client but has two issues:
|
|
99
|
+
|
|
100
|
+
1. **No backoff** — `src/client.py:42` retries immediately
|
|
101
|
+
in a tight loop. Under load this will hammer the server.
|
|
102
|
+
|
|
103
|
+
2. **Unused import** — `src/client.py:89` imports `sleep`
|
|
104
|
+
but the retry loop uses `time.sleep` directly.
|
|
105
|
+
|
|
106
|
+
I've added both as draft comments.
|
|
107
|
+
|
|
108
|
+
you: the first one is a blocker, mark it as such
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Inspect and post the draft:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
you: /draft
|
|
115
|
+
|
|
116
|
+
## 2 comments
|
|
117
|
+
|
|
118
|
+
### src/client.py
|
|
119
|
+
|
|
120
|
+
★ 1. L:42
|
|
121
|
+
> resp = session.get(url)
|
|
122
|
+
**blocker:** Retries without backoff. Under load this
|
|
123
|
+
hammers the server. Use exponential backoff.
|
|
124
|
+
|
|
125
|
+
★ 2. L:89
|
|
126
|
+
> from time import sleep
|
|
127
|
+
**nit:** Unused import — `sleep` is never called.
|
|
128
|
+
|
|
129
|
+
## Summary
|
|
130
|
+
|
|
131
|
+
Two issues in the retry logic. The missing backoff is a
|
|
132
|
+
blocker; the unused import is minor.
|
|
133
|
+
|
|
134
|
+
you: /draft post
|
|
135
|
+
Review posted.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You can also start without a PR — `rbtr` opens a plain
|
|
139
|
+
conversation in any git repo. Use `/review` later to select
|
|
140
|
+
a target.
|
|
141
|
+
|
|
142
|
+
### Snapshot review
|
|
143
|
+
|
|
144
|
+
Review code at a single point in time — no PR, no diff, no
|
|
145
|
+
GitHub. Useful for onboarding, architecture review, or audit.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
rbtr v2.1.0 # launch with a tag
|
|
149
|
+
rbtr main # launch with a branch
|
|
150
|
+
rbtr HEAD # launch at current commit
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Or from inside rbtr:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
you: /review v2.1.0
|
|
157
|
+
Reviewing snapshot: v2.1.0
|
|
158
|
+
⟳ indexing 177 files…
|
|
159
|
+
|
|
160
|
+
you: walk me through the auth module
|
|
161
|
+
|
|
162
|
+
you: /review main feature
|
|
163
|
+
Reviewing branch: main → feature
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Tools
|
|
167
|
+
|
|
168
|
+
The model has 20 tools for reading code, navigating the
|
|
169
|
+
codebase, writing review feedback, and running shell
|
|
170
|
+
commands. Tools appear and disappear based on session state
|
|
171
|
+
— the model never sees a tool it cannot use.
|
|
172
|
+
|
|
173
|
+
| Condition | Tools available |
|
|
174
|
+
| ----------------- | ---------------------------------------- |
|
|
175
|
+
| Always | `edit`, `remember`, `run_command` |
|
|
176
|
+
| Repo + any target | `read_file`, `list_files`, `grep` |
|
|
177
|
+
| Index ready | `search`, `read_symbol`, `list_symbols`, |
|
|
178
|
+
| | `find_references` |
|
|
179
|
+
| PR or branch | `diff`, `changed_files`, `commit_log`, |
|
|
180
|
+
| | `changed_symbols` |
|
|
181
|
+
| PR only | Draft tools, `get_pr_discussion` |
|
|
182
|
+
|
|
183
|
+
In snapshot mode (`/review <ref>`) the model has file, index,
|
|
184
|
+
workspace, and shell tools. Diff and draft tools are hidden
|
|
185
|
+
— there is no base to compare against.
|
|
186
|
+
|
|
187
|
+
### Reading code
|
|
188
|
+
|
|
189
|
+
The model reads changed files, referenced modules, tests,
|
|
190
|
+
and config to understand context beyond the diff.
|
|
191
|
+
|
|
192
|
+
| Tool | Description |
|
|
193
|
+
| ------------ | ------------------------------------------ |
|
|
194
|
+
| `read_file` | Read file contents, paginated by lines |
|
|
195
|
+
| `grep` | Substring search, scoped by glob or prefix |
|
|
196
|
+
| `list_files` | List files, scoped by glob or prefix |
|
|
197
|
+
|
|
198
|
+
### Understanding changes
|
|
199
|
+
|
|
200
|
+
The model starts here — what changed, how the work was
|
|
201
|
+
structured, and what the changes mean structurally.
|
|
202
|
+
|
|
203
|
+
| Tool | Description |
|
|
204
|
+
| ----------------- | ------------------------------------ |
|
|
205
|
+
| `diff` | Unified diff, scoped by glob or file |
|
|
206
|
+
| `changed_files` | Files changed in the PR |
|
|
207
|
+
| `commit_log` | Commits between base and head |
|
|
208
|
+
| `changed_symbols` | Symbols added, removed, or modified. |
|
|
209
|
+
| | Flags stale docs and missing tests |
|
|
210
|
+
|
|
211
|
+
### Navigating the codebase
|
|
212
|
+
|
|
213
|
+
The code index lets the model search by name, keyword, or
|
|
214
|
+
concept — and follow references to check whether a change
|
|
215
|
+
breaks callers or misses related code.
|
|
216
|
+
|
|
217
|
+
| Tool | Description |
|
|
218
|
+
| ----------------- | ------------------------------------ |
|
|
219
|
+
| `search` | Find symbols by name, keyword, or |
|
|
220
|
+
| | natural-language concept |
|
|
221
|
+
| `read_symbol` | Read the full source of a symbol |
|
|
222
|
+
| `list_symbols` | Table of contents for a file |
|
|
223
|
+
| `find_references` | Find all symbols referencing a given |
|
|
224
|
+
| | symbol via the dependency graph |
|
|
225
|
+
|
|
226
|
+
### Writing the review
|
|
227
|
+
|
|
228
|
+
The model builds the review incrementally — adding comments
|
|
229
|
+
on specific lines, editing them based on discussion, and
|
|
230
|
+
setting the overall summary.
|
|
231
|
+
|
|
232
|
+
| Tool | Description |
|
|
233
|
+
| ---------------------- | -------------------------------- |
|
|
234
|
+
| `add_draft_comment` | Inline comment on a code snippet |
|
|
235
|
+
| `edit_draft_comment` | Edit an existing comment |
|
|
236
|
+
| `remove_draft_comment` | Remove a comment |
|
|
237
|
+
| `set_draft_summary` | Set the top-level review body |
|
|
238
|
+
| `read_draft` | Read the current draft |
|
|
239
|
+
|
|
240
|
+
### Context and memory
|
|
241
|
+
|
|
242
|
+
The model reads existing discussion to avoid duplicating
|
|
243
|
+
feedback, saves durable facts for future sessions, and
|
|
244
|
+
writes notes to the workspace.
|
|
245
|
+
|
|
246
|
+
| Tool | Description |
|
|
247
|
+
| ------------------- | ----------------------------------- |
|
|
248
|
+
| `get_pr_discussion` | Existing reviews, comments, CI |
|
|
249
|
+
| `remember` | Save a fact for future sessions |
|
|
250
|
+
| `edit` | Create or modify `.rbtr/notes/` and |
|
|
251
|
+
| | `.rbtr/AGENTS.md` |
|
|
252
|
+
|
|
253
|
+
### Shell execution
|
|
254
|
+
|
|
255
|
+
The model can run shell commands when `tools.shell.enabled`
|
|
256
|
+
is `true` (the default).
|
|
257
|
+
|
|
258
|
+
| Tool | Description |
|
|
259
|
+
| ------------- | --------------------------------------- |
|
|
260
|
+
| `run_command` | Execute a shell command, return output |
|
|
261
|
+
|
|
262
|
+
The primary use is executing scripts bundled with skills.
|
|
263
|
+
The model is steered away from using it for codebase access
|
|
264
|
+
— files under review live in a different branch or commit,
|
|
265
|
+
so `read_file`, `grep`, and other bespoke tools are the
|
|
266
|
+
correct choice (they read from the git object store at the
|
|
267
|
+
right ref). The working tree is treated as read-only.
|
|
268
|
+
|
|
269
|
+
Output is streamed to the TUI via a head/tail buffer
|
|
270
|
+
(first 3 + last 5 lines, refreshed at ~30 fps). When the
|
|
271
|
+
command executes a skill script, the header shows the skill
|
|
272
|
+
name and source instead of raw JSON args
|
|
273
|
+
(e.g. `⚙ [brave-search · user] search.sh "query"`). The
|
|
274
|
+
full result returned to the model is truncated to
|
|
275
|
+
`tools.shell.max_output_lines` (default 2000).
|
|
276
|
+
|
|
277
|
+
```toml
|
|
278
|
+
[tools.shell]
|
|
279
|
+
enabled = true # set false to disable entirely
|
|
280
|
+
timeout = 120 # default timeout in seconds (0 = no limit)
|
|
281
|
+
max_output_lines = 2000
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`list_files`, `grep`, and `diff` accept a `pattern` parameter
|
|
285
|
+
that works like a git pathspec: a plain string is a directory
|
|
286
|
+
prefix or file path, glob metacharacters (`*`, `?`, `[`)
|
|
287
|
+
activate pattern matching, and `**` matches across
|
|
288
|
+
directories. For example, `pattern="src/**/*.py"` scopes to
|
|
289
|
+
Python files under `src/`.
|
|
290
|
+
|
|
291
|
+
Tools that read code accept a `ref` parameter — `"head"`
|
|
292
|
+
(default), `"base"`, or a raw commit SHA — so the model
|
|
293
|
+
can inspect the codebase at any point in time. File tools
|
|
294
|
+
read from the git object store first and fall back to the
|
|
295
|
+
local filesystem for untracked files (`.rbtr/notes/`,
|
|
296
|
+
drafts).
|
|
297
|
+
|
|
298
|
+
All paginated tools show a trailer when output is truncated.
|
|
299
|
+
Each turn is limited to 25 tool calls (configurable via
|
|
300
|
+
`max_requests_per_turn`). When the limit is reached, the
|
|
301
|
+
model summarises its progress and asks whether to continue.
|
|
302
|
+
|
|
303
|
+
## Commands
|
|
304
|
+
|
|
305
|
+
| Command | Description | Context |
|
|
306
|
+
| ------------------------- | ------------------------------------------- | ------- |
|
|
307
|
+
| `/help` | Show available commands | |
|
|
308
|
+
| `/review` | List open PRs and branches | ✓ |
|
|
309
|
+
| `/review <number>` | Select a PR for review | ✓ |
|
|
310
|
+
| `/review <ref>` | Snapshot review at a git ref | ✓ |
|
|
311
|
+
| `/review <base> <target>` | Diff review between two refs | ✓ |
|
|
312
|
+
| `/draft` | View, sync, or post the review draft | ✓ |
|
|
313
|
+
| `/connect <service>` | Authenticate with a service | ✓ |
|
|
314
|
+
| `/model` | List available models from all providers | |
|
|
315
|
+
| `/model <provider/id>` | Set the active model | ✓ |
|
|
316
|
+
| `/index` | Index status, search, diagnostics, rebuild | partial |
|
|
317
|
+
| `/compact` | Summarise older context to free space | ✓ |
|
|
318
|
+
| `/compact reset` | Undo last compaction (before new messages) | ✓ |
|
|
319
|
+
| `/session` | List, inspect, or delete sessions | partial |
|
|
320
|
+
| `/stats` | Show session token and cost statistics | ✓ |
|
|
321
|
+
| `/memory` | List, extract, or purge cross-session facts | partial |
|
|
322
|
+
| `/skill` | List or load a skill | ✓ |
|
|
323
|
+
| `/reload` | Show active prompt sources | |
|
|
324
|
+
| `/new` | Start a new conversation | |
|
|
325
|
+
| `/quit` | Exit (also `/q`) | |
|
|
326
|
+
|
|
327
|
+
The **Context** column shows which commands produce
|
|
328
|
+
[context markers](#context-markers) for the model.
|
|
329
|
+
`partial` means some subcommands emit markers (e.g.
|
|
330
|
+
`/index status` does, `/index search` does not).
|
|
331
|
+
|
|
332
|
+
## Providers
|
|
333
|
+
|
|
334
|
+
rbtr connects to LLMs through multiple providers. Use `/connect`
|
|
335
|
+
to authenticate:
|
|
336
|
+
|
|
337
|
+
| Provider | Auth | Command |
|
|
338
|
+
| ---------- | ------------------ | -------------------------------------- |
|
|
339
|
+
| Claude | OAuth (Pro/Max) | `/connect claude` |
|
|
340
|
+
| ChatGPT | OAuth (Plus/Pro) | `/connect chatgpt` |
|
|
341
|
+
| Google | OAuth (free) | `/connect google` |
|
|
342
|
+
| OpenAI | API key | `/connect openai sk-...` |
|
|
343
|
+
| Fireworks | API key | `/connect fireworks fw-...` |
|
|
344
|
+
| OpenRouter | API key | `/connect openrouter sk-or-...` |
|
|
345
|
+
| Endpoint | URL + optional key | `/connect endpoint <name> <url> [key]` |
|
|
346
|
+
|
|
347
|
+
Multiple providers can be connected at the same time. Tab on
|
|
348
|
+
`/connect` autocompletes provider names.
|
|
349
|
+
|
|
350
|
+
### Endpoints
|
|
351
|
+
|
|
352
|
+
Any OpenAI-compatible API can be used as a custom endpoint:
|
|
353
|
+
|
|
354
|
+
```text
|
|
355
|
+
you: /connect endpoint deepinfra https://api.deepinfra.com/v1/openai di-...
|
|
356
|
+
you: /connect endpoint ollama http://localhost:11434/v1
|
|
357
|
+
you: /model deepinfra/meta-llama/Meta-Llama-3.1-70B-Instruct
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Endpoints are first-class providers — they appear in `/model`
|
|
361
|
+
listings, support tab completion, and participate in the same
|
|
362
|
+
dispatch pipeline as builtin providers.
|
|
363
|
+
|
|
364
|
+
### GitHub
|
|
365
|
+
|
|
366
|
+
rbtr uses GitHub to fetch PRs and branches for review. Authenticate
|
|
367
|
+
with `/connect github` (device flow). This is separate from LLM
|
|
368
|
+
providers — it gives rbtr read access to your repositories.
|
|
369
|
+
|
|
370
|
+
## Models
|
|
371
|
+
|
|
372
|
+
Models use `<provider>/<model-id>` format:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
/model claude/claude-sonnet-4-20250514
|
|
376
|
+
/model chatgpt/gpt-5.2-codex
|
|
377
|
+
/model openai/gpt-4o
|
|
378
|
+
/model deepinfra/meta-llama/Meta-Llama-3.1-70B-Instruct
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Listing models
|
|
382
|
+
|
|
383
|
+
`/model` with no argument shows all models from connected providers,
|
|
384
|
+
marking the active one:
|
|
385
|
+
|
|
386
|
+
```text
|
|
387
|
+
you: /model
|
|
388
|
+
claude:
|
|
389
|
+
claude/claude-sonnet-4-20250514 ◂
|
|
390
|
+
claude/claude-opus-4-20250514
|
|
391
|
+
chatgpt:
|
|
392
|
+
chatgpt/o3-pro
|
|
393
|
+
chatgpt/gpt-5.2-codex
|
|
394
|
+
deepinfra:
|
|
395
|
+
deepinfra/meta-llama/Meta-Llama-3.1-70B-Instruct
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Providers that don't expose a model listing show a hint instead:
|
|
399
|
+
|
|
400
|
+
```text
|
|
401
|
+
ollama:
|
|
402
|
+
/model ollama/<model-id>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
The model list is fetched lazily on first Tab completion or
|
|
406
|
+
`/model` command, and refreshed on every `/connect`.
|
|
407
|
+
|
|
408
|
+
### Switching models mid-conversation
|
|
409
|
+
|
|
410
|
+
Conversation history is preserved when you switch models.
|
|
411
|
+
PydanticAI's message format is provider-agnostic, so previous
|
|
412
|
+
messages are converted automatically. When a provider rejects
|
|
413
|
+
history from a different provider (mismatched tool-call
|
|
414
|
+
formats, thinking metadata), rbtr repairs the history in
|
|
415
|
+
memory — the original messages are never modified:
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
you: explain the retry logic in src/client.py
|
|
419
|
+
claude/claude-sonnet-4-20250514: The retry logic uses exponential backoff…
|
|
420
|
+
|
|
421
|
+
you: /model chatgpt/o3-pro
|
|
422
|
+
Model set to chatgpt/o3-pro
|
|
423
|
+
|
|
424
|
+
you: what do you think about adding jitter?
|
|
425
|
+
chatgpt/o3-pro: Based on the retry logic we discussed…
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Only `/new` clears history (explicit user action). The active model is
|
|
429
|
+
persisted to `config.toml` across restarts. Conversation messages are
|
|
430
|
+
saved automatically to the session database (see Sessions below).
|
|
431
|
+
|
|
432
|
+
## Terminal reference
|
|
433
|
+
|
|
434
|
+
### Shell commands
|
|
435
|
+
|
|
436
|
+
Prefix any command with `!` to run it in a shell:
|
|
437
|
+
|
|
438
|
+
```text
|
|
439
|
+
you: !git log --oneline -5
|
|
440
|
+
you: !rg "TODO" src/
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Long output is truncated — press **Ctrl+O** to expand it.
|
|
444
|
+
|
|
445
|
+
### Tab completion
|
|
446
|
+
|
|
447
|
+
| Context | Example | Completes |
|
|
448
|
+
| -------------- | ------------------ | ----------------------- |
|
|
449
|
+
| Slash commands | `/rev` → `/review` | Command names |
|
|
450
|
+
| Command args | `/connect c` | Providers, models, etc. |
|
|
451
|
+
| Shell commands | `!git ch` | Bash completion |
|
|
452
|
+
| File paths | `!cat ~/Doc` | Directories and files |
|
|
453
|
+
|
|
454
|
+
### Key bindings
|
|
455
|
+
|
|
456
|
+
| Key | Action |
|
|
457
|
+
| ----------------------- | ---------------------------------------- |
|
|
458
|
+
| Enter | Submit input |
|
|
459
|
+
| Shift+Enter / Alt+Enter | Insert newline (multiline input) |
|
|
460
|
+
| Tab | Autocomplete |
|
|
461
|
+
| Shift+Tab | Cycle thinking effort level |
|
|
462
|
+
| Up/Down | Browse history or navigate multiline |
|
|
463
|
+
| Ctrl+C | Cancel running task (double-tap to quit) |
|
|
464
|
+
| Ctrl+O | Expand truncated shell output |
|
|
465
|
+
|
|
466
|
+
### Pasting
|
|
467
|
+
|
|
468
|
+
Bracketed paste is enabled — pasted newlines insert into the
|
|
469
|
+
prompt instead of submitting. Large pastes collapse into an
|
|
470
|
+
atomic marker (`[pasted 42 lines]`) that expands on submit.
|
|
471
|
+
|
|
472
|
+
### Context markers
|
|
473
|
+
|
|
474
|
+
After a slash command or shell command, a context marker
|
|
475
|
+
appears above your input — a tag like `[/review → PR #42]`
|
|
476
|
+
or `[! git log — exit 0]`. On submit, markers expand into a
|
|
477
|
+
`[Recent actions]` block prepended to your message so the
|
|
478
|
+
model knows what you just did. Backspace at the start of the
|
|
479
|
+
input dismisses the last marker. Not every command produces
|
|
480
|
+
a marker — only those whose outcome is useful to the model.
|
|
481
|
+
|
|
482
|
+
## Usage display
|
|
483
|
+
|
|
484
|
+
The footer shows token usage and context after each response:
|
|
485
|
+
|
|
486
|
+
```text
|
|
487
|
+
owner/repo claude/claude-sonnet-4-20250514
|
|
488
|
+
PR #42 · feature-branch |7| 12% of 200k ↑24.3k ↓1.2k ↯18.0k $0.045
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
`|7|` messages, `12%` context used, `↑` input tokens,
|
|
492
|
+
`↓` output tokens, `↯` cache-read tokens, `$` cost.
|
|
493
|
+
Colours shift from green to yellow to red as context fills.
|
|
494
|
+
`/new` resets all counters.
|
|
495
|
+
|
|
496
|
+
## Sessions
|
|
497
|
+
|
|
498
|
+
Every conversation is saved to a local SQLite database at
|
|
499
|
+
`~/.config/rbtr/sessions.db`. Messages are persisted as they
|
|
500
|
+
stream — if rbtr crashes, the conversation survives up to the
|
|
501
|
+
last received part. Requests are always persisted before their
|
|
502
|
+
responses, so resumed sessions load in the correct order.
|
|
503
|
+
|
|
504
|
+
### Persistence
|
|
505
|
+
|
|
506
|
+
The message format is provider-agnostic. History is preserved
|
|
507
|
+
across `/model` switches — only `/new` clears it. rbtr
|
|
508
|
+
repairs history automatically in memory on every turn — the
|
|
509
|
+
original messages are never modified. Preventive repairs
|
|
510
|
+
(sanitising cross-provider field values, patching cancelled
|
|
511
|
+
tool calls) run before each API call. When a provider still
|
|
512
|
+
rejects the history, escalating structural repairs retry
|
|
513
|
+
automatically. All repairs are recorded as incidents, visible
|
|
514
|
+
in `/stats`.
|
|
515
|
+
|
|
516
|
+
Ctrl+C during a tool-calling turn cancels immediately. Any tool
|
|
517
|
+
calls without results get synthetic `(cancelled)` returns so
|
|
518
|
+
the conversation can continue:
|
|
519
|
+
|
|
520
|
+
```text
|
|
521
|
+
⚠ Previous turn was cancelled mid-tool-call (read_file, grep).
|
|
522
|
+
Those tool results are lost — the model will continue without them.
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
See [Conversation storage](ARCHITECTURE.md#conversation-storage)
|
|
526
|
+
and [Cross-provider history repair](ARCHITECTURE.md#cross-provider-history-repair)
|
|
527
|
+
in ARCHITECTURE.md.
|
|
528
|
+
|
|
529
|
+
### `/new` — starting fresh
|
|
530
|
+
|
|
531
|
+
`/new` clears the in-memory conversation (history, usage
|
|
532
|
+
counters) and generates a new session ID. The previous session's
|
|
533
|
+
data stays in the database — it can be listed with `/session` and
|
|
534
|
+
resumed with `/session resume`.
|
|
535
|
+
|
|
536
|
+
### `/session` command
|
|
537
|
+
|
|
538
|
+
```text
|
|
539
|
+
/session List recent sessions (current repo)
|
|
540
|
+
/session all List sessions across all repos
|
|
541
|
+
/session info Show current session details
|
|
542
|
+
/session rename <n> Rename the current session
|
|
543
|
+
/session resume <q> Resume a session (ID prefix or label)
|
|
544
|
+
/session delete <id> Delete a session by ID prefix
|
|
545
|
+
/session purge 7d Delete sessions older than 7 days
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
**`/session rename`** changes the label on the current session.
|
|
549
|
+
Labels are set automatically when a review target is selected
|
|
550
|
+
(e.g. `acme/app — main → feature-x`), but you can override
|
|
551
|
+
them with any name.
|
|
552
|
+
|
|
553
|
+
**`/session resume`** accepts an ID prefix or a label substring
|
|
554
|
+
(case-insensitive). ID prefix is tried first; if no match,
|
|
555
|
+
the label is searched. When several sessions share a label the
|
|
556
|
+
most recent one is picked.
|
|
557
|
+
|
|
558
|
+
**`/session resume`** loads the target session's messages from the
|
|
559
|
+
database and switches the active session ID. The conversation
|
|
560
|
+
continues where it left off — the model sees the full history.
|
|
561
|
+
If the session had a review target (PR or branch), it's
|
|
562
|
+
automatically restored — rbtr re-runs `/review` to fetch fresh
|
|
563
|
+
metadata and rebuild the code index.
|
|
564
|
+
You can resume sessions from different repos or different models.
|
|
565
|
+
|
|
566
|
+
**`/session delete`** requires an exact ID prefix — no label
|
|
567
|
+
matching, to prevent accidental deletion. Removes all fragments
|
|
568
|
+
for the session (cascading via foreign keys). You cannot delete
|
|
569
|
+
the active session — use `/new` first.
|
|
570
|
+
|
|
571
|
+
### Automatic behaviour
|
|
572
|
+
|
|
573
|
+
- **New session on startup.** Each `rbtr` invocation starts a fresh
|
|
574
|
+
session, labelled with the current repo and branch. When you
|
|
575
|
+
select a review target, the label updates to show the base and
|
|
576
|
+
head branches (e.g. `acme/app — main → feature-x`).
|
|
577
|
+
- **Streaming persistence.** Parts are saved to the database as
|
|
578
|
+
they arrive from the model, not batched after the turn.
|
|
579
|
+
- **Input history from the database.** Up/Down arrow browses input
|
|
580
|
+
history across all sessions, deduplicated and sorted by recency.
|
|
581
|
+
|
|
582
|
+
### Pruning old sessions
|
|
583
|
+
|
|
584
|
+
Sessions accumulate over time. Use `/session purge` to clean up:
|
|
585
|
+
|
|
586
|
+
```text
|
|
587
|
+
/session purge 7d Delete sessions older than 7 days
|
|
588
|
+
/session purge 2w Delete sessions older than 2 weeks
|
|
589
|
+
/session purge 24h Delete sessions older than 24 hours
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
Duration suffixes: `d` (days), `w` (weeks), `h` (hours). The
|
|
593
|
+
active session is never deleted. To remove a specific session,
|
|
594
|
+
use `/session delete <id>`.
|
|
595
|
+
|
|
596
|
+
### `/stats` command
|
|
597
|
+
|
|
598
|
+
```text
|
|
599
|
+
/stats Current session statistics
|
|
600
|
+
/stats <id> Stats for a specific session (prefix match)
|
|
601
|
+
/stats all Aggregate stats across all sessions
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Shows token usage (input, output, cache), cost, tool call
|
|
605
|
+
frequency, and — when the session has incidents — failure and
|
|
606
|
+
repair summaries.
|
|
607
|
+
|
|
608
|
+
#### Incident reporting
|
|
609
|
+
|
|
610
|
+
When an LLM call fails and rbtr auto-recovers, or when history
|
|
611
|
+
is manipulated to satisfy provider constraints, the event is
|
|
612
|
+
recorded as an **incident** in the session database (see
|
|
613
|
+
ARCHITECTURE.md — History repair). `/stats` surfaces these
|
|
614
|
+
when they exist:
|
|
615
|
+
|
|
616
|
+
```text
|
|
617
|
+
Failures (3)
|
|
618
|
+
history_format 2 recovered: 2
|
|
619
|
+
overflow 1 recovered: 1
|
|
620
|
+
|
|
621
|
+
History repairs (6)
|
|
622
|
+
repair_dangling 1 (cancelled_mid_tool_call)
|
|
623
|
+
consolidate_tool_returns 2 (cross_provider_retry)
|
|
624
|
+
demote_thinking 2 (cross_provider_retry)
|
|
625
|
+
flatten_tool_exchanges 1 (cross_provider_retry)
|
|
626
|
+
|
|
627
|
+
Recovery rate 100% 3/3
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
**Failures** are grouped by kind (`history_format`, `overflow`,
|
|
631
|
+
`tool_args`, `type_error`, `effort_unsupported`) with
|
|
632
|
+
recovered/failed sub-counts. **History repairs** are grouped by
|
|
633
|
+
strategy with the reason that triggered them. The **recovery
|
|
634
|
+
rate** shows what percentage of failures were automatically
|
|
635
|
+
resolved.
|
|
636
|
+
|
|
637
|
+
Sessions with no incidents show no extra sections — the output
|
|
638
|
+
is identical to before.
|
|
639
|
+
|
|
640
|
+
## Cross-session memory
|
|
641
|
+
|
|
642
|
+
rbtr learns facts from conversations and remembers them across
|
|
643
|
+
sessions. Facts are durable knowledge — project conventions,
|
|
644
|
+
architecture decisions, user preferences, recurring patterns
|
|
645
|
+
discovered during review.
|
|
646
|
+
|
|
647
|
+
Static project instructions belong in `AGENTS.md`. Facts are
|
|
648
|
+
what the agent learns on its own.
|
|
649
|
+
|
|
650
|
+
### How facts are created
|
|
651
|
+
|
|
652
|
+
Facts are extracted automatically at two points:
|
|
653
|
+
|
|
654
|
+
- **During compaction** — the extraction agent runs
|
|
655
|
+
concurrently with the summary agent, analysing the messages
|
|
656
|
+
being compacted.
|
|
657
|
+
- **After posting a review** — `/draft post` triggers
|
|
658
|
+
extraction on the full session, since completed reviews are
|
|
659
|
+
the richest source of project knowledge.
|
|
660
|
+
|
|
661
|
+
You can also trigger extraction manually with
|
|
662
|
+
`/memory extract`, or teach the agent directly — it has a
|
|
663
|
+
`remember` tool that saves facts on demand during
|
|
664
|
+
conversation.
|
|
665
|
+
|
|
666
|
+
### Scopes
|
|
667
|
+
|
|
668
|
+
Each fact has a scope:
|
|
669
|
+
|
|
670
|
+
- **global** — applies everywhere (e.g. "prefers British
|
|
671
|
+
English spelling")
|
|
672
|
+
- **repo** — specific to the current repository (e.g. "uses
|
|
673
|
+
pytest with the mocker fixture, not unittest.mock")
|
|
674
|
+
|
|
675
|
+
Repo-scoped facts are keyed by `owner/repo` and only
|
|
676
|
+
injected when working in that repository.
|
|
677
|
+
|
|
678
|
+
### Injection
|
|
679
|
+
|
|
680
|
+
At session start, active facts for the current scopes are
|
|
681
|
+
loaded and injected into the system prompt. Two caps control
|
|
682
|
+
what's included:
|
|
683
|
+
|
|
684
|
+
- `max_injected_facts` (default 20) — maximum number of
|
|
685
|
+
facts
|
|
686
|
+
- `max_injected_tokens` (default 2000) — token budget for
|
|
687
|
+
injected facts
|
|
688
|
+
|
|
689
|
+
Facts are ordered by `last_confirmed_at` (most recently
|
|
690
|
+
confirmed first), so frequently re-observed facts take
|
|
691
|
+
priority.
|
|
692
|
+
|
|
693
|
+
### Deduplication
|
|
694
|
+
|
|
695
|
+
The extraction agent sees all existing facts and tags each
|
|
696
|
+
extraction as `new`, `confirm` (re-observed), or `supersede`
|
|
697
|
+
(replaces an outdated fact). Matching is content-based — no
|
|
698
|
+
opaque IDs are exposed to the LLM. When the LLM's reference
|
|
699
|
+
doesn't exactly match, a clarification retry corrects the
|
|
700
|
+
mismatch.
|
|
701
|
+
|
|
702
|
+
### `/memory` command
|
|
703
|
+
|
|
704
|
+
```text
|
|
705
|
+
/memory List active facts by scope
|
|
706
|
+
/memory all Include superseded facts
|
|
707
|
+
/memory extract Extract facts from the current session
|
|
708
|
+
/memory purge 7d Delete facts not confirmed in 7 days
|
|
709
|
+
/memory purge 2w Delete facts older than 2 weeks
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
Purge uses `last_confirmed_at` — facts that are regularly
|
|
713
|
+
re-observed survive longer. Duration suffixes: `d` (days),
|
|
714
|
+
`w` (weeks), `h` (hours).
|
|
715
|
+
|
|
716
|
+
### Memory configuration
|
|
717
|
+
|
|
718
|
+
```toml
|
|
719
|
+
[memory]
|
|
720
|
+
enabled = true # Toggle the feature
|
|
721
|
+
max_injected_facts = 20 # Facts in system prompt
|
|
722
|
+
max_injected_tokens = 2000 # Token budget for injection
|
|
723
|
+
max_extraction_facts = 200 # Existing facts shown to extraction agent
|
|
724
|
+
fact_extraction_model = "" # Override model (empty = session model)
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
## Skills
|
|
728
|
+
|
|
729
|
+
Skills are self-contained instruction packages — a markdown
|
|
730
|
+
file with optional bundled scripts — that teach the model
|
|
731
|
+
new capabilities. rbtr discovers skills automatically from
|
|
732
|
+
multiple directories and presents them in the system prompt.
|
|
733
|
+
|
|
734
|
+
rbtr scans the same skill directories as pi and Claude Code,
|
|
735
|
+
so existing skills work with zero configuration:
|
|
736
|
+
|
|
737
|
+
```text
|
|
738
|
+
~/.config/rbtr/skills/ # user-level rbtr skills
|
|
739
|
+
~/.claude/skills/ # Claude Code skills
|
|
740
|
+
~/.pi/agent/skills/ # pi skills
|
|
741
|
+
~/.agents/skills/ # Agent Skills standard
|
|
742
|
+
.rbtr/skills/ # project-level (any ancestor to git root)
|
|
743
|
+
.claude/skills/ # project-level Claude Code
|
|
744
|
+
.pi/skills/ # project-level pi
|
|
745
|
+
.agents/skills/ # project-level Agent Skills
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
Skills use the [Agent Skills standard][agent-skills] format:
|
|
749
|
+
a markdown file with YAML frontmatter (`name`, `description`).
|
|
750
|
+
The model sees a catalog of available skills in its system
|
|
751
|
+
prompt and reads the full skill file on demand via `read_file`.
|
|
752
|
+
|
|
753
|
+
[agent-skills]: https://agentskills.io/specification
|
|
754
|
+
|
|
755
|
+
### `/skill` command
|
|
756
|
+
|
|
757
|
+
```text
|
|
758
|
+
/skill List discovered skills
|
|
759
|
+
/skill brave-search Load a skill into context
|
|
760
|
+
/skill brave-search "query" Load with a follow-up message
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Tab-completes skill names. Skills marked with
|
|
764
|
+
`disable-model-invocation: true` are hidden from the prompt
|
|
765
|
+
catalog but still loadable via `/skill`.
|
|
766
|
+
|
|
767
|
+
### Configuration
|
|
768
|
+
|
|
769
|
+
```toml
|
|
770
|
+
[skills]
|
|
771
|
+
project_dirs = [".rbtr/skills", ".claude/skills", ".pi/skills", ".agents/skills"]
|
|
772
|
+
user_dirs = ["~/.config/rbtr/skills", "~/.claude/skills", "~/.pi/agent/skills", "~/.agents/skills"]
|
|
773
|
+
extra_dirs = []
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
Set `project_dirs = []` or `user_dirs = []` to disable
|
|
777
|
+
scanning. `extra_dirs` adds directories on top.
|
|
778
|
+
|
|
779
|
+
## Context compaction
|
|
780
|
+
|
|
781
|
+
Long conversations fill the context window. rbtr compacts
|
|
782
|
+
automatically — summarising older messages while keeping
|
|
783
|
+
recent turns intact.
|
|
784
|
+
|
|
785
|
+
Compaction splits the conversation by turn boundaries. A turn
|
|
786
|
+
starts at a user prompt and includes the model's responses,
|
|
787
|
+
tool calls, and tool results. The last `keep_turns` (default 2)
|
|
788
|
+
are preserved; everything older is serialised and sent to the
|
|
789
|
+
model for summarisation. The original messages stay in the
|
|
790
|
+
database for auditing.
|
|
791
|
+
|
|
792
|
+
### Example
|
|
793
|
+
|
|
794
|
+
Before (5 turns):
|
|
795
|
+
|
|
796
|
+
```text
|
|
797
|
+
turn 1: user "set up the project" → assistant "done"
|
|
798
|
+
turn 2: user "add authentication" → assistant [tools] → "added auth"
|
|
799
|
+
turn 3: user "write tests for auth" → assistant [tools] → "added 12 tests"
|
|
800
|
+
turn 4: user "fix the failing test" → assistant [tools] → "fixed assertion"
|
|
801
|
+
turn 5: user "review the PR" → assistant [reading files...]
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
After (turns 1–3 summarised, 4–5 kept):
|
|
805
|
+
|
|
806
|
+
```text
|
|
807
|
+
summary: "[Context summary] Set up project. Added auth
|
|
808
|
+
middleware. Wrote 12 tests for auth module."
|
|
809
|
+
turn 4: user "fix the failing test" → assistant "fixed assertion"
|
|
810
|
+
turn 5: user "review the PR" → assistant [reading files...]
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### When compaction triggers
|
|
814
|
+
|
|
815
|
+
- **Post-turn** — after a response, if context usage exceeds
|
|
816
|
+
`auto_compact_pct` (default 85%).
|
|
817
|
+
- **Mid-turn** — during a tool-calling cycle, if the threshold
|
|
818
|
+
is exceeded. Compacts once, reloads history, resumes the turn.
|
|
819
|
+
- **Overflow** — when the API rejects a request with a
|
|
820
|
+
context-length error. Compacts and retries.
|
|
821
|
+
- **Manual** — `/compact`, with optional extra instructions:
|
|
822
|
+
|
|
823
|
+
```text
|
|
824
|
+
you: /compact
|
|
825
|
+
you: /compact Focus on the authentication changes
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
`/compact reset` undoes the latest compaction, restoring the
|
|
829
|
+
original messages. Only allowed before new messages are sent.
|
|
830
|
+
|
|
831
|
+
When the old messages are too large for a single summary
|
|
832
|
+
request, rbtr finds the largest prefix that fits, summarises
|
|
833
|
+
it, and pushes the rest into the kept portion.
|
|
834
|
+
|
|
835
|
+
### Settings
|
|
836
|
+
|
|
837
|
+
```toml
|
|
838
|
+
[compaction]
|
|
839
|
+
auto_compact_pct = 85 # trigger threshold (% of context)
|
|
840
|
+
keep_turns = 2 # recent turns to preserve
|
|
841
|
+
reserve_tokens = 16000 # reserved for the summary response
|
|
842
|
+
summary_max_chars = 2000 # max chars per tool result in input
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
See [Context compaction in ARCHITECTURE.md](ARCHITECTURE.md#context-compaction)
|
|
846
|
+
for the split algorithm, orphan handling, and reset mechanics.
|
|
847
|
+
|
|
848
|
+
## Configuration
|
|
849
|
+
|
|
850
|
+
User-level files live in `~/.config/rbtr/` (override with
|
|
851
|
+
`RBTR_USER_DIR`). A workspace overlay at `.rbtr/config.toml`
|
|
852
|
+
can override per-project settings — the nearest `.rbtr/`
|
|
853
|
+
walking from CWD to the git root wins (monorepo-friendly).
|
|
854
|
+
|
|
855
|
+
- **`config.toml`** — model, endpoints, feature settings.
|
|
856
|
+
- **`creds.toml`** — API keys and OAuth tokens (0600).
|
|
857
|
+
|
|
858
|
+
```toml
|
|
859
|
+
# config.toml
|
|
860
|
+
model = "claude/claude-sonnet-4-20250514"
|
|
861
|
+
|
|
862
|
+
[endpoints.deepinfra]
|
|
863
|
+
base_url = "https://api.deepinfra.com/v1/openai"
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
Config values can also be set via environment variables with
|
|
867
|
+
`RBTR_` prefix (e.g. `RBTR_MODEL`). OAuth tokens are managed
|
|
868
|
+
by `/connect` — you never need to edit `creds.toml` by hand.
|
|
869
|
+
|
|
870
|
+
### Customising the prompt
|
|
871
|
+
|
|
872
|
+
Three levels of customisation, loaded in order:
|
|
873
|
+
|
|
874
|
+
1. **`AGENTS.md`** (repo root) — project-specific rules.
|
|
875
|
+
Configure the file list with
|
|
876
|
+
`project_instructions = ["AGENTS.md"]`.
|
|
877
|
+
2. **`~/.config/rbtr/APPEND_SYSTEM.md`** — user-wide
|
|
878
|
+
preferences appended to the system prompt.
|
|
879
|
+
3. **`~/.config/rbtr/SYSTEM.md`** — full system prompt
|
|
880
|
+
replacement (Jinja template with `project_instructions`
|
|
881
|
+
and `append_system` variables).
|
|
882
|
+
|
|
883
|
+
Example `AGENTS.md`:
|
|
884
|
+
|
|
885
|
+
```markdown
|
|
886
|
+
- Target Python 3.13+. Use modern features.
|
|
887
|
+
- All code must be type-annotated.
|
|
888
|
+
- Run `just check` after every change.
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
## Code index
|
|
892
|
+
|
|
893
|
+
When you start a review (`/review`), rbtr builds a structural index
|
|
894
|
+
of the repository in the background. The index gives the LLM tools
|
|
895
|
+
to search, navigate, and reason about the codebase — not just the
|
|
896
|
+
diff.
|
|
897
|
+
|
|
898
|
+
### What gets indexed
|
|
899
|
+
|
|
900
|
+
rbtr extracts **chunks** (functions, classes, methods, imports,
|
|
901
|
+
doc sections) from every file in the repo at the base commit, then
|
|
902
|
+
incrementally indexes the head commit. Each chunk records its name,
|
|
903
|
+
kind, file path, line range, and content.
|
|
904
|
+
|
|
905
|
+
Cross-file **edges** are inferred automatically:
|
|
906
|
+
|
|
907
|
+
- **Import edges** — structural (from tree-sitter import metadata)
|
|
908
|
+
or text-search fallback for languages without an extractor.
|
|
909
|
+
- **Test edges** — `test_foo.py` → `foo.py` by naming convention
|
|
910
|
+
and import analysis.
|
|
911
|
+
- **Doc edges** — markdown/RST sections that mention function or
|
|
912
|
+
class names.
|
|
913
|
+
|
|
914
|
+
**Embeddings** are computed for semantic search using a local GGUF
|
|
915
|
+
model (bge-m3, quantized, runs on Metal/CPU — no API calls). The
|
|
916
|
+
structural index is usable immediately; embeddings fill in behind
|
|
917
|
+
it.
|
|
918
|
+
|
|
919
|
+
### Progress indicator
|
|
920
|
+
|
|
921
|
+
The footer shows indexing progress:
|
|
922
|
+
|
|
923
|
+
```text
|
|
924
|
+
⟳ parsing 42/177 (extracting chunks)
|
|
925
|
+
⟳ embedding 85/380 (computing vectors)
|
|
926
|
+
● 1.2k (ready — 1,200 chunks indexed)
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
The review proceeds immediately — you don't have to wait for
|
|
930
|
+
indexing to finish.
|
|
931
|
+
|
|
932
|
+
### `/index` command
|
|
933
|
+
|
|
934
|
+
| Subcommand | Description |
|
|
935
|
+
| ---------------------------- | ---------------------------------------- |
|
|
936
|
+
| `/index` | Show index status (chunks, edges, size) |
|
|
937
|
+
| `/index clear` | Delete the index database |
|
|
938
|
+
| `/index rebuild` | Clear and re-index from scratch |
|
|
939
|
+
| `/index prune` | Remove orphan chunks not in any snapshot |
|
|
940
|
+
| `/index model` | Show current embedding model |
|
|
941
|
+
| `/index model <id>` | Switch embedding model and re-embed |
|
|
942
|
+
| `/index search <query>` | Search the index and show ranked results |
|
|
943
|
+
| `/index search-diag <query>` | Search with full signal breakdown table |
|
|
944
|
+
|
|
945
|
+
### Index configuration
|
|
946
|
+
|
|
947
|
+
```toml
|
|
948
|
+
[index]
|
|
949
|
+
enabled = true
|
|
950
|
+
embedding_model = "gpustack/bge-m3-GGUF/bge-m3-Q4_K_M.gguf"
|
|
951
|
+
include = [".rbtr/notes/*"] # force-include (override .gitignore)
|
|
952
|
+
extend_exclude = [".rbtr/index"] # exclude on top of .gitignore
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
The index is persistent — subsequent `/review` runs skip
|
|
956
|
+
unchanged files (keyed by git blob SHA).
|
|
957
|
+
|
|
958
|
+
### Graceful degradation
|
|
959
|
+
|
|
960
|
+
- **No grammar installed** for a language → falls back to
|
|
961
|
+
line-based plaintext chunking.
|
|
962
|
+
- **No embedding model** (missing GGUF, GPU init failure) →
|
|
963
|
+
structural index works, semantic search signal is skipped
|
|
964
|
+
(weight redistributed to name and keyword channels).
|
|
965
|
+
- **Slow indexing** → review starts immediately, index catches
|
|
966
|
+
up in a background thread.
|
|
967
|
+
|
|
968
|
+
## Review draft
|
|
969
|
+
|
|
970
|
+
The LLM builds a structured review using draft tools
|
|
971
|
+
(`add_draft_comment`, `set_draft_summary`, etc.). The draft
|
|
972
|
+
persists to `.rbtr/drafts/<pr>.yaml` — crash-safe, human-
|
|
973
|
+
editable, and synced bidirectionally with GitHub.
|
|
974
|
+
|
|
975
|
+
### Workflow
|
|
976
|
+
|
|
977
|
+
1. `/review 42` — fetches the PR, pulls any existing
|
|
978
|
+
pending review from GitHub.
|
|
979
|
+
2. The LLM adds comments and a summary as it reviews.
|
|
980
|
+
3. `/draft` — inspect the current state.
|
|
981
|
+
4. `/draft sync` — bidirectional sync with GitHub
|
|
982
|
+
(three-way merge, conflicts resolve to local).
|
|
983
|
+
5. `/draft post` — submit the review. Optional event type:
|
|
984
|
+
`approve`, `request_changes` (default `COMMENT`).
|
|
985
|
+
|
|
986
|
+
### Draft commands
|
|
987
|
+
|
|
988
|
+
| Subcommand | Description |
|
|
989
|
+
| --------------------- | ------------------------------------- |
|
|
990
|
+
| `/draft` | Show draft with sync status |
|
|
991
|
+
| `/draft sync` | Bidirectional sync with GitHub |
|
|
992
|
+
| `/draft post [event]` | Submit review to GitHub |
|
|
993
|
+
| `/draft clear` | Delete local draft and remote pending |
|
|
994
|
+
|
|
995
|
+
### Status indicators
|
|
996
|
+
|
|
997
|
+
| Indicator | Meaning |
|
|
998
|
+
| --------- | -------------------------------------- |
|
|
999
|
+
| `✓` | Synced — matches last-pushed snapshot |
|
|
1000
|
+
| `✎` | Modified locally since last sync |
|
|
1001
|
+
| `★` | New — never synced to GitHub |
|
|
1002
|
+
| `✗` | Deleted — will be removed on next sync |
|
|
1003
|
+
|
|
1004
|
+
### Safety
|
|
1005
|
+
|
|
1006
|
+
- **Unsynced guard** — `/draft post` refuses if the remote
|
|
1007
|
+
has comments not in the local draft.
|
|
1008
|
+
- **Atomic posting** — all comments are submitted in one
|
|
1009
|
+
API call.
|
|
1010
|
+
- **Crash-safe** — YAML on disk, updated on every mutation.
|
|
1011
|
+
Mid-sync crashes recover on the next sync.
|
|
1012
|
+
- **GitHub suggestions** — the LLM can provide replacement
|
|
1013
|
+
code; it's posted as a suggestion block that the author
|
|
1014
|
+
can apply with one click.
|
|
1015
|
+
|
|
1016
|
+
See [Review draft and GitHub integration][arch-draft]
|
|
1017
|
+
in ARCHITECTURE.md for sync internals.
|
|
1018
|
+
|
|
1019
|
+
[arch-draft]: ARCHITECTURE.md#review-draft-and-github-integration
|
|
1020
|
+
|
|
1021
|
+
## Theme
|
|
1022
|
+
|
|
1023
|
+
rbtr defaults to a dark palette with semantically tinted panel
|
|
1024
|
+
backgrounds. Switch to light mode or override individual
|
|
1025
|
+
styles in `config.toml`:
|
|
1026
|
+
|
|
1027
|
+
```toml
|
|
1028
|
+
[theme]
|
|
1029
|
+
mode = "light" # "dark" (default) or "light"
|
|
1030
|
+
|
|
1031
|
+
[theme.light] # override fields for the active mode
|
|
1032
|
+
bg_succeeded = "on #E0FFE0"
|
|
1033
|
+
prompt = "bold magenta"
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
Text styles use ANSI names (`bold cyan`, `dim`, `yellow`, …)
|
|
1037
|
+
that adapt to your terminal's colour scheme. Panel backgrounds
|
|
1038
|
+
use hex values. Any string that Rich accepts as a
|
|
1039
|
+
[style definition](https://rich.readthedocs.io/en/latest/style.html)
|
|
1040
|
+
is valid.
|
|
1041
|
+
|
|
1042
|
+
Available fields are defined in `PaletteConfig` in
|
|
1043
|
+
[`config.py`](src/rbtr/config.py).
|
|
1044
|
+
|
|
1045
|
+
## Development
|
|
1046
|
+
|
|
1047
|
+
```bash
|
|
1048
|
+
uv sync # Install dependencies
|
|
1049
|
+
just check # Lint + typecheck + test
|
|
1050
|
+
just fmt # Auto-fix and format
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
### Architecture reference
|
|
1054
|
+
|
|
1055
|
+
For details on how providers, tools, the index, language
|
|
1056
|
+
plugins, session persistence, history repair, and GitHub sync
|
|
1057
|
+
work internally, see [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
1058
|
+
|
|
1059
|
+
### Git reference handling
|
|
1060
|
+
|
|
1061
|
+
rbtr never modifies your working tree or local branches.
|
|
1062
|
+
All reads go through the git object store.
|
|
1063
|
+
|
|
1064
|
+
When you select a PR, rbtr fetches the PR head and the
|
|
1065
|
+
base branch from origin so that diffs, commit logs, and
|
|
1066
|
+
changed-file lists reflect the actual PR scope — not stale
|
|
1067
|
+
local refs. For PRs, the exact base and head SHAs come from
|
|
1068
|
+
the GitHub API, so a local `main` that is behind
|
|
1069
|
+
`origin/main` cannot pollute the results. For local branch
|
|
1070
|
+
reviews, branch names are used directly.
|
|
1071
|
+
|
|
1072
|
+
Commit logs use `git log base..head` semantics — only
|
|
1073
|
+
commits reachable from head but not from base. Review
|
|
1074
|
+
comment validation diffs from the merge base of the two
|
|
1075
|
+
refs, matching GitHub's three-dot diff.
|
|
1076
|
+
|
|
1077
|
+
### Benchmarking
|
|
1078
|
+
|
|
1079
|
+
```bash
|
|
1080
|
+
just bench # quick benchmark (current repo)
|
|
1081
|
+
just bench -- /path/to/repo main # custom repo
|
|
1082
|
+
just bench -- . main feature # with incremental update
|
|
1083
|
+
just bench-scalene -- /path/to/repo # line-level CPU + memory profiling
|
|
1084
|
+
just scalene-view # view last scalene profile
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
Detailed results and optimization notes are in `PROFILING.md`.
|
|
1088
|
+
|
|
1089
|
+
### Search quality
|
|
1090
|
+
|
|
1091
|
+
The unified search system fuses three signals — name matching,
|
|
1092
|
+
BM25 keyword search, and semantic (embedding) similarity — with
|
|
1093
|
+
post-fusion adjustments for chunk kind and file category. Two
|
|
1094
|
+
scripts measure and tune search quality:
|
|
1095
|
+
|
|
1096
|
+
```bash
|
|
1097
|
+
just eval-search # evaluate against curated queries
|
|
1098
|
+
just tune-search # grid-search fusion weights
|
|
1099
|
+
just tune-search -- --step 0.05 # finer resolution (400 combos)
|
|
1100
|
+
just bench-search # replay real queries (current dir)
|
|
1101
|
+
just bench-search -- /path/to/repo # replay for a specific repo
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
**`scripts/eval_search.py`** — Runs 24+ curated queries against
|
|
1105
|
+
the rbtr repo, measuring recall@1, recall@5, and MRR across
|
|
1106
|
+
three backends (name, BM25, unified). Queries are grouped by
|
|
1107
|
+
the technique they test (tokenisation, IDF, kind scoring, file
|
|
1108
|
+
category, name matching, query understanding, structural
|
|
1109
|
+
signals). Results are tracked in `TODO-search.md`.
|
|
1110
|
+
|
|
1111
|
+
**`scripts/tune_search.py`** — Grid-searches over fusion weight
|
|
1112
|
+
combinations for each query kind (identifier / concept).
|
|
1113
|
+
Precomputes all channel scores once, then sweeps in-memory —
|
|
1114
|
+
runs in ~1s. Reports the top 10 weight combos and the current
|
|
1115
|
+
settings for comparison.
|
|
1116
|
+
|
|
1117
|
+
**`scripts/bench_search.py`** — Mines real search queries from
|
|
1118
|
+
the session history database (`~/.config/rbtr/sessions.db`).
|
|
1119
|
+
Pass a repo path (defaults to current directory), and the
|
|
1120
|
+
script filters to events matching that repo by remote URL.
|
|
1121
|
+
Extracts search→read pairs (search followed by `read_symbol`),
|
|
1122
|
+
detects retry chains, classifies queries, and replays paired
|
|
1123
|
+
queries through the current search pipeline. Reports R@1, R@5,
|
|
1124
|
+
MRR, and per-query signal breakdowns for misranked results.
|
|
1125
|
+
|
|
1126
|
+
`eval_search` and `tune_search` are rbtr-specific — they
|
|
1127
|
+
validate the repo identity via `pyproject.toml` before running.
|
|
1128
|
+
`bench_search` works with any repo that has session history.
|
|
1129
|
+
|
|
1130
|
+
For search internals (fusion algorithm, scoring functions,
|
|
1131
|
+
tokenisation), see [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
1132
|
+
|
|
1133
|
+
## License
|
|
1134
|
+
|
|
1135
|
+
MIT
|