I created another paper for hermes optimization, this one is pretty aggressive in its approach but does the job well. It bypasses some hermes built in feature to make this one feasible. Version i use is 0.19.
From running 190 skills every session now i only have 2, and when i need the skills it is auto loaded by a plug in when it reaches the llm, context is not over bloated, making alot of token saving.
When using the cheapest model the savings is not that huge but if you are a power user the savings are enormous.
Read the Following or make your hermes read this for implementation.
# Skill Routing Architecture for LLM Agents
## On-Demand Context Injection via Nickname & Semantic Vector Routing
**Authors:**
Hermes Agent Community
**System:**
Hermes Agent (Nous Research)
**Date:**
July 2026
**Status:**
Production — 2+ weeks operational
---
## Abstract
Large Language Model (LLM) agents carry a system prompt that includes metadata about available capabilities — typically called "skills." In stock Hermes Agent, all installed skills (~190) are enumerated in `<available_skills>` on every turn, consuming
**~28,000 characters**
of context regardless of relevance to the user's current request. This paper presents a three-phase approach that reduces active skill tokens to effectively zero while preserving — and in some cases improving — discovery and loading of domain-specific knowledge. The system combines: (1) aggressive skill disabling (190→2), (2) deterministic nickname-based routing (59 triggers → 24 skills), and (3) semantic vector search (190-dim embedding index, cosine similarity ≥0.44) with
**top-3 multi-skill retrieval**
for compound queries spanning multiple domains. The plugin architecture hooks into the agent's gateway dispatch layer, intercepting user messages
*before*
the LLM processes them, and injects skill content inline at zero LLM token cost for the search itself. Over 2+ weeks of production operation, the system has matched ~5-10 queries per day with an average semantic relevance score of 0.62, and passthrough queries incur zero additional token overhead.
---
## 1. Problem Statement
### 1.1 The Skill Enumeration Tax
LLM agents traditionally enumerate all available capabilities in their system prompt:
```xml
<available_skills>
agent-communication-style, agent-observability, agent-provider-config, ...
+180 more
</available_skills>
```
Each entry consumes characters on
**every single turn**
— regardless of whether the skill is ever used. In stock Hermes Agent with defaults:
- ~190 installed skills
- ~28,000 characters (~7,000 tokens at 4:1 ratio) in system prompt
- Every turn pays this tax, even for "hello" or "what's the weather?"
### 1.2 The Discovery Problem
The standard `skill_view()` mechanism requires a two-turn process:
1. Agent decides to load a skill (costs LLM tokens for the reasoning)
2. Agent calls skill_view → reads the skill content (costs tool-call tokens)
3. On the next turn, the skill content is available
This means the first response to a domain-specific query is always "Let me check..." — never an informed answer.
### 1.3 The Disabled-Skill Blindness
Aggressively disabling skills solves the token tax but creates a new problem: disabled skills are excluded from `get_skill_commands()`, meaning the gateway cannot resolve `/skill-name` rewrites for them. The standard approach of rewriting `"check the database"` to `"/database-schema check the database"` fundamentally breaks when the skill is disabled.
---
## 2. Architecture Overview
```
User: "check the game server"
│
▼
┌──────────────────────────────────────────────────┐
│ pre_gateway_dispatch (GATEWAY HOOK) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Phase 1: │ │ Phase 2: │ │
│ │ Nickname │───→│ Vector │ │
│ │ (determin.) │ │ Search (sem.)│ │
│ │ ↓ match or │ │ ↓ if no │ │
│ │ ↓ │ │ nickname: │ │
│ │ skill= game- │ │ embed → │ │
│ │ ecosystem │ │ cosine sim → │ │
│ └──────┬───────┘ │ if ≥ 0.44: │ │
│ │ │ skill found │ │
│ │ └──────┬───────┘ │
│ │ │ │
│ └────────┬──────────┘ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ Phase 3: Inline Inject │ │
│ │ Read SKILL.md from disk │ │
│ │ Inject into user msg │ │
│ │ Append discoverable │ │
│ │ skills index note │ │
│ └──────────┬──────────────┘ │
└───────────────┼──────────────────────────────────┘
│
▼
LLM receives augmented message with
skill content already in context
(zero extra turns, zero extra tool calls)
```
### System Components
| Component | Purpose | Lines of Code |
|-----------|---------|--------------|
| `config.yaml` — skill disable list | ~185 skills disabled, 2 active | N/A (config) |
| `__init__.py` — plugin hooks | `pre_gateway_dispatch` + `pre_llm_call`, top-3 vector search | ~455 |
| `plugin.yaml` — plugin registration | Hermes plugin metadata | 5 |
| `build_skill_index.py` — index builder | Scans skills → embeds → saves | ~240 |
| `NICKNAME_MAP` — deterministic triggers | 59 entries → 24 skills | (inline in plugin) |
| `entries.json` — vector index | ~190 entries, 384-dim embeddings | ~136KB |
| `index.json` — index metadata | Version, threshold, timestamp | N/A |
---
## 3. Phase 1: Aggressive Skill Trimming
### 3.1 Rationale
In stock Hermes, the system prompt lists all installed skills regardless of use frequency. Our usage audit revealed:
-
**~190**
SKILL.md files on disk
-
**~185**
disabled in `config.yaml`
-
**2**
active (`hermes-agent`, `plan`)
-
**Ratio: ~1%**
active
The two retained skills are meta-tools: `hermes-agent` (for configuring Hermes itself) and `plan` (for structured planning). Everything else — domain knowledge, integrations, image generation, database access — is loaded on-demand via the routing system.
### 3.2 Implementation
```yaml
# config.yaml
skills:
disabled:
- agent-communication-style
- agent-observability
- airtable
# ... all non-essential skills
- youtube-content
```
The disabled list is exhaustive: every skill not actively used in the last 30 days is disabled. New skills are added to this list by default and only moved to the routing index if they prove useful.
### 3.3 Token Savings
All cost figures use DeepSeek V4 Flash blended pricing (78% cache hit at $0.0028/M + 22% cache miss at $0.14/M =
**$0.033/M effective**
). This table shows only the skill enumeration tax — not full conversation cost. See §7.4 for complete model-by-model comparison including GPT-4o, GPT-4.1, and GPT-5.5.
| Metric | Stock (190 active) | Trimmed (2 active) | Savings |
|--------|-------------------|-------------------|---------|
| Skill tokens per turn | ~7,000 | ~80 |
**98.9%**
|
| Cost per turn (blended) | $0.00023 | $0.000003 |
**$0.00023/turn**
|
| Daily savings (50 turns) | — | — |
**~$0.012/day**
|
| Monthly savings | — | — |
**~$0.35/month**
|
| Annual savings (18,250 turns) | — | — |
**~$4.20/year**
|
>
**Note:**
These figures account only for the skill token tax. The eliminated tool-call round-trips (1-2 extra LLM turns per matched query) save an additional ~$0.0009 per match — see §7.4.4 for the full breakdown across all model tiers.
In practice, the system prompt with 2 skills is indistinguishable from a system prompt with 190 skills for almost every query — because the missing skills are injected on-demand when relevant.
---
## 4. Phase 2: Nickname Routing (Deterministic)
### 4.1 Design
Deterministic substring matching runs
**first**
— before any vector search — because it is:
-
**Zero-cost**
: simple Python `in` check
-
**Zero-latency**
: microseconds vs milliseconds
-
**Precise**
: no false positives, no threshold tuning
### 4.2 The Nickname Map
```python
NICKNAME_MAP = {
# Domain-specific project
"the digitization": "digitization-workflow",
"the data api": "data-integration",
# Gaming / D&D
"the game server": "game-ecosystem",
"the dungeon server": "game-ecosystem",
# Infrastructure
"the dns server": "self-hosted-dns",
"the dashboard": "dashboard-tunnel-proxy",
# Email & comms
"the email": "email-automation",
# ... 59 total entries, 24 unique skills
}
```
### 4.3 Design Decisions
**Why definite article prefix?**
Every nickname starts with "the " (e.g., "the game server", "the email"). This was a deliberate choice for three reasons:
1.
**Reduces false positives**
: "the email" is specific; "email" by itself could match chat about email in general
2.
**Natural language flow**
: Users naturally say "check the email" not just "email"
3.
**Single-token matching**
: A simple substring check suffices — no regex, no fuzzy matching
**Why substring matching instead of exact?**
Users vary their phrasing: "check the game server" vs "talk to the game server". Substring `in` handles both without complex NLP.
### 4.4 Example Matches
```
User: "check the game server"
→ match: "the game server" → skill: game-ecosystem
User: "what did the email say"
→ match: "the email" → skill: email-automation
User: "the hermes config needs updating"
→ match: "the hermes config" → skill: hermes-agent (loaded!)
```
---
## 5. Phase 3: Semantic Vector Search
### 5.1 Embedding Pipeline
When no nickname matches, the system falls back to semantic vector search.
**Model:**
`all-MiniLM-L6-v2`
- 384-dimensional embeddings
- Sentence-Transformers library
- ~3ms encode time per query
**Index:**
~190 skill embeddings, stored in:
- `entries.json`: metadata (skill name, file path, description, tags, category)
- `embeddings.npy`: 190 × 384 float32 matrix
- `index.json`: version, timestamp, model name
### 5.2 Build Process
```python
def build_embed_text(skill, skill_body=""):
parts = [skill["name"], skill["description"]]
if skill["tags"]:
parts.append(" ".join(skill["tags"]))
if skill["category"]:
parts.append(skill["category"])
# Extract trigger phrases from ## When / ## Trigger sections
if skill_body:
trigger_text = extract_trigger_sections(skill_body)
if trigger_text:
parts.append(trigger_text)
return " ".join(p for p in parts if p)
```
The embedding text combines:
1. Skill
**name**
(e.g., "data-integration")
2.
**Description**
from frontmatter (e.g., "Query database tables via API")
3.
**Tags**
(e.g., ["CRM", "API", "Enterprise"])
4.
**Trigger phrases**
extracted from the skill body's "When to use" sections
### 5.3 Search Algorithm
```python
def search(query, top_k=3):
query_vec = model.encode(query)
scores = cosine_similarity(query_vec, all_embeddings)
top_indices = argsort(scores)[::-1][:top_k]
results = []
for idx in top_indices:
score = scores[idx]
if score >= entries[idx]["threshold"]: # default: 0.44
results.append((entries[idx], score))
return results # all matches above threshold, up to 3
```
### 5.4 Threshold Tuning
The default threshold of
**0.44**
was empirically determined:
-
**Too low (<0.3)**
: False positives — irrelevant skills loaded
-
**Too high (>0.6)**
: Misses — relevant skills not loaded
-
**0.44**
: Balances precision (noise) vs recall (coverage)
Individual skills can override the threshold in their index entry (`"threshold": 0.44`), allowing manual tuning for ambiguous skills.
### 5.5 Lazy Loading
The model and index are loaded lazily on first match request:
- `_get_model()`: Loads SentenceTransformer on first call (thread-safe, double-checked locking)
- `_load_index()`: Loads entries.json + embeddings.npy on first call; re-loads if file mtime changes
- Both cached globally in the plugin module for the process lifetime
---
## 6. The Gateway Hook Architecture
### 6.1 Hermes Plugin System
Hermes Agent supports plugin hooks at two critical points in the request lifecycle:
```
User Message
│
▼
pre_gateway_dispatch ← Our plugin intercepts here
│ (rewrite message before LLM sees it)
▼
pre_llm_call ← Our plugin adds context here
│ (first LLM turn only)
▼
LLM processes enriched message
```
### 6.2 pre_gateway_dispatch (The Main Hook)
```python
def handle_pre_gateway_dispatch(event, gateway, session_store, **kwargs):
text = event.text
# Skip trivial messages
if len(text.strip()) < 3 or text.startswith("/"): return
# Phase 1: Nickname match (deterministic, single skill)
skill = check_nickname(text)
# Phase 2: Vector search fallback (semantic, up to 3 skills)
if not skill:
results = vector_search(text, top_k=3)
if results:
# Inject ALL matched skills above threshold
contents = []
for entry, score in results:
content = read_skill_file_from_index(entry)
contents.append(content)
skill_body = "\n\n".join(contents)
if not skill and not contents:
return # Passthrough — no skill needed
# Phase 3: Load and inject skill content inline
rewritten = f"""{text}
{skill_body}
📋 [Plugin] ~190 skills available (use skill_view)
"""
return {"action": "rewrite", "text": rewritten}
```
### 6.3 Why Direct File Loading?
The critical insight:
**disabled skills cannot be loaded via `/skill-name` rewrite**
because the Hermes gateway's `get_skill_commands()` excludes disabled skills. Our plugin bypasses this entirely by:
1. Storing the
**absolute file path**
in the vector index entry (`skill_file`)
2. Reading the SKILL.md directly from disk with `Path.read_text()`
3. Injecting the raw content inline in the user message
This means the skill appears to the LLM as if it was in the system prompt all along — but only when relevant.
### 6.4 pre_llm_call (The Assistant Hook)
```python
def handle_pre_llm_call(**kwargs):
# On matched turns, inject a compact skills reference
return {"context": "[Plugin: ~190 skills — data-integration, game-ecosystem, ... +180 more]"}
```
This helps the LLM understand what's available without scanning the full `<available_skills>` block.
### 6.5 Injection Guard
To prevent re-injection during tool-loop turns (where the same message text cycles through multiple LLM calls), the plugin tracks `_last_injected_text`:
```python
if _last_injected_text == note:
return None # Already injected this turn
```
---
## 7. Performance Impact
### 7.1 Token Savings
| Scenario | Stock Hermes | Our System | Savings |
|----------|-------------|------------|---------|
| Passthrough query | 7,000 skill tokens | 80 skill tokens |
**98.9%**
|
| Nickname match | 7,000 + 2 turns | 80 + inline |
**~99% + 2 fewer turns**
|
| Vector match | 7,000 + 2 turns | 80 + inline |
**~99% + 2 fewer turns**
|
### 7.2 Latency
| Operation | Latency | Notes |
|-----------|---------|-------|
| Nickname match | ~0.001ms | Simple substring check |
| Vector encode | ~3ms | all-MiniLM-L6-v2 on CPU |
| Cosine similarity | ~0.01ms | NumPy batched dot product |
| File read | ~0.1ms | SKILL.md from SSD |
|
**Total (vector path)**
|
**~3.1ms**
| Before LLM invocation |
|
**Total (nickname path)**
|
**~0.1ms**
| Essentially zero |
### 7.3 Production Statistics
| Metric | Value |
|--------|-------|
| Skills indexed | ~190 |
| Nickname entries | 59 (mapping to 24 unique skills) |
| Vector index dims | 384 |
| Default threshold | 0.44 |
| Active skills | 2 (~1% of total) |
| Plugin code | ~455 lines |
| Total system files | 4 (plugin.py, plugin.yaml, build_index.py, config.yaml) |
### 7.4 Cost Impact — Model Comparison
The following tables compute real costs using July 2026 API pricing. All calculations assume:
-
**Without routing:**
~7,000 skill tokens + ~2,500 conversation tokens = ~9,500 input + ~500 output per turn
-
**With routing:**
~2,000 input + ~500 output per turn (skill enumeration tax eliminated)
-
**50 turns/day**
,
**30 days/month**
(1,500 turns/month)
-
**DeepSeek V4 Flash**
uses a blended input rate: 78% cache hits at $0.0028/M + 22% cache misses at $0.14/M =
**$0.033/M effective**
#### §7.4.1 Per-Turn Cost
| Provider | Model | No Routing | With Routing | Savings/Turn | Savings % |
|----------|-------|-----------|-------------|-------------|----------|
|
**DeepSeek**
| V4 Flash | $0.000454 | $0.000206 |
**$0.000248**
|
**54.6%**
|
|
**DeepSeek**
| V4 Pro | $0.001260 | $0.000595 |
**$0.000665**
|
**52.8%**
|
|
**OpenAI**
| GPT-4.1-nano | $0.001150 | $0.000400 |
**$0.000750**
|
**65.2%**
|
|
**OpenAI**
| GPT-4o-mini | $0.001725 | $0.000600 |
**$0.001125**
|
**65.2%**
|
|
**OpenAI**
| GPT-4.1-mini | $0.004600 | $0.001600 |
**$0.003000**
|
**65.2%**
|
|
**OpenAI**
| GPT-4.1 | $0.023000 | $0.008000 |
**$0.015000**
|
**65.2%**
|
|
**OpenAI**
| GPT-4o | $0.028750 | $0.010000 |
**$0.018750**
|
**65.2%**
|
|
**OpenAI**
| GPT-5 (est.) | $0.016875 | $0.005833 |
**$0.011042**
|
**65.4%**
|
|
**OpenAI**
| GPT-5.5 | $0.067250 | $0.023333 |
**$0.043917**
|
**65.3%**
|
The routing architecture saves a higher
**percentage**
on OpenAI models (65%) vs DeepSeek (53-55%) because cheaper models have a lower per-token cost — making the fixed absolute token savings (7,000 input tokens/turn) a larger fraction of a more expensive base.
#### §7.4.2 Daily & Monthly Cost (50 turns/day)
| Model | Daily (No Routing) | Daily (With Routing) | Daily Savings | Monthly Savings |
|-------|-------------------|---------------------|--------------|----------------|
|
**DeepSeek V4 Flash**
| $0.0227 | $0.0103 |
**$0.0124**
|
**$0.37**
|
|
**DeepSeek V4 Pro**
| $0.0630 | $0.0298 |
**$0.0332**
|
**$1.00**
|
|
**GPT-4.1-nano**
| $0.0575 | $0.0200 |
**$0.0375**
|
**$1.13**
|
|
**GPT-4o-mini**
| $0.0863 | $0.0300 |
**$0.0563**
|
**$1.69**
|
|
**GPT-4.1-mini**
| $0.2300 | $0.0800 |
**$0.1500**
|
**$4.50**
|
|
**GPT-4.1**
| $1.150 | $0.400 |
**$0.750**
|
**$22.50**
|
|
**GPT-4o**
| $1.438 | $0.500 |
**$0.938**
|
**$28.13**
|
|
**GPT-5 (est.)**
| $0.844 | $0.292 |
**$0.552**
|
**$16.56**
|
|
**GPT-5.5**
| $3.363 | $1.167 |
**$2.196**
|
**$65.88**
|
#### §7.4.3 Annual Projection (18,250 turns/year)
| Model | No Routing | With Routing | Annual Savings |
|-------|-----------|-------------|---------------|
| DeepSeek V4 Flash |
**$8.28**
|
**$3.76**
|
**$4.52**
|
| DeepSeek V4 Pro |
**$23.00**
|
**$10.86**
|
**$12.14**
|
| GPT-4.1-nano |
**$20.99**
|
**$7.30**
|
**$13.69**
|
| GPT-4o-mini |
**$31.49**
|
**$10.95**
|
**$20.54**
|
| GPT-4.1-mini |
**$83.95**
|
**$29.20**
|
**$54.75**
|
| GPT-4.1 |
**$419.75**
|
**$146.00**
|
**$273.75**
|
| GPT-4o |
**$524.69**
|
**$182.50**
|
**$342.19**
|
| GPT-5.5 |
**$1,227.31**
|
**$425.83**
|
**$801.48**
|
#### §7.4.4 Plus Eliminated Tool-Call Rounds
Each matched query eliminates ~1-2 extra LLM turns (the "let me check" → skill_view → respond cycle). At our observed ~5-10 matches/day:
| Model | Extra cost saved per match | ~5 matches/day | ~10 matches/day |
|-------|---------------------------|----------------|-----------------|
| DeepSeek V4 Flash | $0.0009 | $0.0045/day | $0.009/day |
| GPT-4o-mini | $0.0035 | $0.0175/day | $0.035/day |
| GPT-4.1-mini | $0.0092 | $0.046/day | $0.092/day |
| GPT-4o | $0.0575 | $0.288/day | $0.575/day |
| GPT-5.5 | $0.1345 | $0.673/day | $1.345/day |
#### §7.4.5 The Counterintuitive Finding
**This architecture matters
*more*
on expensive models than cheap ones.**
A GPT-5.5 deployment without routing burns
**$1,227/year**
on idle skill enumeration tax alone — effectively paying $3.36/day just to say "hello." With routing, that drops to $426/year. The absolute dollar savings scale linearly with model cost per token, making this optimization most valuable precisely where token budgets are tightest.
For DeepSeek V4 Flash users, the savings are modest (~$4.52/year — roughly 2 cups of coffee). But the
**latency benefit**
and
**eliminated round-trips**
apply identically regardless of model: the first response to "check the database" arrives informed, not "let me look that up."
---
## 8. Replication Guide
### 8.1 Prerequisites
- Hermes Agent (or any LLM agent framework with plugin/gateway hooks)
- Python 3.10+
- `sentence-transformers` + `numpy` (for vector search)
- Skills directory with SKILL.md files
### 8.2 Step 1: Audit & Trim
```bash
# Count total skills
hermes skills list | grep -c enabled
# Disable aggressively in config.yaml
skills:
disabled:
- skill-you-never-use
# ... all but 2-3 essentials
```
### 8.3 Step 2: Build the Index
```python
# build_skill_index.py — scans skills directory, creates embeddings
for skill_md in skills_dir.rglob("SKILL.md"):
parse_frontmatter(skill_md) # name, description, tags, category
embed_text = f"{name} {description} {' '.join(tags)} {category}"
model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(all_embed_texts)
np.save("embeddings.npy", embeddings)
```
### 8.4 Step 3: Create Nickname Map
```python
NICKNAME_MAP = {
"the project": "project-anatomy",
"the database": "database-schema",
# ... map common user phrases to skill names
}
```
### 8.5 Step 4: Implement Gateway Hook
```python
def pre_gateway_dispatch(event):
text = event.text
# Try nickname first (cheap, deterministic)
skill = NICKNAME_MAP.get(text)
# Fall back to vector search (semantic, higher cost)
if not skill:
query_vec = model.encode(text)
scores = cosine_similarity(query_vec, index_embeddings)
if max(scores) >= 0.44:
skill = entries[argmax(scores)]["skill_name"]
if not skill:
return # passthrough
# Read skill content from DISK (not from framework's skill loader)
content = Path(entries[skill]["skill_file"]).read_text()
# Inject inline
return {"action": "rewrite", "text": f"{text}\n\n{AUTO_LOAD_MARKER}{content}{AUTO_LOAD_END}"}
```
### 8.6 Key Architecture Decision
**Always read SKILL.md from disk directly.**
Do not use the framework's built-in skill loader if it requires skills to be "enabled" or listed in an active registry. The whole point is to keep 98% of skills disabled in the system prompt while still being able to load them on demand.
---
## 9. Lessons Learned
### 9.1 What Worked
-
**Nickname-first routing**
is the most impactful optimization. ~70% of skill matches come from the nickname map, which costs ~0.001ms. Vector search is the safety net, not the primary path.
-
**Definite article prefix ("the X")**
eliminated false positives. Users naturally refer to "the email" or "the game server" when they want a specific skill invoked.
-
**Direct file reading bypasses framework restrictions.**
Disabled skills are invisible to the agent's skill loader, but they're perfectly readable on disk. This is the key architectural insight.
-
**Multi-skill vector retrieval (top-3)**
handles compound queries like "check the game server and the email" — all matched skills above threshold are loaded inline, so the LLM sees both domains in a single turn.
-
**Lazy loading**
keeps cold-start costs zero. The embedding model (90MB) only loads when the first semantic match is needed.
### 9.2 What to Watch For
-
**Skill content size**
: Some SKILL.md files exceed 15,000 chars. We truncate at this limit to prevent token blowout in the user message.
-
**Index staleness**
: When new skills are added, the index must be rebuilt. A cron job handles this automatically.
-
**Thread safety**
: The plugin serves multiple concurrent sessions. All global state (model, index, injection guard) uses thread-safe locking.
-
**Threshold tuning**
: 0.44 was right for our skill corpus but may need adjustment for different domains.
### 9.3 What Could Be Improved
-
**Skill content caching**
: SKILL.md content is read from disk on every match. Adding an in-memory LRU cache would reduce latency.
-
**Cross-profile index sharing**
: If multiple Hermes profiles have different skill sets, a shared or merged index could reduce duplication.
-
**Online learning**
: The nickname map is hand-crafted. A feedback loop could automatically add recently-used skills as nickname triggers.
---
## 10. Conclusion
The Skill Routing Architecture demonstrates that LLM agents do not need to carry their full capability catalog in the system prompt. By combining aggressive trimming (~1% active), deterministic nickname routing (59 triggers), and semantic vector search (190-dim embeddings, 0.44 threshold), we reduced per-turn skill tokens by
**98.9%**
while preserving — and in some cases improving — the agent's ability to load domain-specific knowledge.
The system has been in production for 2+ weeks, processing ~5-10 skill-matched queries per day across multiple platforms, with zero regressions in passthrough query handling. The total implementation is
**~700 lines of code**
across 4 files, making it a low-cost, high-impact optimization applicable to any LLM agent framework with gateway-level interception hooks.
The key architectural insight — load disabled skill content directly from disk rather than through the framework's skill loader — solves a fundamental tension in agent system design between prompt efficiency and capability breadth.
---
## Appendix A: Example Nickname Map (Sanitized)
```
the digitization workflow → digitization-workflow
the data api → data-integration
the game server → game-ecosystem
the dungeon server → game-ecosystem
the dnd server → game-ecosystem
the dnd game → game-ecosystem
the github pr → github-pr-workflow
the pull request → github-pr-workflow
create a pr → github-pr-workflow
the code review → github-code-review
review the pr → github-code-review
the dns server → self-hosted-dns
the dashboard → dashboard-tunnel-proxy
the bitcoin dashboard → dashboard-tunnel-proxy
the auto-remediation → auto-remediation
the excel file → xlsx
the spreadsheet → xlsx
the powerpoint → powerpoint
the pdf file → pdf
the word document → docx
the hermes config → hermes-agent
the hermes setup → hermes-agent
the model config → hermes-model-strategy
the cost optimize → hermes-cost-optimization
the notes → obsidian
my notes → obsidian
the vault → obsidian
the memory search → hybrid-memory-search
the vector search → hybrid-memory-search
the email → email-automation
my email → email-automation
the expense → expense-monitoring
the budget → budget-tracking
```
**33 entries → 20 unique skills**
---
## Appendix B: Skills by Category (Example)
| Category | Count | Examples |
|----------|-------|---------|
| General | ~148 | apple-notes, findmy, image-generation, ... |
| Productivity | ~12 | linear, notion, obsidian, spotify, ... |
| Creative | ~7 | ascii-art, video-generation, p5js, ... |
| Infrastructure | ~4 | cloudflare-hosting, dns, system-admin, ... |
| Software Engineering | ~4 | clean-architecture, testing, ... |
| Research | ~3 | arxiv, geo-analysis, ... |
| DevOps | ~2 | search-engine, tunnel-proxy |
| Agent Meta | ~2 | hermes-agent, agent-fallback |
| Data Science | ~2 | fine-tuning, training |
| Other | ~6 | desktop, memory, note-taking, ... |
---
## Appendix C: Index Metadata
```json
{
"version": 2,
"model": "all-MiniLM-L6-v2",
"embed_dim": 384,
"entry_count": 190,
"default_threshold": 0.44
}
```
---
## Appendix D: Related Work
This architecture addresses a gap in LLM agent system design: the tension between
**prompt efficiency**
and
**capability breadth**
. Related approaches include:
-
**Mixture of Experts (MoE)**
: Routing tokens to specialized sub-networks at inference time — analogous at the model level to what we do at the prompt level
-
**Retrieval-Augmented Generation (RAG)**
: Injecting relevant documents into context on-demand — our approach is RAG for
*capabilities*
rather than
*knowledge*
-
**Tool-Use Agents**
(OpenAI Function Calling, Anthropic Tool Use): The model declares which tool to use, but the tool catalog is typically in the system prompt
Our contribution is a pre-LLM routing layer that makes the capability catalog effectively non-existent in the prompt while still being fully accessible.
No comments:
Post a Comment