diff --git a/README.md b/README.md
index 4ebf53b..a9c5e0c 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,9 @@
+
+
+
@@ -58,9 +61,9 @@ Four ways this changes what Claude Code can do for you:
- đź’ˇ **Stop repeating the same mistakes:** Produces actionable playbooks Claude can follow next time; memory only records what happened.
- > *Example:* you tell Claude to stop running `npm test` without `--run` because watch mode hangs.
- > **Memory:** “user was annoyed about npm test hanging”
- > **Learning:** “always pass `--run` to `npm test` in this repo — default watch mode blocks CI”
+ > *Example:* a deploy fails after Claude bumps `prisma` from 5.x to 6.0; you tell it to roll back because 6.0 breaks nested writes in your order flow.
+ > **Memory:** “deploy broke after prisma bump; user rolled back”
+ > **Learning:** “treat major-version bumps of ORMs/DB drivers as breaking — verify with integration tests, not just unit tests”
- 🚀 **Start from the optimized path:** Preserves and optimizes execution paths so Claude can reuse what already works.
> *Example:* Claude spends several iterations trying to start the local dev environment before discovering that this repo requires `pnpm dev:all` instead of the usual `npm run dev`.
diff --git a/assets/playbook_dashboard.png b/assets/playbook_dashboard.png
index 846ce0d..8eb0c7c 100644
Binary files a/assets/playbook_dashboard.png and b/assets/playbook_dashboard.png differ
diff --git a/assets/profile_dashboard.png b/assets/profile_dashboard.png
index 2f7246a..034f39c 100644
Binary files a/assets/profile_dashboard.png and b/assets/profile_dashboard.png differ
diff --git a/plugin/dashboard/app/configure/server/page.tsx b/plugin/dashboard/app/configure/server/page.tsx
index 10d6df1..a16b079 100644
--- a/plugin/dashboard/app/configure/server/page.tsx
+++ b/plugin/dashboard/app/configure/server/page.tsx
@@ -162,11 +162,11 @@ export default function ConfigureServerPage() {
{
const n = Number(e.target.value);
updateSrv(
- "batch_size",
+ "window_size",
Number.isFinite(n) && n > 0 ? n : undefined,
);
}}
@@ -184,11 +184,11 @@ export default function ConfigureServerPage() {
{
const n = Number(e.target.value);
updateSrv(
- "batch_interval",
+ "stride_size",
Number.isFinite(n) && n > 0 ? n : undefined,
);
}}
diff --git a/plugin/dashboard/app/dashboard/page.tsx b/plugin/dashboard/app/dashboard/page.tsx
index 41937dd..329a137 100644
--- a/plugin/dashboard/app/dashboard/page.tsx
+++ b/plugin/dashboard/app/dashboard/page.tsx
@@ -183,7 +183,7 @@ export default function DashboardPage() {
)}
diff --git a/plugin/dashboard/app/playbooks/page.tsx b/plugin/dashboard/app/playbooks/page.tsx
index 6f90604..ac8c219 100644
--- a/plugin/dashboard/app/playbooks/page.tsx
+++ b/plugin/dashboard/app/playbooks/page.tsx
@@ -137,7 +137,7 @@ export default function PlaybooksPage() {
) : (
diff --git a/plugin/dashboard/app/profiles/page.tsx b/plugin/dashboard/app/profiles/page.tsx
index 311c272..a3859a9 100644
--- a/plugin/dashboard/app/profiles/page.tsx
+++ b/plugin/dashboard/app/profiles/page.tsx
@@ -82,7 +82,7 @@ export default function ProfilesPage() {
) : (
diff --git a/plugin/dashboard/lib/types.ts b/plugin/dashboard/lib/types.ts
index 41b85f1..cc64efc 100644
--- a/plugin/dashboard/lib/types.ts
+++ b/plugin/dashboard/lib/types.ts
@@ -112,8 +112,8 @@ export interface ReflexioExtractorConfig {
export interface ReflexioConfig {
agent_context_prompt?: string | null;
- batch_size?: number;
- batch_interval?: number;
+ window_size?: number;
+ stride_size?: number;
profile_extractor_configs?: ReflexioExtractorConfig[] | null;
user_playbook_extractor_configs?: ReflexioExtractorConfig[] | null;
[k: string]: unknown;
diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml
index 9e42280..b4241e3 100644
--- a/plugin/pyproject.toml
+++ b/plugin/pyproject.toml
@@ -5,7 +5,7 @@ description = "Self-improving Claude Code plugin — learns from corrections via
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
- "reflexio-ai>=0.2.15",
+ "reflexio-ai>=0.2.20",
# Used by reflexio's local embedding provider (ONNXMiniLM_L6_V2).
# Pulls in onnxruntime + tokenizers; the ~80 MB ONNX model itself is
# downloaded on first use, not at install time.
diff --git a/plugin/src/claude_smart/events/session_start.py b/plugin/src/claude_smart/events/session_start.py
index c793600..f0a15e7 100644
--- a/plugin/src/claude_smart/events/session_start.py
+++ b/plugin/src/claude_smart/events/session_start.py
@@ -10,11 +10,11 @@
from claude_smart import context_format, cs_cite, hook, ids, state
from claude_smart.reflexio_adapter import Adapter
-# Claude-smart's preferred extraction cadence — more frequent, smaller batches
+# Claude-smart's preferred extraction cadence — more frequent, smaller windows
# than reflexio's out-of-box 10/5. Applied idempotently to the reflexio server
-# on every SessionStart via Adapter.apply_batch_defaults.
-_CLAUDE_SMART_BATCH_SIZE = 5
-_CLAUDE_SMART_BATCH_INTERVAL = 3
+# on every SessionStart via Adapter.apply_extraction_defaults.
+_CLAUDE_SMART_WINDOW_SIZE = 5
+_CLAUDE_SMART_STRIDE_SIZE = 3
def handle(payload: dict[str, Any]) -> None:
@@ -26,9 +26,9 @@ def handle(payload: dict[str, Any]) -> None:
project_id = ids.resolve_project_id(cwd)
adapter = Adapter()
- adapter.apply_batch_defaults(
- batch_size=_CLAUDE_SMART_BATCH_SIZE,
- batch_interval=_CLAUDE_SMART_BATCH_INTERVAL,
+ adapter.apply_extraction_defaults(
+ window_size=_CLAUDE_SMART_WINDOW_SIZE,
+ stride_size=_CLAUDE_SMART_STRIDE_SIZE,
)
playbooks, profiles = adapter.fetch_both(
project_id=project_id,
diff --git a/plugin/src/claude_smart/reflexio_adapter.py b/plugin/src/claude_smart/reflexio_adapter.py
index 323b733..1beb55d 100644
--- a/plugin/src/claude_smart/reflexio_adapter.py
+++ b/plugin/src/claude_smart/reflexio_adapter.py
@@ -121,23 +121,23 @@ def delete_all(self) -> tuple[dict[str, int], list[tuple[str, str]]] | None:
counts[name] = getattr(response, "deleted_count", 0) or 0
return counts, errors
- def apply_batch_defaults(self, *, batch_size: int, batch_interval: int) -> bool:
- """Push claude-smart's preferred batch defaults to the reflexio server.
+ def apply_extraction_defaults(self, *, window_size: int, stride_size: int) -> bool:
+ """Push claude-smart's preferred extraction defaults to the reflexio server.
Reads the current ``Config`` and only issues a ``set_config`` when the
server-side values differ, so steady state is a single cheap GET.
Reflexio persists ``Config`` to disk, so once these values land they
survive backend restarts. The flip side: if an operator customizes
- ``batch_size``/``batch_interval`` via the dashboard, this call will
+ ``window_size``/``stride_size`` via the dashboard, this call will
overwrite those values back to the claude-smart defaults on the next
SessionStart. To change the defaults, edit the constants at the call
site in ``events/session_start.py``.
Args:
- batch_size (int): Desired ``Config.batch_size`` on the server.
- batch_interval (int): Desired ``Config.batch_interval`` on the
- server. Must be ``<= batch_size`` (reflexio enforces this).
+ window_size (int): Desired ``Config.window_size`` on the server.
+ stride_size (int): Desired ``Config.stride_size`` on the
+ server. Must be ``<= window_size`` (reflexio enforces this).
Returns:
bool: True if the server is already at the target values or the
@@ -150,16 +150,16 @@ def apply_batch_defaults(self, *, batch_size: int, batch_interval: int) -> bool:
try:
config = client.get_config()
if (
- getattr(config, "batch_size", None) == batch_size
- and getattr(config, "batch_interval", None) == batch_interval
+ getattr(config, "window_size", None) == window_size
+ and getattr(config, "stride_size", None) == stride_size
):
return True
- config.batch_size = batch_size
- config.batch_interval = batch_interval
+ config.window_size = window_size
+ config.stride_size = stride_size
client.set_config(config)
return True
except Exception as exc: # noqa: BLE001 — adapter must never raise.
- _LOGGER.warning("apply_batch_defaults failed: %s", exc)
+ _LOGGER.warning("apply_extraction_defaults failed: %s", exc)
return False
# -----------------------------------------------------------------
diff --git a/plugin/uv.lock b/plugin/uv.lock
index 7e8fddd..ed7613b 100644
--- a/plugin/uv.lock
+++ b/plugin/uv.lock
@@ -434,7 +434,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "chromadb", specifier = ">=0.5" },
- { name = "reflexio-ai", specifier = ">=0.2.15" },
+ { name = "reflexio-ai", specifier = ">=0.2.20" },
]
[package.metadata.requires-dev]
diff --git a/reflexio b/reflexio
index 9da73f8..b8ac1b0 160000
--- a/reflexio
+++ b/reflexio
@@ -1 +1 @@
-Subproject commit 9da73f80456365abc6f756b3742059d4e50b019d
+Subproject commit b8ac1b0e92b703f3776b93a9f4d240b332d7981e
diff --git a/tests/test_adapter.py b/tests/test_adapter.py
index 76622db..6fed522 100644
--- a/tests/test_adapter.py
+++ b/tests/test_adapter.py
@@ -229,17 +229,15 @@ def test_fetch_playbooks_default_top_k_is_tightened() -> None:
# -----------------------------------------------------------------------------
-# apply_batch_defaults — push claude-smart's preferred cadence to reflexio
+# apply_extraction_defaults — push claude-smart's preferred cadence to reflexio
# -----------------------------------------------------------------------------
class _ConfigClient:
"""Captures get_config/set_config calls against a mutable config object."""
- def __init__(self, *, batch_size: int, batch_interval: int, get_raises=None):
- self._config = SimpleNamespace(
- batch_size=batch_size, batch_interval=batch_interval
- )
+ def __init__(self, *, window_size: int, stride_size: int, get_raises=None):
+ self._config = SimpleNamespace(window_size=window_size, stride_size=stride_size)
self._get_raises = get_raises
self.set_calls: list[SimpleNamespace] = []
@@ -251,39 +249,39 @@ def get_config(self):
def set_config(self, config):
self.set_calls.append(
SimpleNamespace(
- batch_size=config.batch_size, batch_interval=config.batch_interval
+ window_size=config.window_size, stride_size=config.stride_size
)
)
self._config = config
return {"ok": True}
-def test_apply_batch_defaults_writes_when_values_differ() -> None:
- client = _ConfigClient(batch_size=10, batch_interval=5)
+def test_apply_extraction_defaults_writes_when_values_differ() -> None:
+ client = _ConfigClient(window_size=10, stride_size=5)
a = _adapter_with(client)
- assert a.apply_batch_defaults(batch_size=5, batch_interval=3) is True
+ assert a.apply_extraction_defaults(window_size=5, stride_size=3) is True
assert len(client.set_calls) == 1
- assert client.set_calls[0].batch_size == 5
- assert client.set_calls[0].batch_interval == 3
+ assert client.set_calls[0].window_size == 5
+ assert client.set_calls[0].stride_size == 3
-def test_apply_batch_defaults_skips_set_when_values_match() -> None:
- client = _ConfigClient(batch_size=5, batch_interval=3)
+def test_apply_extraction_defaults_skips_set_when_values_match() -> None:
+ client = _ConfigClient(window_size=5, stride_size=3)
a = _adapter_with(client)
- assert a.apply_batch_defaults(batch_size=5, batch_interval=3) is True
+ assert a.apply_extraction_defaults(window_size=5, stride_size=3) is True
assert client.set_calls == []
-def test_apply_batch_defaults_returns_false_when_client_unavailable(
+def test_apply_extraction_defaults_returns_false_when_client_unavailable(
monkeypatch,
) -> None:
a = reflexio_adapter.Adapter()
monkeypatch.setattr(a, "_get_client", lambda: None)
- assert a.apply_batch_defaults(batch_size=5, batch_interval=3) is False
+ assert a.apply_extraction_defaults(window_size=5, stride_size=3) is False
-def test_apply_batch_defaults_absorbs_get_config_errors() -> None:
+def test_apply_extraction_defaults_absorbs_get_config_errors() -> None:
a = _adapter_with(
- _ConfigClient(batch_size=10, batch_interval=5, get_raises=RuntimeError("down"))
+ _ConfigClient(window_size=10, stride_size=5, get_raises=RuntimeError("down"))
)
- assert a.apply_batch_defaults(batch_size=5, batch_interval=3) is False
+ assert a.apply_extraction_defaults(window_size=5, stride_size=3) is False
diff --git a/tests/test_events.py b/tests/test_events.py
index f99d9a4..dc3c2d4 100644
--- a/tests/test_events.py
+++ b/tests/test_events.py
@@ -1208,7 +1208,7 @@ def test_session_start_emits_continue_when_no_playbook_or_profile(
session_dir, monkeypatch
) -> None:
class StubAdapter:
- def apply_batch_defaults(self, **_kw):
+ def apply_extraction_defaults(self, **_kw):
return True
def fetch_both(self, **_kw):
@@ -1230,7 +1230,7 @@ def test_session_start_emits_additional_context_when_playbook_present(
session_dir, monkeypatch
) -> None:
class Stub:
- def apply_batch_defaults(self, **_kw):
+ def apply_extraction_defaults(self, **_kw):
return True
def fetch_both(self, **_kw):
@@ -1260,14 +1260,14 @@ def fetch_both(self, **_kw):
assert "use pathlib" in payload["hookSpecificOutput"]["additionalContext"]
-def test_session_start_applies_claude_smart_batch_defaults(
+def test_session_start_applies_claude_smart_extraction_defaults(
session_dir, monkeypatch
) -> None:
- """SessionStart must push claude-smart's 5/3 batch defaults to reflexio."""
+ """SessionStart must push claude-smart's 5/3 extraction defaults to reflexio."""
applied: list[dict[str, Any]] = []
class Stub:
- def apply_batch_defaults(self, **kwargs):
+ def apply_extraction_defaults(self, **kwargs):
applied.append(kwargs)
return True
@@ -1284,7 +1284,7 @@ def fetch_both(self, **_kw):
buf = io.StringIO()
monkeypatch.setattr(sys, "stdout", buf)
session_start.handle({"session_id": "s1", "source": "startup"})
- assert applied == [{"batch_size": 5, "batch_interval": 3}]
+ assert applied == [{"window_size": 5, "stride_size": 3}]
def test_session_start_fetches_both_on_every_source(session_dir, monkeypatch) -> None:
@@ -1292,7 +1292,7 @@ def test_session_start_fetches_both_on_every_source(session_dir, monkeypatch) ->
calls: list[dict[str, Any]] = []
class Stub:
- def apply_batch_defaults(self, **_kw):
+ def apply_extraction_defaults(self, **_kw):
return True
def fetch_both(self, **kwargs):