brainpalace-cli 26.7.2__tar.gz → 26.7.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.
Files changed (115) hide show
  1. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/PKG-INFO +1 -1
  2. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/cli.py +2 -0
  3. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/__init__.py +2 -0
  4. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/records.py +42 -0
  5. brainpalace_cli-26.7.3/brainpalace_cli/commands/rules.py +164 -0
  6. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/verify_docs.py +23 -2
  7. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/pyproject.toml +1 -1
  8. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/README.md +0 -0
  9. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/__init__.py +0 -0
  10. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/__main__.py +0 -0
  11. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/ai_guidance.py +0 -0
  12. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/client/__init__.py +0 -0
  13. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/client/api_client.py +0 -0
  14. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/client/errors.py +0 -0
  15. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/_dashboard_url.py +0 -0
  16. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/ai_guide.py +0 -0
  17. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/backfill.py +0 -0
  18. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/bm25_project.py +0 -0
  19. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/cache.py +0 -0
  20. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/config.py +0 -0
  21. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/context.py +0 -0
  22. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/dashboard.py +0 -0
  23. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/doctor.py +0 -0
  24. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/estimate_util.py +0 -0
  25. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/extraction.py +0 -0
  26. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/extraction_drain.py +0 -0
  27. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/folders.py +0 -0
  28. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/graph.py +0 -0
  29. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/hook.py +0 -0
  30. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/index.py +0 -0
  31. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/init.py +0 -0
  32. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/init_plan.py +0 -0
  33. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/inject.py +0 -0
  34. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/install_agent.py +0 -0
  35. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/jobs.py +0 -0
  36. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/list_cmd.py +0 -0
  37. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/lsp.py +0 -0
  38. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/mcp.py +0 -0
  39. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/memories.py +0 -0
  40. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/plugin_detect.py +0 -0
  41. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/query.py +0 -0
  42. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/read_only.py +0 -0
  43. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/reap.py +0 -0
  44. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/recall.py +0 -0
  45. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/remember.py +0 -0
  46. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/reset.py +0 -0
  47. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/session_hooks.py +0 -0
  48. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/sessions.py +0 -0
  49. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/start.py +0 -0
  50. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/status.py +0 -0
  51. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/stop.py +0 -0
  52. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/sync_docs.py +0 -0
  53. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/types.py +0 -0
  54. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/uninstall.py +0 -0
  55. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/update.py +0 -0
  56. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/commands/whoami.py +0 -0
  57. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config.py +0 -0
  58. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_fields.py +0 -0
  59. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_migrate.py +0 -0
  60. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_parity.py +0 -0
  61. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_resolve.py +0 -0
  62. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_review.py +0 -0
  63. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/config_schema.py +0 -0
  64. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/data/__init__.py +0 -0
  65. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/data/ai_guidance.md +0 -0
  66. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/data/hooks/__init__.py +0 -0
  67. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/data/hooks/sessionstart-hook.sh +0 -0
  68. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/diagnostics.py +0 -0
  69. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/discovery.py +0 -0
  70. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/__init__.py +0 -0
  71. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/allowlist.py +0 -0
  72. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/__init__.py +0 -0
  73. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/base.py +0 -0
  74. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/cli_commands.py +0 -0
  75. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/config.py +0 -0
  76. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/endpoints.py +0 -0
  77. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/mcp.py +0 -0
  78. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/mode_parity_checker.py +0 -0
  79. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/modes.py +0 -0
  80. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/plugin_docs.py +0 -0
  81. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/provider_tables.py +0 -0
  82. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/checkers/skills.py +0 -0
  83. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/contract_parity.py +0 -0
  84. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/facts.py +0 -0
  85. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/generator.py +0 -0
  86. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/introspect.py +0 -0
  87. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/markers.py +0 -0
  88. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/mode_meta.py +0 -0
  89. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/mode_parity.py +0 -0
  90. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/orchestrator.py +0 -0
  91. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/referential.py +0 -0
  92. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/serializer.py +0 -0
  93. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/doc_sync/triggers.py +0 -0
  94. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/known_projects.py +0 -0
  95. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/lsp_install.py +0 -0
  96. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/mcp_server/__init__.py +0 -0
  97. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/mcp_server/lifecycle.py +0 -0
  98. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/mcp_server/schemas.py +0 -0
  99. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/mcp_server/server.py +0 -0
  100. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/mcp_server/tools.py +0 -0
  101. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/migration.py +0 -0
  102. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/optional_deps.py +0 -0
  103. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/prompt_render.py +0 -0
  104. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/providers.py +0 -0
  105. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/__init__.py +0 -0
  106. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/claude_converter.py +0 -0
  107. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/codex_converter.py +0 -0
  108. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/converter_base.py +0 -0
  109. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/gemini_converter.py +0 -0
  110. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/opencode_converter.py +0 -0
  111. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/parser.py +0 -0
  112. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/skill_runtime_converter.py +0 -0
  113. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/tool_maps.py +0 -0
  114. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/runtime/types.py +0 -0
  115. {brainpalace_cli-26.7.2 → brainpalace_cli-26.7.3}/brainpalace_cli/xdg_paths.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainpalace-cli
3
- Version: 26.7.2
3
+ Version: 26.7.3
4
4
  Summary: BrainPalace CLI - Command-line interface for managing AI agent memory and knowledge retrieval
5
5
  License: MIT
6
6
  Keywords: brainpalace,rag,cli,ai-memory,llm-memory,semantic-search,ai-agent,claude-code,agent-memory
@@ -37,6 +37,7 @@ from .commands import (
37
37
  records_group,
38
38
  remember_command,
39
39
  reset_command,
40
+ rules_group,
40
41
  session_path_command,
41
42
  start_command,
42
43
  status_command,
@@ -152,6 +153,7 @@ cli.add_command(install_agent_command, name="install-agent")
152
153
  cli.add_command(install_session_hooks_command, name="install-session-hooks")
153
154
  cli.add_command(backfill_command, name="backfill-sessions")
154
155
  cli.add_command(records_group, name="records")
156
+ cli.add_command(rules_group, name="rules")
155
157
  cli.add_command(extraction_group, name="extraction")
156
158
  cli.add_command(graph_group, name="graph")
157
159
 
@@ -25,6 +25,7 @@ from .recall import recall_command
25
25
  from .records import records_group
26
26
  from .remember import remember_command
27
27
  from .reset import reset_command
28
+ from .rules import rules_group
28
29
  from .session_hooks import install_session_hooks_command
29
30
  from .sessions import session_path_command, submit_session_command
30
31
  from .start import start_command
@@ -64,6 +65,7 @@ __all__ = [
64
65
  "recall_command",
65
66
  "remember_command",
66
67
  "reset_command",
68
+ "rules_group",
67
69
  "session_path_command",
68
70
  "start_command",
69
71
  "submit_session_command",
@@ -59,6 +59,48 @@ def records_stats(url: str | None, json_output: bool) -> None:
59
59
  raise SystemExit(1) from e
60
60
 
61
61
 
62
+ @records_group.command("recompute-salience")
63
+ @click.option(
64
+ "--url",
65
+ envvar="BRAINPALACE_URL",
66
+ default=None,
67
+ help="BrainPalace server URL (default: from config or http://127.0.0.1:8000)",
68
+ )
69
+ @click.option(
70
+ "--metric", "-m", default=None, help="Restrict recompute to this metric only."
71
+ )
72
+ @click.option("--json", "json_output", is_flag=True, help="Output as JSON")
73
+ def records_recompute_salience(
74
+ url: str | None, metric: str | None, json_output: bool
75
+ ) -> None:
76
+ """Re-score record salience with the registered scorer."""
77
+ resolved_url = url or get_server_url()
78
+ body: dict[str, str] = {}
79
+ if metric is not None:
80
+ body["metric"] = metric
81
+ try:
82
+ with DocServeClient(base_url=resolved_url) as client:
83
+ r = client._request("POST", "/records/recompute-salience", json=body)
84
+ if json_output:
85
+ import json as _json
86
+
87
+ click.echo(_json.dumps(r, indent=2))
88
+ else:
89
+ console.print(
90
+ f"[green]Recomputed salience for {r['rescored']} record(s).[/]"
91
+ )
92
+ except ConnectionError as e:
93
+ exit_on_connection_error(e, base_url=resolved_url, json_output=json_output)
94
+ except ServerError as e:
95
+ if json_output:
96
+ import json as _json
97
+
98
+ click.echo(_json.dumps({"error": str(e), "detail": e.detail}))
99
+ else:
100
+ console.print(f"[red]Server Error ({e.status_code}):[/] {e.detail}")
101
+ raise SystemExit(1) from e
102
+
103
+
62
104
  @records_group.command("revalidate")
63
105
  @click.option(
64
106
  "--url",
@@ -0,0 +1,164 @@
1
+ """CLI subcommands for durable taught confidence rules (Phase 5 / CO-3)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as _json
6
+ from typing import Any, Callable
7
+
8
+ import click
9
+ from rich.console import Console
10
+
11
+ from ..client import (
12
+ ConnectionError,
13
+ DocServeClient,
14
+ ServerError,
15
+ exit_on_connection_error,
16
+ )
17
+ from ..config import get_server_url
18
+
19
+ console = Console()
20
+
21
+
22
+ def _url(url: str | None) -> str:
23
+ return url or get_server_url()
24
+
25
+
26
+ _URL_OPT = click.option(
27
+ "--url",
28
+ envvar="BRAINPALACE_URL",
29
+ default=None,
30
+ help="BrainPalace server URL (default: from config or http://127.0.0.1:8000)",
31
+ )
32
+ _JSON_OPT = click.option("--json", "json_output", is_flag=True, help="Output as JSON")
33
+
34
+
35
+ @click.group("rules")
36
+ def rules_group() -> None:
37
+ """Manage durable taught confidence rules (compute-mode trust)."""
38
+
39
+
40
+ def _run(
41
+ resolved_url: str,
42
+ json_output: bool,
43
+ fn: Callable[[DocServeClient], Any],
44
+ ) -> Any:
45
+ try:
46
+ with DocServeClient(base_url=resolved_url) as client:
47
+ return fn(client)
48
+ except ConnectionError as e:
49
+ exit_on_connection_error(e, base_url=resolved_url, json_output=json_output)
50
+ except ServerError as e:
51
+ if json_output:
52
+ click.echo(_json.dumps({"error": str(e), "detail": e.detail}))
53
+ else:
54
+ console.print(f"[red]Server Error ({e.status_code}):[/] {e.detail}")
55
+ raise SystemExit(1) from e
56
+
57
+
58
+ @rules_group.command("list")
59
+ @_URL_OPT
60
+ @click.option("--all", "show_all", is_flag=True, help="Include retired rules")
61
+ @_JSON_OPT
62
+ def rules_list(url: str | None, show_all: bool, json_output: bool) -> None:
63
+ """List taught rules (active by default)."""
64
+ resolved = _url(url)
65
+
66
+ def _do(client: DocServeClient) -> None:
67
+ r = client._request("GET", "/rules", params={"active": not show_all})
68
+ if json_output:
69
+ click.echo(_json.dumps(r, indent=2))
70
+ else:
71
+ rules = r.get("rules") or []
72
+ if not rules:
73
+ console.print("[dim]no rules[/]")
74
+ for x in rules:
75
+ rng = f"[{x.get('value_min')}, {x.get('value_max')}]"
76
+ console.print(
77
+ f"[bold]{x['id']}[/] {x['metric']} "
78
+ f"{x.get('unit') or ''} {rng} -> {x['tier']} "
79
+ f"(v{x['version']}{' RETIRED' if x['retired_at'] else ''})"
80
+ )
81
+
82
+ _run(resolved, json_output, _do)
83
+
84
+
85
+ @rules_group.command("add")
86
+ @_URL_OPT
87
+ @click.option("--metric", "-m", required=True)
88
+ @click.option(
89
+ "--tier",
90
+ "-t",
91
+ required=True,
92
+ type=click.Choice(["HIGH", "PROVISIONAL", "UNVERIFIED"]),
93
+ )
94
+ @click.option("--unit", "-u", default=None)
95
+ @click.option("--min", "value_min", type=float, default=None)
96
+ @click.option("--max", "value_max", type=float, default=None)
97
+ @click.option("--owner", default="user")
98
+ @_JSON_OPT
99
+ def rules_add(
100
+ url: str | None,
101
+ metric: str,
102
+ tier: str,
103
+ unit: str | None,
104
+ value_min: float | None,
105
+ value_max: float | None,
106
+ owner: str,
107
+ json_output: bool,
108
+ ) -> None:
109
+ """Teach a confidence rule (promotes matching records)."""
110
+ resolved = _url(url)
111
+ body = {
112
+ "owner": owner,
113
+ "metric": metric,
114
+ "tier": tier,
115
+ "unit": unit,
116
+ "value_min": value_min,
117
+ "value_max": value_max,
118
+ }
119
+
120
+ def _do(client: DocServeClient) -> None:
121
+ r = client._request("POST", "/rules", json=body)
122
+ if json_output:
123
+ click.echo(_json.dumps(r, indent=2))
124
+ else:
125
+ console.print(f"[green]Rule added:[/] {r['id']}")
126
+
127
+ _run(resolved, json_output, _do)
128
+
129
+
130
+ @rules_group.command("retire")
131
+ @_URL_OPT
132
+ @click.argument("rule_id")
133
+ @_JSON_OPT
134
+ def rules_retire(url: str | None, rule_id: str, json_output: bool) -> None:
135
+ """Retire (soft-delete) a taught rule."""
136
+ resolved = _url(url)
137
+
138
+ def _do(client: DocServeClient) -> None:
139
+ r = client._request("POST", f"/rules/{rule_id}/retire")
140
+ if json_output:
141
+ click.echo(_json.dumps(r, indent=2))
142
+ else:
143
+ console.print(
144
+ "[green]Retired.[/]"
145
+ if r.get("retired")
146
+ else "[yellow]No active rule with that id.[/]"
147
+ )
148
+
149
+ _run(resolved, json_output, _do)
150
+
151
+
152
+ @rules_group.command("show")
153
+ @_URL_OPT
154
+ @click.argument("rule_id")
155
+ @_JSON_OPT
156
+ def rules_show(url: str | None, rule_id: str, json_output: bool) -> None:
157
+ """Show one taught rule by id."""
158
+ resolved = _url(url)
159
+
160
+ def _do(client: DocServeClient) -> None:
161
+ r = client._request("GET", f"/rules/{rule_id}")
162
+ click.echo(_json.dumps(r, indent=2))
163
+
164
+ _run(resolved, json_output, _do)
@@ -186,6 +186,22 @@ def _changed_paths(base: str) -> list[str]:
186
186
  return sorted(n for n in names if n)
187
187
 
188
188
 
189
+ def _default_base() -> str:
190
+ """Base ref for the `--changed` / `--check` net diff. `main` (the historical
191
+ Click default) is WRONG for this repo: `stable` (the working branch) and
192
+ `main` (the squashed publish mirror) have UNRELATED histories, so `main...HEAD`
193
+ is empty and the affected set collapses to nothing — the `--check` gate then
194
+ trivially passes and prose drift builds up unseen.
195
+
196
+ The real done-boundary is the PREVIOUS release: the most recent `release:`
197
+ commit reachable from HEAD. `before-push` runs at RELEASING step 8, before the
198
+ new release commit is made at step 9, so this always resolves to the prior
199
+ release — i.e. exactly the changes THIS release ships. Falls back to `main`
200
+ when no release commit exists (a fresh repo / non-release history)."""
201
+ rel = _git("log", "-E", "--grep=^release:", "--format=%H", "-1")
202
+ return rel[0] if rel else "main"
203
+
204
+
189
205
  #: Docs that are NEITHER verified by Layer B NOR usable as grounding for another
190
206
  #: doc's claim — historical / frozen / scratch material that describes PAST or
191
207
  #: INTENDED state, so grounding live code against it is meaningless (false verdicts
@@ -1601,7 +1617,10 @@ def _render_report(summary: dict[str, Any]) -> str:
1601
1617
  help="Verify the net-diff affected set (done-boundary).",
1602
1618
  )
1603
1619
  @click.option(
1604
- "--base", default="main", help="Base ref for --changed net diff (default: main)."
1620
+ "--base",
1621
+ default=None,
1622
+ help="Base ref for --changed net diff (default: the previous `release:` "
1623
+ "commit; `main` is degenerate here — unrelated histories).",
1605
1624
  )
1606
1625
  @click.option(
1607
1626
  "--record",
@@ -1670,7 +1689,7 @@ def verify_docs_command(
1670
1689
  paths: tuple[str, ...],
1671
1690
  all_docs: bool,
1672
1691
  changed: bool,
1673
- base: str,
1692
+ base: str | None,
1674
1693
  record_file: str | None,
1675
1694
  check_marker: bool,
1676
1695
  resettle: bool,
@@ -1711,6 +1730,8 @@ def verify_docs_command(
1711
1730
  lists CONTRADICTED + UNVERIFIABLE (PENDING stays silent).
1712
1731
  """
1713
1732
  _require_repo()
1733
+ if base is None:
1734
+ base = _default_base()
1714
1735
  if check_marker:
1715
1736
  # B5 process gate (advisory, opt-in for pre-push wiring): did verify-docs
1716
1737
  # run for THIS diff? Compares the current net-diff fingerprint to the one
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "brainpalace-cli"
3
- version = "26.7.2"
3
+ version = "26.7.3"
4
4
  description = "BrainPalace CLI - Command-line interface for managing AI agent memory and knowledge retrieval"
5
5
  authors = ["bxw91"]
6
6
  readme = "README.md"