Commit graph

9 commits

Author SHA1 Message Date
Tejas Chopra
e7340aee65
ci(changelog): stop the CHANGELOG cascade — release-please owns it (#2329)
## Description

Stops the recurring **CHANGELOG cascade** where several concurrent PRs
all edit `CHANGELOG.md`'s `## Unreleased` section, so the first to merge
turns the rest `DIRTY` — forcing a serial rebase-per-merge grind.

Root cause: **release-please already generates `CHANGELOG.md`** from
Conventional Commit titles (see `.release-please-config.json`
`changelog-sections`), so the hand-written `## Unreleased` entries are
*both redundant with release-please and the sole source of the
conflicts*. The PR template and CONTRIBUTING were actively telling
contributors to keep hand-editing it. `.gitattributes merge=union`
(#2138) does not help — GitHub squash-merge ignores merge drivers.

Fix: make release-please the only author of the changelog and stop
hand-edits at the source.

Closes #

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue) — CI/process

## Changes Made

- **`.github/workflows/changelog-guard.yml`** (new): fails any PR that
modifies `CHANGELOG.md`, except release-please's own release PR (head
branch `release-please--*`). Uses the preinstalled `gh` CLI — no
third-party action to pin.
- **`.github/PULL_REQUEST_TEMPLATE.md`**: flips the "I have updated the
CHANGELOG.md" checkbox to "I did **not** edit CHANGELOG.md —
release-please generates it from my Conventional Commit PR title."
- **`CONTRIBUTING.md`**: replaces step 6 ("Update `CHANGELOG.md`") with
the release-please policy.

## Testing

- [x] `actionlint .github/workflows/changelog-guard.yml` — clean
- [x] YAML parses (`yaml.safe_load`)
- [x] Guard match logic unit-checked locally: fires on root
`CHANGELOG.md`, ignores nested paths (`docs/CHANGELOG.md`) and PRs that
don't touch it.

### Test Output

```text
YAML OK
actionlint OK
root CHANGELOG.md         -> FIRES
nested docs/CHANGELOG.md  -> pass
no changelog              -> pass
```

## Real Behavior Proof

- Environment: local clone + `actionlint`.
- Exact steps: created the workflow, validated with actionlint + a YAML
parse, and exercised the `grep -qx 'CHANGELOG.md'` decision against
representative changed-file lists.
- Observed result: guard fires only on a root-level `CHANGELOG.md` edit;
the release-please branch is exempted via the job-level `if`.
- Not tested: a live PR run in Actions (will exercise on this PR itself
— note this PR does **not** touch `CHANGELOG.md`, so the guard should
pass green here).

## Additional Notes

- To *enforce* (block merge, not just show red), add **Changelog Guard /
no-manual-changelog** to the branch's required status checks.
- Follow-up: the ~10 currently-open PRs that hand-edit `CHANGELOG.md`
will need that edit removed (a clean deletion now, not a conflict
resolution) before they merge — after which the cascade is gone for
good.
2026-07-16 14:28:57 -07:00
Tejas Chopra
bd76235f5c
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491)
## Summary

Full CLI audit + documentation accuracy pass. All 5 commits on this
branch:

### CLI Hardening (4 commits)
- **Clean errors instead of tracebacks**: corrupt manifests, missing
Docker, malformed JSONL, bad `--profile`, invalid env-var values all now
raise `click.ClickException` with helpful messages
- **Range validation**: ~25 numeric flags across 10 files now use
`click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0`
etc. produce clean usage errors instead of silent wrong behavior
- **Flag combination warnings**: conflicting combos (`--no-rate-limit` +
`--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` +
`--no-telemetry`) emit yellow warnings on stderr
- **`memory --db-path` default fixed**: was resolving to
`headroom_memory.db` (wrong bare file); now uses project store
`./.headroom/memory.db` if present, else `~/.headroom/memory.db`
- **`memory list --search` + filters**: `--scope`/`--session`/`--since`
were silently ignored when `--search` was also set; now filters are
applied to search results
- **`learn --verbosity --apply` now works**: the output shaper is off by
default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via
`POST /admin/runtime-env` on a running proxy, or prints explicit `export
HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running
- **`perf --hours` overflow**: `1e9` hours no longer raises
`OverflowError`; treated as "all data"
- **`evals memory --categories` invalid input**: `abc,1,2` now raises
`BadParameter` instead of a raw `ValueError` traceback

### Documentation (1 commit, 20 files)

Corrected factual errors found by 3 parallel audit agents across root
docs, wiki, and the published Fumadocs site:

**Critical (caused runtime errors or wrong behavior if followed):**
- `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`;
`plan.savings_percent` -> computed from available fields (both raised
`AttributeError`)
- `shared-context.mdx`: `import { SharedContext } from "headroom"` ->
`"headroom-ai"` (5x `ImportError`)
- `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip
install headroom-ai`
- `api-reference.mdx` + `configuration.mdx`: `from headroom import
GoogleProvider` -> `from headroom.providers import GoogleProvider`
- `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min)

**Fabricated flags removed:**
- `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`,
`--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced
with real CCR flags
- `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion`
(none exist); replaced with real flags
- `wiki/troubleshooting.md`, `wiki/metrics.md`,
`docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag
doesn't exist)

**Stale content corrected:**
- `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap
list had 5 tools (now 11)
- `README.md`: compatibility matrix added 5 missing `wrap` targets;
`unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned
- `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x)
- `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior
documented
- `wiki/quickstart.md`: "Configuration Reference" linked to `api.md`
(wrong) -> `configuration.md`
- `CacheAlignerConfig.enabled` default corrected: `True` -> `False`
- `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai`
backend removed
- `CONTRIBUTING.md`: broken Markdown table cell fixed
- `docs/meta.json`: `claude-code-azure-foundry` added to nav (was
unreachable orphan page)
- `configuration.mdx`: SDK modes vs proxy `--mode` now clearly
distinguished

## Test plan

- [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures
- [x] 41-combination CLI smoke test (all flag combos across 8 commands)
— 0 tracebacks
- [x] `ruff check` on all modified Python files — clean
- [x] Docs changes are removals/corrections of fabricated or stale
content; no new claims introduced
2026-06-27 14:48:43 -07:00
Joel Belanger
0b4a4bd483
fix: support Copilot Business subscription auth (#641)
## Description

Adds a first-party `headroom copilot-auth login` flow for Copilot
subscription
mode and uses the resulting Copilot OAuth token to perform GitHub's
Copilot
token exchange before launching the wrapped Copilot CLI.

This fixes Business/Enterprise Cloud accounts where a generic
GitHub/Copilot
token can read Copilot account metadata but is rejected by the Copilot
token
exchange endpoint. It also avoids treating GitHub.com Enterprise Cloud
account
URLs such as `github.com/enterprises/acme` as API hostnames.

Fixes #635
Related: #488, #610
Builds on #576

## Type of Change

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

## Changes Made

- Adds `headroom copilot-auth login` and `headroom copilot-auth status`.
- Stores a Headroom-specific Copilot OAuth token under Headroom's state
dir.
- Exchanges reusable Copilot OAuth tokens with Copilot Chat-compatible
headers before subscription-mode launch.
- Carries the resolved Copilot API endpoint into `headroom wrap copilot
--subscription`.
- Handles GitHub.com Enterprise Cloud URLs without synthesizing invalid
`api.github.com/enterprises/...` hosts.
- Adds focused unit tests and README guidance for subscription login.

## Testing

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

### Test Output

```console
ruff check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py
# All checks passed!

ruff format --check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py
# 9 files already formatted

python -m py_compile headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py

uv run --no-project --with pytest --with pytest-asyncio --with click --with rich --with opentelemetry-api --with pydantic --with tiktoken --with 'litellm==1.82.3' --with fastapi --with uvicorn --with 'httpx[http2]' --with openai --with mcp --with magika --with zstandard --with websockets --with onnxruntime --with transformers --with watchdog --with sqlite-vec pytest tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_cli_proxy_env.py tests/test_copilot_subscription_smoke.py
# 127 passed
```

Local note: `uv run pytest ...` against the project currently fails
before
running tests because `uv.lock` has an unrelated `gitpython`
wheel/version
mismatch.

## Manual Validation

I tested this with an existing GitHub Copilot Business subscription
associated with a GitHub.com Enterprise Cloud account.

The Enterprise Cloud value I tested was in the form:

```text
github.com/enterprises/<enterprise>
```

The tested flow was:

```text
headroom copilot-auth login
headroom wrap copilot --subscription -- --model gpt-5.4
```

This validated that Headroom does not treat
github.com/enterprises/<enterprise> as a Copilot API hostname. Instead,
token exchange uses GitHub.com and Headroom routes subscription-mode
traffic to the Copilot API endpoint returned by GitHub for the signed-in
account.

I did not test this with GitHub Enterprise Server or a custom enterprise
domain such as ghe.example.com.

No tokens, request IDs, or organization-specific identifiers are
included in this PR.

## Real Behavior Proof

- Environment: macOS Darwin, Python 3.12.7, local checkout on
`codex/copilot-business-auth`.
- Exact command / steps: Ran `headroom copilot-auth login`, then
launched `headroom wrap copilot --subscription -- --model gpt-5.4` with
a GitHub Copilot Business subscription tied to a GitHub.com Enterprise
Cloud account.
- Observed result: Headroom did not treat
`github.com/enterprises/<enterprise>` as a Copilot API hostname; token
exchange used GitHub.com and subscription traffic was routed to the
Copilot API endpoint returned for the signed-in account. The latest
focused Copilot auth/proxy tests pass locally (`127 passed`).
- Not tested: GitHub Enterprise Server or custom enterprise domains such
as `ghe.example.com`; Windows Credential Manager integration still needs
confirmation from someone on Windows.

## 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
- [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 targeted unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A

## Additional Notes

Acknowledgement: the OAuth/token-exchange behavior was informed by
`anomalyco/opencode-copilot-auth` by Aiden Cline.

No tokens are printed by the new login/status commands; only a short
SHA-256
fingerprint is displayed for troubleshooting.

The interactive login is included because the missing piece is not just
an
Enterprise URL or routing hint. For GitHub.com Enterprise Cloud
accounts,
URLs like `github.com/enterprises/acme` identify the enterprise account
but
are not Copilot API hostnames; token exchange still happens through
GitHub.com
and then returns the account-specific Copilot API endpoint. A
command-line
enterprise argument can help for true GitHub Enterprise
Server/custom-domain
deployments, but it cannot produce the Copilot OAuth token class that
the
token-exchange endpoint accepts.

Ideally, Headroom would avoid an extra interactive login and reuse an
existing
GitHub/Copilot CLI session everywhere. In practice, some
reusable-looking
tokens can read Copilot account metadata but are rejected by Copilot
token
exchange, which leaves Business/Enterprise Cloud users with missing
model
catalogs. The explicit login command is the smallest independent way to
obtain
and persist the token needed for that exchange without asking users to
pass a
secret on the command line.

---------

Co-authored-by: jbelanger <your-username@users.noreply.github.com>
2026-06-12 20:46:38 -05:00
Copilot
96a7d7cbbe
Fix CI lint failure by formatting PR governance scripts (#933)
`CI / lint (pull_request)` failed because `ruff format --check` detected
formatting drift in the new PR governance script and its tests. This PR
aligns those files with repository formatting rules so the lint job can
pass.

- **Root cause**
  - `ruff format --check .` reported two files as non-canonical:
    - `scripts/pr-governance.py`
    - `scripts/tests/test_pr_governance.py`

- **Change set**
  - Applied `ruff` formatting to only the two flagged files.
- No behavioral or logic changes; edits are line-wrap/format
normalization only.

- **Representative update**
  ```python
  parser.add_argument(
"--event", type=Path, required=True, help="Path to the GitHub event
payload JSON."
  )
  ```

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-12 17:11:39 -05:00
Ashish
3db6cd430f
chore: wire pre-commit ruff hooks into make install-git-hooks (#786)
## Problem

`.pre-commit-config.yaml` already has `ruff` + `ruff-format` configured,
and `pre-commit>=3.0.0` is already in `[dev]` deps — but `make
install-git-hooks` never called `pre-commit install`. Every
contributor's repo had the hook **config** but no running hook.

PR #772 merged with inline-comment spacing and import-order violations
that ruff would have caught automatically. The maintainer had to add a
separate fixup commit (`fix: format issue 728 regression test`) to clean
it up.

## Changes

**`scripts/install-git-hooks.sh`** — after installing the pre-push hook,
also run `pre-commit install`. Falls back to `.venv/bin/pre-commit` when
`pre-commit` is not on `PATH`, with a clear warning if neither is found:

```
 installed: .git/hooks/pre-push
   Runs 'make ci-precheck' before every git push.
 installed: .git/hooks/pre-commit (ruff lint + format via pre-commit)
```

**`CONTRIBUTING.md`** — update PR workflow step 2 to mention `make
install-git-hooks` so contributors know to run it after `pip install`:

```
2. pip install -e ".[dev]" then make install-git-hooks — installs ruff on
   every commit and ci-precheck on every push.
```

## No behaviour change for existing code

Only the local dev setup script is touched. Nothing in the proxy, tests,
or CI pipeline changes.

## Real behavior proof

- **OS**: macOS darwin arm64
- **Steps**: ran `bash scripts/install-git-hooks.sh` with venv
available, then attempted a commit with a badly-formatted file
- **Result**: ruff caught and auto-fixed it before the commit landed

```
 installed: .git/hooks/pre-push
   Runs 'make ci-precheck' before every git push.
   Bypass (use sparingly): git push --no-verify
pre-commit installed at .git/hooks/pre-commit
 installed: .git/hooks/pre-commit (ruff lint + format via pre-commit)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:09:22 -05:00
Devanshi Vyas
264271b595 docs: update contributing.md 2026-06-05 22:02:28 -07:00
JerrettDavis
a1beb08d53 feat: add reproducible devcontainers
Add a default devcontainer and a compose-backed memory-stack profile, validate them in CI, and document the contributor workflow.

Also lock the memory-stack dependencies, pin related container tooling, and sync the latest healthcheck shutdown fix for stubbed memory handlers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:58:35 -05:00
Tejas Chopra
e782723ac3 Update CONTRIBUTING.md 2026-01-10 15:05:16 -08:00
chopratejas
175746cc26 Prepare for OSS release v0.2.0
This commit prepares Headroom for public open source release with
comprehensive documentation, licensing, and community infrastructure.

License & Legal:
- Add Apache 2.0 LICENSE file
- Add NOTICE file with third-party attributions
- Add SECURITY.md for vulnerability reporting

Community:
- Add CONTRIBUTING.md with contribution guidelines
- Add CODE_OF_CONDUCT.md (Contributor Covenant)
- Add GitHub issue templates (bug report, feature request)
- Add pull request template

Documentation:
- Update README.md with compelling value proposition
- Add docs/getting-started.md
- Add docs/proxy.md for proxy server documentation
- Add docs/transforms.md for transform reference
- Add docs/api.md for API reference
- Add examples/README.md

Package Infrastructure:
- Add headroom/py.typed for PEP 561 compliance
- Add headroom/cli.py for CLI entry point
- Add .github/workflows/ci.yml for CI pipeline
- Add .github/workflows/publish.yml for PyPI publishing
- Update pyproject.toml with proper metadata

New Features:
- Add multi-provider support (Google, Cohere, LiteLLM, OpenAI-compatible)
- Add universal tokenizer registry with multiple backends
- Add model registry with pricing and context limits
- Add production proxy server with caching and rate limiting

Code Quality:
- Fix 83 lint issues via ruff auto-fix
- Fix version consistency (benchmarks 0.1.0 → 0.2.0)
- Add skip decorators for optional dependency tests
2026-01-07 11:36:44 -08:00