Commit graph

6 commits

Author SHA1 Message Date
Dávid Balatoni
5424e99a65
Clarify uv tool install path on macOS (#1196)
## Description

Clarifies the recommended install path for the Headroom CLI on macOS
Apple Silicon and Linux. The docs now prefer `uv tool install --python
3.13 "headroom-ai[all]"` for host-level CLI use, keep `pip install`
scoped to Python project environments, and call out absolute executable
paths for MCP clients that do not inherit interactive shell `PATH`.

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Added `uv tool install --python 3.13` guidance to the README, docs
install page, quickstarts, and wiki install pages.
- Documented `uv tool update-shell` for shells that cannot find the
installed `headroom` command.
- Clarified absolute MCP server command paths for clients that do not
inherit the interactive shell `PATH`.
- Pointed Intel macOS users at the Docker-native install path until
native wheel support lands.

## Testing

Describe the tests you ran to verify your changes:

- [ ] Unit tests pass (`pytest`) - not run; docs-only change.
- [ ] Linting passes (`ruff check .`) - not run; docs-only change.
- [ ] Type checking passes (`mypy headroom`) - not run; docs-only
change.
- [ ] New tests added for new functionality - not applicable.
- [x] Manual testing performed
- [x] `git diff --check upstream/main...HEAD`

## Real Behavior Proof

```bash
$ git diff --check upstream/main...HEAD
# exits 0; no whitespace errors
```

`npm --prefix docs run types:check` was also attempted. It regenerated
MDX and route types successfully, then failed in existing docs app code
because `@/lib/...` imports cannot resolve from files such as
`app/(home)/layout.tsx`, `app/api/search/route.ts`, and
`components/button.tsx`. This PR only changes `README.md`,
`docs/content/docs/installation.mdx`,
`docs/content/docs/quickstart.mdx`, and `wiki/*.md` files.

## Review Readiness

- [x] Draft PR; docs wording and install-path accuracy are ready for
review.
- [x] No code or runtime files changed.
- [x] Known docs type-check blocker is documented above.

## Test Output

```bash
$ git diff --check upstream/main...HEAD
# no output
```

```text
$ npm --prefix docs run types:check
[MDX] generated files
✓ Types generated successfully
app/(home)/layout.tsx(2,29): error TS2307: Cannot find module @/lib/layout.shared or its corresponding type declarations.
...
components/button.tsx(4,20): error TS2307: Cannot find module @/lib/cn or its corresponding type declarations.
```

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- not applicable; docs-only change.
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works - not applicable; docs-only change.
- [ ] New and existing unit tests pass locally with my changes - not
run; docs-only change.
- [ ] I have updated the CHANGELOG.md if applicable - not applicable.

## Screenshots (if applicable)

Not applicable.

## Additional Notes

The PR remains a draft while docs verification is limited by the
existing docs app `@/lib/*` resolution issue.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-15 21:06:30 +00:00
Dashsoap
ca23257d1b
docs: correct macOS troubleshooting Python floor to 3.10+ (#981)
## Description

`wiki/macos-deployment.md` told users that Headroom "Requires Python
3.9+", but the project's actual floor is Python 3.10. This corrects that
one line to 3.10+ so it matches `pyproject.toml` and every other doc.

Closes #

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- `wiki/macos-deployment.md` (troubleshooting → "Common causes"):
`Requires Python 3.9+` → `Requires Python 3.10+`.

## Testing

<!-- Check what you actually ran, then paste the real command output
below. -->

- [ ] Unit tests pass (`pytest`)
- [ ] Linting passes (`ruff check .`)
- [ ] Type checking passes (`mypy headroom`)
- [ ] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
# Ground truth — the real Python floor:
$ grep -n 'requires-python' pyproject.toml
11:requires-python = ">=3.10"

# Every other doc already says 3.10+, and this was the only "3.9" left:
$ grep -rniE 'requires? python *3\.(9|10)' README.md docs/ wiki/ CONTRIBUTING.md
README.md: ... Requires **Python 3.10+**.
docs/content/docs/installation.mdx:16: Headroom requires **Python 3.10+** ...
docs/content/docs/installation.mdx:245: This project requires **Python 3.10+**.
wiki/index.md:405: Requires Python 3.10+.
CONTRIBUTING.md:125: - Python 3.10+. ...
wiki/macos-deployment.md:426: - Python version incompatible: Requires Python 3.10+   # fixed by this PR
```

## Real Behavior Proof

- Environment: local clone at `origin/main`; this is a
documentation-only change.
- Exact command / steps: confirmed `pyproject.toml` declares
`requires-python = ">=3.10"`; grepped all docs and found
`wiki/macos-deployment.md` was the only file claiming `3.9+`; changed
that single line to `3.10+`.
- Observed result: all Python-floor mentions across README,
`docs/content/docs/installation.mdx`, `wiki/index.md`,
`CONTRIBUTING.md`, and now `wiki/macos-deployment.md` agree on 3.10+,
matching `requires-python`.
- Not tested: N/A — single-line prose fix in a Markdown file; no code
paths, no build, no runtime behavior involved.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Additional Notes

Documentation-only change, so `pytest`/`ruff`/`mypy` over the `headroom`
package are N/A — the diff contains no Python source. The fix was a
misleading minimum specifically in the version-incompatibility
troubleshooting step, where the wrong floor (3.9 vs the real 3.10) would
actively mislead a user diagnosing a Python version problem on macOS.
2026-06-15 11:09:59 -05:00
Logan Kang
c71592d421
feat(memory): add opt-in Apple-GPU (MPS) embedding runtime (#766)
## Description

On Apple-Silicon Macs — especially fanless models like the MacBook Air
(M5) — running the proxy with memory context injection can pin the CPU
while embedding. The embedding work runs an uncapped session on the CPU,
saturating multiple cores, which starves the proxy's asyncio loop and
leads to request timeouts.

This PR adds an **opt-in** runtime that offloads the memory embedder to
the Apple GPU (MPS). Setting `HEADROOM_EMBEDDER_RUNTIME=pytorch_mps`
routes embedding through the torch `sentence-transformers` backend on
MPS instead of the default ONNX CPU embedder, moving the work off the
CPU and keeping the proxy responsive.
The default behavior is unchanged — the feature is strictly opt-in,
env-var only, and falls through to the existing default embedder
selection (with a warning) whenever MPS or the torch dependencies are
unavailable.

Fixes: N/A — no tracking issue (surfaced while running codex auto-review
through
the proxy on a fanless MacBook Air (M5)).

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [x] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [x] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- **Runtime selection** (`headroom/proxy/memory_handler.py`): read
`HEADROOM_EMBEDDER_RUNTIME`; when set to `pytorch_mps` **and** MPS is
actually available, route the memory embedder to the torch
`sentence-transformers` backend (Apple GPU).
- If MPS is unavailable or torch/sentence-transformers is not installed,
log a warning and fall through to the existing default embedder
selection (ONNX when available, else the pre-existing local
sentence-transformers fallback) — no crash. The default (env var unset)
is unchanged. Env-var only
- **MPS serialization** (`headroom/memory/adapters/embedders.py`):
`LocalEmbedder` now funnels every `encode()` through a dedicated
single-worker `ThreadPoolExecutor` when the resolved device is MPS.
torch-MPS is not thread-safe, and the existing `run_in_executor(None,
...)` dispatch would otherwise let concurrent proxy requests call MPS
from multiple threads. CPU/CUDA keep the shared default executor
(behavior unchanged). `close()` also drops the cached model so re-use
after close re-initializes cleanly.
- **Packaging** (`pyproject.toml`): new `pytorch-mps` extra (`torch` +
`sentence-transformers`), **platform-gated to macOS** (`; sys_platform
== 'darwin'`) since MPS is Apple-Silicon-only. Deliberately left out of
`[all]` (its deps already arrive via `[ml]`/`[memory]`).
- **Tests** (`tests/test_memory/test_embedder_mps_serialization.py`):
regression coverage for the serialized executor, concurrency safety (no
SIGABRT), CPU-path default behavior, and close/re-use re-initialization.
- **Docs**: `wiki/{configuration,memory,macos-deployment}.md`,
`docs/content/docs/{configuration,installation,memory}.mdx`,
`README.md`, `CHANGELOG.md`.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed (CPU-offload + concurrency profiling on
Apple Silicon)

## Test Output

```
$ pytest -v tests/test_memory/test_embedder_mps_serialization.py
collected 4 items
tests/test_memory/test_embedder_mps_serialization.py::test_cpu_uses_shared_executor PASSED            [ 25%]
tests/test_memory/test_embedder_mps_serialization.py::test_mps_creates_single_worker_executor PASSED  [ 50%]
tests/test_memory/test_embedder_mps_serialization.py::test_mps_concurrent_embeds_do_not_crash PASSED  [ 75%]
tests/test_memory/test_embedder_mps_serialization.py::test_mps_reembed_after_close_recreates_executor PASSED [100%]
============================== 4 passed in 6.92s ===============================

$ ruff check headroom/memory/adapters/embedders.py headroom/proxy/memory_handler.py tests/test_memory/test_embedder_mps_serialization.py
All checks passed!

$ mypy headroom/memory/adapters/embedders.py headroom/proxy/memory_handler.py
Success: no issues found in 2 source files

$ pytest -q tests/test_memory/ tests/test_memory_handler_concurrent_init.py tests/test_memory_handler_native_ops.py
553 passed, 1 skipped in 13.51s
```

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable

## Additional Notes

**Why MPS (and not CoreML or a thread cap):** measured on an
Apple-Silicon Mac, the default uncapped CPU embedding session saturates
the cores; the same model on MPS runs at a fraction of the CPU (≈8x
lower sustained CPU utilization in profiling) while producing
**byte-identical embeddings** (cosine distance ≈ 0 across runtimes), so
relevance/ranking is unchanged. A CoreML execution-provider path was
evaluated and rejected: the default optimized ONNX model uses fused ops
that fall back to CPU under CoreML (no offload), and a full-precision
re-export was impractical (very low throughput + multi-GB memory). MPS
via `sentence-transformers` was the only practical GPU offload.

**Why serialization is mandatory:** torch-MPS is not thread-safe —
concurrent encode calls from a multi-worker executor abort with
`-[IOGPUMetalCommandBuffer validate]: failed assertion 'commit an
already committed command buffer'` (reproduced deterministically; a
single-worker executor resolves it).
Under concurrent load the serialized single-GPU-stream throughput meets
or exceeds the parallel CPU path while using a fraction of the cores.

**Scope / boundary:** this targets the Python **memory** embedder, which
is live on the proxy request path (memory context injection). The
Rust-backed SmartCrusher compression path is unaffected and remains
non-configurable from Python by design.

**Safety:** default behavior is unchanged (ONNX, no torch). The feature
is opt-in, env-var only, macOS-gated at the packaging layer, and
degrades gracefully (warn + the existing default embedder selection)
when MPS or the dependencies are unavailable.
2026-06-11 12:59:20 -05:00
pratikbin
42b1cd24de docs: fix env var discrepancies across markdown files
Audit all .md files against codebase; fix wrong names, remove phantom
variables, and correct outdated values:

- HEADROOM_PROXY_PORT → HEADROOM_PORT (proxy.py envvar="HEADROOM_PORT")
- HEADROOM_BIND → HEADROOM_HOST + HEADROOM_PORT (RUST_DEV.md)
- HEADROOM_LEARN_{CLAUDE,CODEX,GEMINI}_ENABLED → HEADROOM_LEARN_CLI
  (only HEADROOM_LEARN_CLI exists in learn/analyzer.py)
- HEADROOM_TRACING_ENABLED → HEADROOM_LANGFUSE_ENABLED=1 with correct
  LANGFUSE_PUBLIC_KEY/SECRET_KEY vars (tracing.py)
- HEADROOM_LOG_LEVEL/LOG_FORMAT → --log-level CLI flag / RUST_LOG
  (no HEADROOM_LOG_LEVEL var exists in code)
- HEADROOM_LOG_LEVEL/HEADROOM_STORE_URL/HEADROOM_DEFAULT_MODE rows
  removed from wiki/configuration.md (all phantom)
- HEADROOM_SUMMARY_{ENABLED,THRESHOLD,RATIO} noted as not yet
  implemented (no code exists)
- HEADROOM_DB_URL/HEADROOM_CACHE_BACKEND → explanatory notes pointing
  to HEADROOM_WORKSPACE_DIR (no external DB support in code)
- HEADROOM_DB_PATH/HEADROOM_CACHE_PATH table rows replaced with actual
  HEADROOM_WORKSPACE_DIR/CONFIG_DIR (paths.py)
2026-05-29 15:04:13 +05:30
chopratejas
265554d4ad fix(cli): proxy/perf/wrap UX cleanup + perf --hours correctness
Address user-reported UX gaps across the CLI surface:

- code-aware: add --code-aware/--no-code-aware (+ HEADROOM_CODE_AWARE_ENABLED env)
  to the Click CLI. PR #411 had added these only to the orphaned argparse main;
  the user-facing CLI couldn't reach the flag. Banner status text "remove
  --no-code-aware to enable" referenced a flag that didn't exist — fix to point
  at the actual flag/env. Surface code-aware in the click banner and add
  print_banner=False plumbing to run_server so the click path doesn't print
  two banners back-to-back.

- --mode: hide alias clutter via metavar=[token|cache] and rewrite help to
  lead with the two real modes. Legacy aliases (token_mode/token_savings/...)
  still validate.

- perf --hours: was documented but ignored. Records are now actually filtered,
  the report shows the actual time-range covered, and the count of records
  filtered out (so users can tell when raising --hours helps).

- perf TOIN: replace the hash-keyed pattern dump with a strategy-distribution
  view + recommendation-eligibility from the live store — actionable signal
  rather than opaque rows.

- code-graph: clarify in --help that it indexes cwd / project root.

- wrap: spell out supported tools, wrap-vs-proxy distinction, and that
  `headroom wrap opencode` isn't a thing (use `proxy` directly for opencode;
  openclaw is not opencode).

- mcp: note that mcp__headroom__headroom_retrieve is correct MCP namespacing,
  not a doubled-prefix bug. Renaming would break the proxy's tool injection.

- LLMLingua cleanup: remove [llmlingua] extra from pyproject (no live code
  uses it). Delete wiki/llmlingua.md and clean retired flag/class references
  in 6 other wiki pages. Point at [ml] (Kompress) where ML compression is
  documented.

- init -g openclaw: strip mcpServers from existing plugin entries before
  re-writing — newer openclaw schemas reject it, leaving stale entries from
  older installs unhealable. Pinned with regression test.

Tests: mock_run_server signatures in two existing tests accept **kwargs
(needed for the new print_banner plumbing). New test for the openclaw
mcpServers strip. Full suite: 4847 passed, 262 skipped, 0 failed.
2026-05-07 16:43:35 -07:00
Adib Mohsin
911eb85a44 new docs UI + ts doc coverage 2026-04-12 13:15:58 +06:00
Renamed from docs/macos-deployment.md (Browse further)