Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 108 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,85 @@ concurrency:
cancel-in-progress: true

jobs:
changes:
name: Changed surfaces
runs-on: ubuntu-22.04
outputs:
harness: ${{ steps.classify.outputs.harness }}
docs: ${{ steps.classify.outputs.docs }}
python: ${{ steps.classify.outputs.python }}
rust: ${{ steps.classify.outputs.rust }}
package: ${{ steps.classify.outputs.package }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Classify changed paths
id: classify
env:
BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
python scripts/agent/ci_changes.py "$BASE" "$HEAD"
git diff --check "$BASE" "$HEAD"

harness:
name: Agent harness
needs: changes
if: ${{ needs.changes.outputs.harness == 'true' }}
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
python-version: "3.11"

- name: Install locked harness environment
run: uv sync --locked --only-group dev --no-install-project

- name: Lint harness
run: uv run --no-sync ruff check scripts/agent tests/test_agent_*.py tests/test_rtk_hook.py tests/test_codegraph_mcp.py

- name: Check harness formatting
run: uv run --no-sync ruff format --check scripts/agent tests/test_agent_*.py tests/test_rtk_hook.py tests/test_codegraph_mcp.py

- name: Test harness
run: uv run --no-sync pytest -q tests/test_agent_*.py tests/test_rtk_hook.py tests/test_codegraph_mcp.py

docs:
name: Documentation
needs: changes
if: ${{ needs.changes.outputs.docs == 'true' }}
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
python-version: "3.11"

- name: Install locked docs test environment
run: uv sync --locked --only-group dev --no-install-project

- name: Check local links
run: uv run --no-sync python scripts/check_local_links.py

- name: Check documentation routes
run: uv run --no-sync pytest -q tests/test_docs_routes.py

python:
name: Python / package
needs: changes
if: ${{ needs.changes.outputs.python == 'true' }}
runs-on: ubuntu-22.04
steps:
- name: Check out repository
Expand All @@ -30,7 +107,6 @@ jobs:
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
version-file: uv.toml

- name: Install locked development environment
run: uv sync --locked --all-groups
Expand All @@ -43,6 +119,8 @@ jobs:

rust:
name: Rust
needs: changes
if: ${{ needs.changes.outputs.rust == 'true' }}
runs-on: ubuntu-22.04
steps:
- name: Check out repository
Expand All @@ -62,13 +140,14 @@ jobs:
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
version-file: uv.toml

- name: Run Rust validation
run: uv run --no-project python scripts/agent/check.py rust

package:
name: Package / release wheel
needs: changes
if: ${{ needs.changes.outputs.package == 'true' }}
runs-on: ubuntu-22.04
steps:
- name: Check out repository
Expand All @@ -83,7 +162,33 @@ jobs:
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
version-file: uv.toml

- name: Build, inspect, and smoke test release artifacts
run: uv run --locked python scripts/agent/check.py package --smoke

gate:
name: CI gate
needs: [changes, harness, docs, python, rust, package]
if: ${{ always() }}
runs-on: ubuntu-22.04
steps:
- name: Require all selected checks
env:
CHANGES: ${{ needs.changes.result }}
HARNESS_REQUIRED: ${{ needs.changes.outputs.harness }}
HARNESS_RESULT: ${{ needs.harness.result }}
DOCS_REQUIRED: ${{ needs.changes.outputs.docs }}
DOCS_RESULT: ${{ needs.docs.result }}
PYTHON_REQUIRED: ${{ needs.changes.outputs.python }}
PYTHON_RESULT: ${{ needs.python.result }}
RUST_REQUIRED: ${{ needs.changes.outputs.rust }}
RUST_RESULT: ${{ needs.rust.result }}
PACKAGE_REQUIRED: ${{ needs.changes.outputs.package }}
PACKAGE_RESULT: ${{ needs.package.result }}
run: |
test "$CHANGES" = success
if [ "$HARNESS_REQUIRED" = true ]; then test "$HARNESS_RESULT" = success; fi
if [ "$DOCS_REQUIRED" = true ]; then test "$DOCS_RESULT" = success; fi
if [ "$PYTHON_REQUIRED" = true ]; then test "$PYTHON_RESULT" = success; fi
if [ "$RUST_REQUIRED" = true ]; then test "$RUST_RESULT" = success; fi
if [ "$PACKAGE_REQUIRED" = true ]; then test "$PACKAGE_RESULT" = success; fi
64 changes: 41 additions & 23 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ voice-agent transcripts. Rust generates valid written candidates, a frozen
DeBERTa scorer ranks them in sentence context, and an exact decoder selects
compatible edits.

Code and tests define implemented behavior. Read the README only for public API,
installation, or documentation changes.

## Boundaries

- `rust/` owns deterministic realization rules and candidate generation.
Expand All @@ -15,11 +18,19 @@ compatible edits.

## Change rules

- For semantic implementation changes, read the relevant implementation,
direct callers, and tests before editing. For small mechanical or
configuration changes, inspect only the target state and evidence needed to
apply and validate the requested change.
- Make the smallest coherent change and preserve unrelated work.
- For semantic changes, inspect the implementation, direct callers, consumers,
and relevant tests.
- For mechanical changes, inspect only the target and required validation.
- Use CodeGraph for structure. Use `rg` for exact text and references.
- Make the smallest coherent change. Preserve unrelated work.
- Add abstractions, options, compatibility layers, or caches only for a current
need.
- Keep one authoritative owner for each semantic rule.
- Test behavior, not edits. Add or update tests only when behavior, contracts,
or critical workflow logic changes.
- Prefer deterministic tests and replay. Use live models or downloads only when
that boundary is under test.
- Measure end-to-end latency before claiming a performance improvement.
- Keep `PremoveITN` as the single implementation behind the Python API and CLI.
- Do not change model, candidate, decoder, or normalization behavior in a
cleanup-only change.
Expand Down Expand Up @@ -74,23 +85,28 @@ If two evidence-driven fixes fail and the cause remains unclear, stop and return
## Git

- Treat `main` as the stable release branch.
- Use one short-lived branch and one focused pull request per change.
- Create branches with `scripts/agent/start_change.py --base <branch> --branch <prefix>/<name>`. Use `main` for normal work and the parent branch for stacked work.
- Use prefixes: `feat/`, `fix/`, `refactor/`, `perf/`, `test/`, `docs/`, `ci/`, `build/`, `chore/`, `design/`, and `epic/`.
- Keep each pull request to one coherent responsibility and one primary review question. Keep its implementation, tests, and required docs together.
- Split at a new responsibility, pipeline boundary, independent invariant, or substantial runtime surface. File count is a warning, not a limit.
- Use stacked pull requests for dependent stages. Each layer targets its parent branch.
- Use `epic/` only when dependent work must stay off `main` until integrated. Child PRs target the epic; the final epic PR targets `main`.
- Do not split trivial work or combine unrelated work for PR-count or file-count reasons.
- Do not push directly to `main` or force-push shared branches.
- Merge only after required checks pass.
- Merge only when explicitly requested and required checks pass.

## Verification

Keep validation proportional to the changed surface. Documentation and policy-only
changes do not require the full Python, Rust, or package suites.

During implementation, use the focused gate with the semantic tests relevant to
the change:

```bash
uv run --locked python scripts/agent/check.py focused --pytest <test>
```

Prefer the smallest validation that establishes the change locally. Do not run
the complete local gate only to duplicate checks that pull-request CI runs from
a clean checkout.

Use the complete local gate when the change is cross-cutting, modifies the
validation harness or CI, prepares a release, CI is unavailable, or focused
evidence is insufficient:
Expand All @@ -100,28 +116,30 @@ uv run --locked python scripts/agent/check.py full
```

GitHub Actions is the authoritative completion gate for pull requests.

Do not repeat an already-passing local gate only to open or integrate an
unchanged, already-reviewed branch. Confirm the branch state and expected diff,
then rely on the target pull request's authoritative CI unless prior validation
is stale, incomplete, or the integration introduces new changes.

## Command output

RTK may compact supported shell output. When compact output omits information
needed to continue:
RTK may compact shell output.

1. Use the printed `rtk recall <hash>` handle.
2. Use `rtk proxy <command>` if raw re-execution is required.
3. Use `RTK_DISABLED=1 <command>` only when RTK behavior itself is under
investigation.
- Use `rtk recall <hash>` when omitted output is needed.
- Use `rtk proxy <command>` for raw re-execution.
- Use `RTK_DISABLED=1` only when debugging RTK.
- Do not wrap `scripts/agent/check.py` with RTK. It already verifies exact recall.

<!-- CODEGRAPH_START -->
## CodeGraph

In repositories indexed by CodeGraph (a `.codegraph/` directory exists at the repo root), reach for it BEFORE grep/find or reading files when you need to understand or locate code:
Use CodeGraph before broad grep, find, or file reads when locating or
understanding code.

- **MCP tool** (when available): `codegraph_explore` answers most code questions in one call — the relevant symbols' verbatim source plus the call paths between them, including dynamic-dispatch hops grep can't follow. Name a file or symbol in the query to read its current line-numbered source. If it's listed but deferred, load it by name via tool search.
- **Shell** (always works): `codegraph explore "<symbol names or question>"` prints the same output.
Use `rg` for exact text and references.

If there is no `.codegraph/` directory, skip CodeGraph entirely — indexing is the user's decision.
<!-- CODEGRAPH_END -->
If `.codegraph/` is missing, run:

```bash
uv run --locked python scripts/agent/bootstrap.py
```
8 changes: 7 additions & 1 deletion AGENT_HARNESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ repository's `scripts/agent/rtk_hook.py` adapter. RTK shortens supported shell
output and preserves a way to recover the full output. When a compact result
omits needed detail, use `rtk recall <hash>`. Use `rtk proxy <command>` to
rerun a command with raw output. Set `RTK_DISABLED=1` only when investigating
RTK itself.
RTK itself. The repository-owned validation runner must not be outer-wrapped by
RTK because it already verifies exact recall before compacting failures.

## Validation

Expand All @@ -85,3 +86,8 @@ enough:
```bash
uv run --locked python scripts/agent/check.py full
```

Pull-request CI classifies changed paths before running expensive work. Agent
harness, documentation, Python, Rust, and package checks run only when their
surfaces require them. Unknown surfaces select the full set. A final CI gate
requires every selected job and is the authoritative pull-request result.
Loading
Loading