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 tiny, deterministic compaction layer for Hermes Agent. It catches the massive terminal walls, test logs, build spam, and search dumps before they flood your model context, while leaving exact content alone.

No model calls. No fuzzy summaries. No "trust me bro" compression.

Just predictable reducers, safe bypasses, protected outputs, and enough metadata to know what happened.

The problem

Agents are great at running tools.

Tools are great at producing nonsense amounts of output.

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 it does

Noisegate gives Hermes Agent 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 for Hermes

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

The easiest path is the installer command:

uvx --from noisegate-hermes noisegate install-hermes

That command:

  1. finds the hermes launcher on PATH;
  2. resolves the Hermes Python interpreter from either a Python console-script shebang or the official Hermes bash shim;
  3. installs noisegate-hermes into that interpreter environment;
  4. enables the noisegate Hermes entry-point plugin through Hermes config helpers;
  5. runs noisegate doctor inside the Hermes Python environment.

Preview the exact commands without changing anything:

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

From a checkout, install that exact checkout into Hermes:

uv run noisegate install-hermes --package .

Manual fallback for older installs where command -v hermes is a Python console script:

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

Noisegate registers two Hermes hooks:

transform_terminal_output
transform_tool_result

npm installer wrapper

The npm package noisegate-hermes is only a thin convenience installer. It is not the canonical implementation. It delegates to the Python package:

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

The npm package has no postinstall script and does not bundle the Python implementation.

Publishing and package security

Noisegate uses release-cycle package publishing, not ad-hoc local tokens:

  • 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 noisegate-hermes version is visible on PyPI
  • GitHub Actions publish with OIDC/trusted publishing where supported
  • npm publish uses provenance (npm publish --provenance)
  • no long-lived publish tokens in git or workflow files
  • any emergency/recovery credentials belong in Keeper, not chat, git, logs, or CI output
  • main is branch-protected; package releases must come from reviewed release-cycle changes

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.

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
rm -rf dist
uv build
uvx twine check dist/*
git diff --check

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 --output dist/release-notes.md

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.1.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.1-py3-none-any.whl (33.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: noisegate_hermes-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 853ec3aebce75ea71de61c3c0052b850e1a80e1dbab0ad9b6c57f93e2de59084
MD5 340809c97aa8523c04dd2f557fcdcfc7
BLAKE2b-256 4e3cc29c3533eef6ba7d99ca77636837144e1c3cb2636a7f50208d45c6455acb

See more details on using hashes here.

Provenance

The following attestation bundles were made for noisegate_hermes-0.1.1.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.1-py3-none-any.whl.

File metadata

File hashes

Hashes for noisegate_hermes-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3231a95efd0b120c483c648686eacfb3d7d00a7f2fc373b3a7126b20391d6ad4
MD5 9f77f06c5777127d73edf8efb096e929
BLAKE2b-256 c1069d1d7075cb62761b8219e158587ea41a49c360267c1028fa8115c3e3aa01

See more details on using hashes here.

Provenance

The following attestation bundles were made for noisegate_hermes-0.1.1-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