Skip to content

Repository files navigation

Aphrodite 💋 Hermes Plugin

CCR compression plugin for Hermes Agent - thin Python loader + Rust dylib. Sub-ms tool output compression, 26-type classifier, 13 tools, 9 skills.

Aphrodite intercepts tool output before it reaches the LLM and replaces it with compact, structured previews. The agent sees 15 tokens of metadata instead of 500 tokens of raw text - and retrieves the full content only when it actually needs it. All compression logic runs in the Rust dylib.

plugin hermes license


Install ⚡

One-command

git clone https://github.com/PlayForm/Aphrodite-Hermes.git
ln -s "$(pwd)/Aphrodite-Hermes" ~/.hermes/plugins/aphrodite
hermes plugins enable aphrodite
hermes

On first launch, the plugin automatically downloads the aphrodite binary from releases. No Rust toolchain required.

Native Windows: run pwsh ./download.ps1 instead of download.sh - no Git Bash/WSL needed. See Windows install for the full walkthrough, and Troubleshooting if the proxy doesn't come up after enabling the plugin.

LLM provider configuration (required)

The aphrodite proxy is an OpenAI-compatible LLM API proxy - it forwards requests upstream - so it needs its own provider credentials even though Hermes already has a provider configured. The plugin cannot read Hermes' provider config, and there is no keyless / compression-only mode: without a key the proxy refuses to start and the plugin is unusable.

export APHRODITE_API_KEY="sk-..."                                  # REQUIRED
export APHRODITE_API_URL="https://api.openai.com"                  # optional
export APHRODITE_MODEL="default-model"                             # optional

Alternatives: run aphrodite setup, or add api_key / api_url / model to ~/.hermes/aphrodite/aphrodite.toml. If the proxy fails to start, ~/.hermes/aphrodite/proxy-stderr.log shows the reason - no API key configured means the key is missing.

What changes after install

After installing and launching Hermes once:

~/.hermes/
├── plugins/
│   └── aphrodite → /path/to/Aphrodite-Hermes    ← symlink to this repo
├── aphrodite/
│   ├── aphrodite                                 ← auto-downloaded binary (~12 MB)
│   └── ccr.db                                    ← SQLite CCR store (on first run)
└── profiles/<name>/
    └── plugins/
        └── aphrodite → ~/.hermes/plugins/aphrodite

The plugin also adds to your Hermes config:

# Added automatically on enable
plugins:
  enabled:
    - aphrodite

# Recommended additions (manual)
context:
  engine: aphrodite
  engine_threshold_pct: 55
model:
  context_length: 1000000

Two proxy processes launch on :9797 (cache) and :9798 (token).

Verify it's working

# In a Hermes session:
aphrodite_stats

# Or via CLI:
curl http://127.0.0.1:9798/health
# → {"status":"ok","version":"<current aphrodite version - see the badge above>"}

Clean uninstall

hermes plugins disable aphrodite
rm ~/.hermes/plugins/aphrodite
pkill -f "aphrodite/binaries/aphrodite"

Architecture 🏗️

Python (thin loader)              Rust dylib (all logic)
  __init__.py       421L            libaphrodite_hermes.dylib
    ↓ ctypes FFI                      ← universal dispatch (5 hooks)
  libaphrodite_hermes.dylib           ← 13 tool handlers, delegates into
                                      libaphrodite (core engine): hooks,
                                      resolve, stage2, struct_extract, state,
                                      catalog, session, marker, prefetch,
                                      config_loader

All 5 hooks + 13 tools delegate to Rust. Python serves as fallback. Hot-reload: rebuild dylib → mtime change detected → next call picks up new code.


Tools 🛠️

Tool Description
aphrodite_retrieve Resolve <<<CCR:hash|type>>> markers
aphrodite_compress Compress content via CCR with type hint
aphrodite_stats Proxy health, engine status, inline store size
aphrodite_rebuild Report binary/proxy version + a rebuild hint (does not rebuild or restart itself)
aphrodite_files Tracked file references grouped by tool
aphrodite_diff Conversation turn history with summaries
aphrodite_search Search CCR store by keyword or type
aphrodite_directive List/swap/add/remove/reset active behavioral directives
aphrodite_test Smoke test suite: quick (1 sample) or full (3 samples)
aphrodite_catalog Full CCR catalog with hashes, types, sizes, previews
aphrodite_reclassify Retroactive metadata enrichment
aphrodite_prefetch Background file read + compress (markers return instantly)
aphrodite_prefetch_status Live prefetch schedule: loading, ready, errors

Configuration ⚙️

All tuning in aphrodite.toml (searched: CWD → ~/.hermes/aphrodite/ → repo root):

[compression]
engine_threshold_pct = 45    # compress at 45% context fill
engine_protect_first = 2     # messages to keep at start
engine_protect_last = 5      # messages to keep at end
engine_min_msgs = 8          # minimum before activating
tool_threshold_token = 512   # token proxy threshold (bytes)
tool_threshold_cache = 4096  # cache proxy threshold (bytes)
code_multiplier = 3.0        # keep code in context longer
context_engine = true        # default-on, no env var needed

[previews]
model_family = "code_first"  # compact | code_first | balance
code_structure_map = true    # show fn/struct/class sigs

[prompts]
retrieve_guidance = "verbose"
ccr_marker_hint = true

Env var overrides: APHRODITE_ENGINE_THRESHOLD_PCT, APHRODITE_CONTEXT_ENGINE, etc.

APHRODITE_HOME relocates the plugin's Python-side data (hot-reload dylib copies, proxy-stderr.log) from the default ~/.hermes/aphrodite; the Rust binary does not read it - aphrodite.toml / ccr.db lookup stays put.

On registration the plugin probes both health endpoints (:9797, :9798) and reuses an already-running proxy pair instead of launching a second instance, so extra Hermes processes no longer pile failed to bind listener noise into proxy-stderr.log. Set APHRODITE_NO_AUTO_LAUNCH=1 to skip the auto-launch entirely, e.g. when a cargo watch dev loop runs the proxy itself.

Directives

Custom behavioral directives are name.md files in ~/.hermes/aphrodite/directives/ - an empty file means an intentionally empty directive. The plugin ships its own directives/ set, auto-exposed to the dylib via APHRODITE_DIRECTIVES_DIR (override the env var to point elsewhere). If no directive directory is found, the compiled built-in set loads as a fallback - its activation is logged. Manage them at runtime with aphrodite_directive (list/swap/add/load/remove/reset).


Dev Install (Rust source)

git clone https://github.com/PlayForm/Aphrodite.git
cd Aphrodite
cargo build -p aphrodite
# Dylib at target/debug/libaphrodite.dylib - auto-detected by plugin

Files

Aphrodite-Hermes/
├── __init__.py          ← 421-line Python loader (ctypes FFI)
├── plugin.yaml          ← 13 tools, 5 hooks, context engine
├── download.sh          ← Binary auto-downloader (macOS/Linux/Git Bash/WSL)
├── download.ps1         ← Binary auto-downloader (native Windows PowerShell)
├── binaries/            ← Platform-native dylib + proxy binary
├── README.md            ← This file
└── .gitignore

About

CCR compression plugin for Hermes Agent - 13 tools, dual-proxy, context engine.

Resources

Code of conduct

Stars

10 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages