Skip to main content

Standalone Hermes Agent plugin and CLI for deterministic terminal/tool-output compaction.

Project description

Noisegate

Noisegate: Gate the noise. Keep the signal.

CI GitHub release License: MIT Python 3.11+

Gate the noise. Keep the signal.

Noisegate is a small, deterministic compaction layer for Hermes Agent. It catches the terminal walls, test-log avalanches, build spam, and other context-gremlins before they flood your model window.

It does not call a model. It does not vibe-summarize your logs. It does not pretend a chopped-off wall of text is "analysis".

It keeps the useful bits, leaves exact content alone, and gets out of the way when it is not sure.

uvx --from noisegate-hermes noisegate install-hermes

That is the normal install/update path for an existing Hermes Agent setup.

The problem

Agents are great at running tools.

Tools are great at producing nonsense amounts of output. Truly Olympic levels of nonsense.

A single test run, package install, Docker build, or search command can dump thousands of lines into context. Most of it is noise. Some of it matters. If you blindly truncate it, you lose the useful part. If you blindly keep it, you burn context and make the next model call worse.

Noisegate sits in the middle:

noisy tool output  ->  Noisegate  ->  compact signal-rich result

It is built for agent work where the context window is valuable and exactness matters.

What you get

Noisegate gives you two surfaces:

  • a Hermes plugin that can compact noisy tool results before they enter the conversation
  • a CLI you can use directly in terminals, scripts, CI jobs, and smoke tests

It knows how to reduce common noisy outputs:

  • pytest and unittest
  • npm, pnpm, and yarn
  • git status and git log
  • search output from rg, grep, ag, and ack
  • Docker build-style logs
  • generic long output with deterministic head/tail fallback

And it refuses to touch things that should stay exact:

  • file reads
  • patches and diffs
  • skill documents
  • memory, LCM, Hindsight, MCP, search, and web extraction results
  • unknown future tools unless explicitly allowed

That last bit matters. A compactor that damages retrieved context is worse than no compactor.

Install or update

Noisegate is distributed as the Python package noisegate-hermes. The Hermes plugin must be installed into the same Python environment that runs hermes.

Most users want this:

uvx --from noisegate-hermes noisegate install-hermes

Use the same command for first install and updates.

It finds hermes on PATH, resolves the Python environment that actually runs Hermes, installs noisegate-hermes there, enables the noisegate plugin, and runs noisegate doctor.

Preview the exact commands first:

uvx --from noisegate-hermes noisegate install-hermes --dry-run

If Hermes is running as a long-lived gateway/service, restart or reload that Hermes process through your normal maintenance flow after installing so the plugin/config change is picked up. Do not kick the chair out from under in-flight agent work.

From a checkout, install that exact checkout into Hermes:

uv run noisegate install-hermes --package .

Noisegate registers two Hermes hooks:

transform_terminal_output
transform_tool_result

npm wrapper

The npm package is a thin installer wrapper. The Python package is still the real thing.

If you prefer npm-shaped commands:

npx -p noisegate-hermes noisegate install-hermes

If your npm client does not resolve the single-bin shortcut, use:

npx -p noisegate-hermes noisegate-hermes-installer install-hermes
Manual fallback for unusual Hermes launchers

Prefer noisegate install-hermes. Use this only when you need to inspect or reproduce the low-level install flow manually.

HERMES_PYTHON="$(head -1 "$(command -v hermes)" | sed 's/^#!//')"
case "$(basename "$HERMES_PYTHON")" in
  python*|pypy*) ;;
  *) echo "Hermes launcher is not a Python console script; use noisegate install-hermes" >&2; exit 1 ;;
esac
HERMES_PREFIX="$(dirname "$(dirname "$HERMES_PYTHON")")"
if [ ! -f "$HERMES_PREFIX/pyvenv.cfg" ]; then
  echo "Hermes Python is not inside a virtual environment; use noisegate install-hermes" >&2
  exit 1
fi
uv pip install --python "$HERMES_PYTHON" noisegate-hermes
"$HERMES_PYTHON" - <<'PY'
from hermes_cli.config import load_config, save_config
cfg = load_config()
plugins = cfg.setdefault("plugins", {})
enabled = plugins.get("enabled") if isinstance(plugins.get("enabled"), list) else []
disabled = plugins.get("disabled") if isinstance(plugins.get("disabled"), list) else []
if "noisegate" not in enabled:
    enabled.append("noisegate")
plugins["enabled"] = enabled
plugins["disabled"] = [name for name in disabled if name != "noisegate"]
save_config(cfg)
PY
"$HERMES_PYTHON" -m noisegate.cli doctor

Try it in 30 seconds

Run the health check:

noisegate doctor

Compact a noisy stream:

python - <<'PY' | noisegate reduce --command "pytest"
for i in range(300):
    print(f"collecting test line {i:03d}")
print("FAILED tests/test_example.py::test_signal")
print("AssertionError: expected signal, got noise")
PY

Wrap a command and keep its exit code:

noisegate wrap -- pytest -q

Bypass compaction when exact output matters:

NOISEGATE_BYPASS=1 noisegate reduce < exact-output.txt
noisegate wrap --raw -- ./script-that-must-stay-exact
noisegate wrap --full -- ./another-exact-command

CLI reference

noisegate reduce --command "pytest" < noisy.log
noisegate reduce-json < hermes-tool-result.json
noisegate wrap -- pytest -q
noisegate wrap --store-artifact -- pytest -q
noisegate wrap --raw -- cat exact-output.txt
noisegate install-hermes --dry-run
noisegate doctor
noisegate cat ng_<artifact-id>
noisegate cat --artifact-dir /tmp/noisegate-artifacts ng_<artifact-id>
noisegate artifacts list --artifact-dir /tmp/noisegate-artifacts
noisegate artifacts stats --artifact-dir /tmp/noisegate-artifacts
noisegate artifacts verify --artifact-dir /tmp/noisegate-artifacts

wrap runs a command without a shell, captures stdout and stderr in arrival order, writes the compacted result to stdout, and exits with the wrapped command's exit code. It captures up to 4 MiB of combined output by default; use --max-capture-bytes <n> to change that.

If capture is truncated, Noisegate adds this marker:

[noisegate: capture truncated]

reduce-json accepts either a Hermes-like envelope with a result string or a direct JSON tool result. Bad JSON fails open and is written back unchanged.

For AI agents

If you are an AI agent working in this repo, read this first.

One-line instruction:

Install and enable Noisegate for Hermes, then stop dumping terminal walls into context; use NOISEGATE_BYPASS when exact bytes matter.

Operational rules:

  1. Use Noisegate for noisy terminal/tool output, not for exact source material.
  2. Do not compact file reads, patches, diffs, retrieved context, skill docs, memory results, MCP results, or web extraction output.
  3. Do not treat Noisegate as a raw-output archive. Raw artifacts are off by default.
  4. Keep Hermes-LCM optional. Noisegate must work without it.
  5. Do not write raw terminal output into Hindsight.
  6. If compaction fails, preserve the original output.
  7. Before committing, run the quality gate and scan the diff for secrets and personal/private data.

Safe smoke test for a lane or installation:

noisegate doctor
python - <<'PY' | noisegate reduce --command "pytest"
for i in range(260):
    print(f"line {i:03d}")
print("FAILED tests/test_demo.py::test_keeps_signal")
print("AssertionError: signal survived")
PY
printf '%s\n' '[noisegate:bypass]' 'line that must stay exact' | noisegate reduce --command "pytest"

Expected result:

  • doctor reports a healthy package/plugin state
  • long noisy output gets smaller
  • the failure line stays visible
  • bypass output stays unchanged
  • no config writes, git writes, service restarts, or artifact writes happen unless explicitly requested
  • install-hermes dry-runs show exact install/enable commands before changing Hermes

Safety model

Noisegate is intentionally conservative. Paranoid, even. That is a feature.

Compacted output is kept within the configured max_chars and max_lines caps. If a readable omission marker plus preserved content cannot fit, Noisegate leaves the original output unchanged instead of emitting marker fragments or dropping important failure text.

For Hermes hook traffic, it compacts only this explicit allowlist:

terminal
process
read_terminal
browser_console

Protected surfaces include:

read_file
write_file
patch
apply_patch
skill_view
skill_manage
session_search
memory
hindsight_*
lcm_*
mcp_* / mcp__*
web_search
web_extract
execute_code
search_files
git diff / unified diffs
unknown future tools

Bypass controls:

NOISEGATE_BYPASS
NOISEGATE_RAW
[noisegate:bypass]
[noisegate:raw]

Environment flags:

NOISEGATE_DISABLE=1      # turn compaction off
NOISEGATE_ARTIFACTS=1    # opt in to private raw-output artifacts
NOISEGATE_ARTIFACT_DIR=/path/to/artifacts
NOISEGATE_ARTIFACT_SIZE_CAP=1000000  # max stored raw-output bytes per artifact

noisegate doctor reports ignored or fallback environment values, so typos like NOISEGATE_ARTIFACTS=maybe do not fail silently.

Hermes calls transform_terminal_output before its built-in terminal redaction pass. Noisegate still compacts inline terminal output there, but it disables raw artifact storage on that early hook so pre-redaction output is not persisted.

Artifacts

Raw terminal output is not stored by default.

When artifact mode is enabled, Noisegate writes the original output to a private filesystem store:

  • directory mode 0700
  • file mode 0600
  • default size cap of 1,000,000 bytes
  • content-addressed IDs shaped like ng_<sha256-prefix>
  • path containment and symlink traversal checks

Retrieve an artifact:

noisegate cat ng_<artifact-id>

Inspect the store:

noisegate artifacts list --artifact-dir /tmp/noisegate-artifacts
noisegate artifacts stats --artifact-dir /tmp/noisegate-artifacts
noisegate artifacts verify --artifact-dir /tmp/noisegate-artifacts

verify recomputes hashes and returns a non-zero exit code if an artifact was tampered with, has an invalid private-store path, or if a live temp artifact file is still present. Stale temp files created by interrupted writes are removed during verification/new writes without printing their raw contents.

Hermes-LCM and memory layers

Noisegate is not Hermes-LCM and does not require Hermes-LCM.

If Hermes-LCM is installed, Noisegate acts as an inline compaction step before noisy output inflates active context. Downstream context or transcript layers usually see the compacted result.

Hindsight is semantic long-term memory, not a raw output bucket. Noisegate must not write raw terminal output into Hindsight.

Development

Start clean:

git status --short --branch
git remote -v

Run the local quality gate:

uv run ruff check .
uv run python -m pytest -q
uv run python scripts/check_release.py
uv run python scripts/check_contributors.py
(cd npm/noisegate && npm ci --ignore-scripts && npm test && npm pack --dry-run)
rm -rf dist
uv build
uvx twine check dist/*
git diff --check

Release and publishing

Noisegate uses release-cycle publishing, not random local tokens and crossed fingers:

  • PyPI package: noisegate-hermes
  • npm package: noisegate-hermes installer wrapper
  • the main release workflow publishes the GitHub Release, then PyPI, then npm
  • npm publish waits until the matching PyPI version is visible
  • GitHub Actions publish through OIDC/trusted publishing where supported
  • npm publish uses provenance (npm publish --provenance)
  • no long-lived publish tokens in git or workflow files
  • main is branch-protected; release changes go through PR review

Release helpers:

uv run python scripts/prepare_release.py 0.2.0
uv run python scripts/check_release.py --tag v0.2.0
uv run python scripts/build_release_notes.py v0.2.0 --repo Tosko4/noisegate --output dist/release-notes.md

build_release_notes.py combines the versioned changelog section with GitHub PR metadata for the tag range. Release notes must include update instructions, categorized PRs, each PR's OP/author handle, and first-time contributors whose first merged PR landed since the previous release.

Release metadata must stay aligned across:

  • pyproject.toml -> [project].version
  • noisegate/_version.py -> __version__
  • noisegate/plugin.yaml -> plugin manifest version
  • uv.lock -> locked editable project version
  • npm/noisegate/package.json -> npm wrapper version
  • npm/noisegate/package-lock.json -> npm wrapper lockfile version

GitHub Actions run linting, tests, release metadata checks, contributor checks, package build, twine check, npm wrapper checks, npm dry-run packing, and wheel install smoke tests on Python 3.11, 3.12, and 3.13.

What Noisegate is not

Noisegate is not a model summarizer.

It is not a replacement for logs.

It is not a database.

It is not a magic context engine.

It is a small gate in front of noisy agent output. That is the whole point.

Attribution

Noisegate was informed by the MIT-licensed Tokenjuice project, especially its ideas around deterministic reducers, command classification, safe bypasses, artifact opt-in, and machine-readable metadata.

Noisegate is a fresh Python implementation focused on Hermes Agent.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

noisegate_hermes-0.1.2.tar.gz (2.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

noisegate_hermes-0.1.2-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file noisegate_hermes-0.1.2.tar.gz.

File metadata

  • Download URL: noisegate_hermes-0.1.2.tar.gz
  • Upload date:
  • Size: 2.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for noisegate_hermes-0.1.2.tar.gz
Algorithm Hash digest
SHA256 ae258d15e54ffee2b97908afd1e23206ddf65ab208e7a9c6744e59d2d6585cf8
MD5 ceda6d64e64a91f64187f8ea24cbed6d
BLAKE2b-256 36bb0b5117ba9f160bc5deb7b5a32635243d609954100fb283c04d971a3f999b

See more details on using hashes here.

Provenance

The following attestation bundles were made for noisegate_hermes-0.1.2.tar.gz:

Publisher: release.yml on Tosko4/noisegate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file noisegate_hermes-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for noisegate_hermes-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 df8668b98cebd469f08f38158451baead8d9b58d9cbe95ac8ca643d109e7e8c6
MD5 7bd5157b3e2e67a4fab7a6147bd7072c
BLAKE2b-256 fab98d4cb964de40f4d9cff81dbae75182735cd0a8a795bf8611763d4843930a

See more details on using hashes here.

Provenance

The following attestation bundles were made for noisegate_hermes-0.1.2-py3-none-any.whl:

Publisher: release.yml on Tosko4/noisegate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page