From 761ee16bc3af563566201ea6e419cb9c919db06a Mon Sep 17 00:00:00 2001 From: Ciaran Jessup Date: Wed, 3 Jun 2026 11:58:54 +0100 Subject: [PATCH] feat: support cache location overrides (#177) Adds support for a neew environment variable 'SEMBLE_CACHE_LOCATION'. The value of this variable will be the full path location of the cache folder that semble stores its caches and savings information. This variable takes precedence over and OS defaults and the Arch XDG_CACHE_HOME convention. --- README.md | 2 +- src/semble/cache.py | 6 ++++-- tests/test_cache.py | 9 +++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 81e9e2f15..b7099ad45 100644 --- a/README.md +++ b/README.md @@ -402,7 +402,7 @@ semble savings --verbose # also show breakdown by call type Savings are calculated as follows: for each call, semble records the total character count of the unique files containing returned chunks and the character count of the snippets returned. Estimated tokens saved is `(file chars − snippet chars) / 4` (4 chars per token). This is a conservative estimate: the baseline is reading matched files in full, which is how coding agents often explore unfamiliar code. -Stats are stored in the OS cache folder (`~/Library/Caches/semble/` on macOS, `~/.cache/semble/` on Linux, `%LOCALAPPDATA%\semble\Cache\` on Windows). +By default, stats are stored in the OS cache folder (`~/Library/Caches/semble/` on macOS, `~/.cache/semble/` on Linux, `%LOCALAPPDATA%\semble\Cache\` on Windows). To override this location you can supply an environment variable `SEMBLE_CACHE_LOCATION` which should be the full path to the target cache location e.g. 'd:\caches\storemysemblecachehere'. diff --git a/src/semble/cache.py b/src/semble/cache.py index 6f6ea49ee..e42454044 100644 --- a/src/semble/cache.py +++ b/src/semble/cache.py @@ -49,9 +49,11 @@ def _linux_cache_dir(name: str) -> Path: def resolve_cache_folder() -> Path: - """Resolves a cache folder, respects XDG_CACHE_HOME.""" + """Resolves a cache folder, respects SEMBLE_CACHE_LOCATION (highest precedence), XDG_CACHE_HOME.""" name = "semble" - if sys.platform == "win32": + if semble_cache_location := os.getenv("SEMBLE_CACHE_LOCATION"): + cache_dir = Path(semble_cache_location) + elif sys.platform == "win32": cache_dir = _windows_cache_dir(name) elif sys.platform == "darwin": cache_dir = _macos_cache_dir(name) diff --git a/tests/test_cache.py b/tests/test_cache.py index e46eb20d0..995705dab 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -93,6 +93,15 @@ def test_resolve_cache_folder(platform: str, mock_target: str, expected: Path) - assert result == expected +def test_resolve_cache_folder_semble_cache_location(tmp_path: Path) -> None: + """SEMBLE_CACHE_LOCATION takes precedence over all platform-specific helpers.""" + custom = tmp_path / "custom_cache" + with patch.dict("os.environ", {"SEMBLE_CACHE_LOCATION": str(custom)}): + result = resolve_cache_folder() + assert result == custom + assert custom.exists() + + def test_clear_cache(tmp_path: Path) -> None: """clear_cache removes the index directory when it exists and is a no-op otherwise.""" index_path = tmp_path / "index"