hydra-nano 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -153
- package/package.json +15 -4
- package/skills/hydra/SKILL.md +13 -19
- package/skills/hydra/scripts/hooks/route-tests.mjs +45 -13
- package/skills/hydra/scripts/hooks/session-guide.mjs +21 -5
- package/skills/hydra/scripts/hydra.mjs +267 -23
- package/skills/hydra/scripts/install.mjs +20 -1
- package/skills/hydra/scripts/lib/claude_hooks.mjs +109 -5
- package/skills/hydra/scripts/lib/integrations.mjs +288 -0
- package/skills/hydra/scripts/lib/ledger.mjs +110 -7
- package/skills/hydra/scripts/lib/refactor.mjs +1122 -0
- package/skills/hydra/scripts/lib/test_logs.mjs +10 -6
- package/skills/hydra/scripts/mcp.mjs +179 -0
package/README.md
CHANGED
|
@@ -1,194 +1,137 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/rahul05ranjan/hydra/main/assets/hydra-banner.svg" alt="Hydra: small local models that take the noisy work off your coding agent" width="100%">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/hydra-nano"><img src="https://img.shields.io/npm/v/hydra-nano?color=7c5cff&label=npm" alt="npm version"></a>
|
|
7
|
+
<a href="https://huggingface.co/rahul05ranjan/hydra-nano-git"><img src="https://img.shields.io/badge/model-Hydra%20Nano%20v2-22d3ee" alt="Hydra Nano v2 on Hugging Face"></a>
|
|
8
|
+
<img src="https://img.shields.io/badge/runs-100%25%20local-5eead4" alt="Runs 100% local">
|
|
9
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A518-3c873a" alt="Node 18 or later">
|
|
10
|
+
<a href="https://github.com/rahul05ranjan/hydra/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
|
|
11
|
+
</p>
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
3. **read head** (`hydra-nano:read`): extracts symbol definitions (functions, classes, methods), line ranges, or structural definition outlines across TypeScript, JavaScript, Python, Rust, and Go without dumping whole multi-thousand-line files into context.
|
|
9
|
-
4. **test & logs head** (`hydra-nano:test`): runs test and compiler suites (`npm test`, `pytest`, `cargo test`, `tsc`), strips framework noise and `node_modules` stacks, and returns verbatim failure diffs and source lines with the command's exit code.
|
|
10
|
-
5. **os head** (`hydra-nano:os`): read-only system inspection (ports, processes, disk, system info) with strict secret-blocking guardrails.
|
|
13
|
+
<p align="center">
|
|
14
|
+
<b>Your coding agent reads every line of every test log, git diff and process list it runs.<br>Hydra reads them on your machine and hands back only the lines that matter.</b>
|
|
15
|
+
</p>
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
---
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
agent ── hydra ask --head git "<question>" ──────▶ git head model picks probes from a menu, code runs them
|
|
16
|
-
agent ── hydra ask --head files "<question>" ────▶ files head model picks search terms, code searches
|
|
17
|
-
agent ── hydra read <file> [symbol|--lines] ─────▶ read head pinpoints symbol/lines, extracts outline
|
|
18
|
-
agent ── hydra run -- <test/build-command> ──────▶ test head runs locally, digests failures & diffs
|
|
19
|
-
agent ◀── verbatim evidence lines ──────────────── model picks lines; the agent interprets them
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
- **Read-only and safe**: The model never writes an arbitrary command. It picks from fixed menus or digests command output.
|
|
23
|
-
- **Verbatim evidence**: Results are the command's own text lines, never a paraphrase.
|
|
24
|
-
- **Complete lists**: Git status, history, branches, remotes, stashes, tags and worktrees retain every returned record. Explicit commit counts override the model's count (maximum 50).
|
|
25
|
-
- **Pass-through**: Output under 800 characters is handed over whole with zero model calls.
|
|
26
|
-
- **Preserved exit codes**: `hydra run -- <cmd>` preserves `<cmd>`'s exit code, so agents know immediately if a build or test failed.
|
|
27
|
-
|
|
28
|
-
On Windows, OS inspection uses fixed read-only netstat, tasklist and PowerShell CIM commands, plus Node system/memory APIs. Process output is capped at 30 records and is not sorted by CPU usage. Failed probes are marked in the returned evidence. Code search ranks current source ahead of archived evaluation results while keeping those results searchable.
|
|
29
|
-
|
|
30
|
-
## Try it
|
|
19
|
+
## Why Hydra
|
|
31
20
|
|
|
32
|
-
|
|
21
|
+
Frontier coding agents pay for every token of tool output: a failing test suite, a long `git log`, a `ps` dump. Most of it is noise, and all of it fills the context window.
|
|
33
22
|
|
|
34
|
-
|
|
23
|
+
Hydra puts small specialist models on your own machine between the agent and that output:
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Start the server in one terminal:
|
|
41
|
-
|
|
42
|
-
```powershell
|
|
43
|
-
llama-server -m C:\models\hydra-nano-git.gguf --alias hydra-nano:git --host 127.0.0.1 --port 8080 -c 8192
|
|
44
|
-
```
|
|
25
|
+
- **Less context, same answer.** A `pnpm test` run that printed ~13,807 tokens reached the agent as ~57: the failing test, the assertion diff and the source line.
|
|
26
|
+
- **Nothing leaves your machine.** The model runs locally on llama.cpp. Hydra's telemetry stays in `~/.hydra/ledger.jsonl`.
|
|
27
|
+
- **Read-only by design.** The model never writes a shell command. It picks from fixed, read-only menus; code builds and runs the command.
|
|
28
|
+
- **Verbatim, not paraphrased.** Hydra returns the command's own lines, so the agent sees evidence, not a summary.
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```powershell
|
|
49
|
-
$env:HYDRA_BACKEND = 'llamacpp'
|
|
50
|
-
$env:HYDRA_LLAMA_URL = 'http://127.0.0.1:8080'
|
|
51
|
-
$env:HYDRA_MODEL = 'hydra-nano:git'
|
|
52
|
-
node skills/hydra/scripts/hydra.mjs doctor
|
|
53
|
-
node skills/hydra/scripts/hydra.mjs ask --head git "which branch am I on?"
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
On macOS/Linux, set the same variables with `export HYDRA_BACKEND=llamacpp`, `export HYDRA_LLAMA_URL=http://127.0.0.1:8080` and `export HYDRA_MODEL=hydra-nano:git`.
|
|
57
|
-
|
|
58
|
-
The URL is the server root, without `/v1`. `HYDRA_MODEL` must match the server alias; setting it sends all model-backed heads to that one model and does not create specialist weights. Without this override, Hydra requests its existing per-head model names; your server must serve those aliases. `hydra doctor` verifies the effective configured names. `hydra setup` with this backend prints instructions without installing or starting anything.
|
|
59
|
-
|
|
60
|
-
Hydra uses llama.cpp's [schema-constrained chat API](https://github.com/ggml-org/llama.cpp/tree/master/tools/server#post-v1chatcompletions-openai-compatible-chat-completions-api), disables thinking, and limits replies to 512 tokens. The model still chooses fixed read-only probes. HTTP fixture tests and native Windows Q8 inference/bootstrap checks pass; sealed accuracy on the converted runtime is tracked separately.
|
|
61
|
-
|
|
62
|
-
### Run with Ollama
|
|
63
|
-
|
|
64
|
-
Set `HYDRA_BACKEND=ollama` first (`$env:HYDRA_BACKEND = 'ollama'` in PowerShell; `export HYDRA_BACKEND=ollama` in Bash).
|
|
30
|
+
## Quick start
|
|
65
31
|
|
|
66
32
|
```bash
|
|
67
|
-
|
|
68
|
-
node skills/hydra/scripts/hydra.mjs setup
|
|
69
|
-
|
|
70
|
-
# 2. Ask questions about any repo
|
|
71
|
-
cd <any git repository>
|
|
72
|
-
node <path>/skills/hydra/scripts/hydra.mjs ask "who changed package.json most recently and why?"
|
|
73
|
-
|
|
74
|
-
# 3. Slice files, symbols, or show structural outlines
|
|
75
|
-
node <path>/skills/hydra/scripts/hydra.mjs read src/index.ts handleRequest
|
|
76
|
-
node <path>/skills/hydra/scripts/hydra.mjs read src/server.ts --lines 20-50
|
|
77
|
-
node <path>/skills/hydra/scripts/hydra.mjs read src/config.py --outline
|
|
78
|
-
|
|
79
|
-
# 4. Run test and build commands through hydra
|
|
80
|
-
node <path>/skills/hydra/scripts/hydra.mjs run -- npm test
|
|
81
|
-
node <path>/skills/hydra/scripts/hydra.mjs run -- pytest
|
|
82
|
-
|
|
83
|
-
# 5. View token savings
|
|
84
|
-
node <path>/skills/hydra/scripts/hydra.mjs stats
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Install as a skill
|
|
88
|
-
|
|
89
|
-
Everything an agent needs is inside `skills/hydra`:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npx skills add rahul05ranjan/hydra --skill hydra
|
|
33
|
+
npx hydra-nano
|
|
93
34
|
```
|
|
94
35
|
|
|
95
|
-
|
|
36
|
+
One command installs everything: a pinned llama.cpp runtime, the ~812 MB Hydra Nano model (SHA-256 checked), the Hydra skill, and the integration for each coding tool it finds.
|
|
96
37
|
|
|
97
|
-
|
|
38
|
+
Want the `hydra` command in your own terminal too?
|
|
98
39
|
|
|
99
40
|
```bash
|
|
100
|
-
|
|
41
|
+
npm install -g hydra-nano
|
|
42
|
+
hydra doctor
|
|
101
43
|
```
|
|
102
44
|
|
|
103
|
-
|
|
45
|
+
Requires Node 18+. Runtime packages for macOS, Linux and Windows on x64 and arm64; verified live on macOS and Windows. Prefer GitHub? `npx github:rahul05ranjan/hydra` installs the same thing.
|
|
104
46
|
|
|
105
|
-
|
|
47
|
+
## Works with your coding tools
|
|
106
48
|
|
|
107
|
-
|
|
49
|
+
| Tool | How Hydra joins | Status |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| **Claude Code** | Skill + hooks that route test/build runs and git questions | Tested |
|
|
52
|
+
| **Codex** | Skill + MCP server + `PreToolUse` hook | MCP listed by Codex; trust the hook with `/hooks` |
|
|
53
|
+
| **OpenCode** | MCP server + plugin | MCP connects |
|
|
54
|
+
| **Cursor** | MCP server + `beforeShellExecution` hook | Preview |
|
|
55
|
+
| **Gemini CLI** | MCP server + `BeforeTool` hook | Preview |
|
|
56
|
+
| **Antigravity** | Skill + MCP server | Preview |
|
|
108
57
|
|
|
109
|
-
|
|
58
|
+
Any other tool that speaks MCP can use Hydra too: point it at `hydra mcp` (stdio).
|
|
110
59
|
|
|
111
|
-
|
|
60
|
+
Hydra never overwrites your settings. Every file it edits is backed up once as `<file>.before-hydra`, only Hydra's own entries change, and `hydra agents remove` takes them out again.
|
|
112
61
|
|
|
113
|
-
|
|
114
|
-
- Claude Code: `~/.claude/skills/hydra`
|
|
115
|
-
- Antigravity: `~/.gemini/config/skills/hydra`
|
|
62
|
+
## What it does
|
|
116
63
|
|
|
117
|
-
|
|
64
|
+
| Head | Ask it | It returns |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| **git** | "what changed in the last commit?", "who last touched `billing.js`?" | The matching commits, diff hunks or blame lines |
|
|
67
|
+
| **test** | `hydra run -- npm test` (pytest, cargo, go, tsc, gradle, ...) | Failing test names, assertion diffs and source locations, with the original exit code |
|
|
68
|
+
| **os** | "what is listening on port 3000?" | The matching ports, processes or disk lines, with secrets blocked |
|
|
69
|
+
| **read** | `hydra read src/server.ts handleRequest` | One symbol, a line range or an outline |
|
|
70
|
+
| **files** | `hydra search parseConfig` | Definition-ranked matches |
|
|
118
71
|
|
|
119
|
-
|
|
72
|
+
Through MCP, Hydra offers the three where it pays most: `hydra_git`, `hydra_run` and `hydra_os`.
|
|
120
73
|
|
|
121
|
-
|
|
74
|
+
## Benchmarks
|
|
122
75
|
|
|
123
|
-
|
|
76
|
+
**Hydra Nano v2**: a full-parameter fine-tune of a 0.8B model, one set of weights for every head, run as a Q8_0 GGUF.
|
|
124
77
|
|
|
125
|
-
|
|
78
|
+
| Set | Tasks | Solved |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Git (sealed test set, never used for training) | 1,000 | **96.3%** |
|
|
81
|
+
| Files (held out) | 1,000 | **98.0%** |
|
|
82
|
+
| Read (held out) | 1,000 | **96.1%** |
|
|
83
|
+
| Test logs (second held-out set) | 1,000 | **97.5%** |
|
|
84
|
+
| OS (held out, synthetic probe outputs) | 1,000 | **100%** |
|
|
85
|
+
| Test-log benchmark across 8 frameworks | 20 | **19/20**, 47% fewer tokens |
|
|
126
86
|
|
|
127
|
-
|
|
87
|
+
Receipts: [model card](https://huggingface.co/rahul05ranjan/hydra-nano-git) and [`evals/results`](https://github.com/rahul05ranjan/hydra/tree/main/evals/results).
|
|
128
88
|
|
|
129
|
-
|
|
89
|
+
<!-- usage-stats:begin (written by evals/usage/readme_stats.mjs) -->
|
|
90
|
+
**In real use.** Since 2026-10-17, Hydra has handled **118 calls** in **9 coding sessions** across **3 projects** on the maintainer's machine. Of **~375,638 tokens** of command output, **~18,781** reached the agent: **95% kept out of context**.
|
|
130
91
|
|
|
131
|
-
|
|
92
|
+
| Work | Calls | Output read locally | Reached the agent | Kept out |
|
|
93
|
+
|---|---|---|---|---|
|
|
94
|
+
| Test and build runs | 112 | ~374,873 | ~18,199 | **95%** |
|
|
95
|
+
| File slices | 1 | ~508 | ~283 | **44%** |
|
|
96
|
+
| Git questions | 5 | ~257 | ~299 | **-16%** |
|
|
132
97
|
|
|
133
|
-
|
|
98
|
+
<sub>From Hydra's local ledger; tokens are estimates (characters / 4). Updated 2026-10-20.</sub>
|
|
99
|
+
<!-- usage-stats:end -->
|
|
134
100
|
|
|
135
|
-
|
|
101
|
+
**Where Hydra does not help, measured.** In a controlled trial of 36 Claude Code sessions extracting functions from real source code, forcing that work through Hydra used **72% more tokens** than the agent's own tools. So Hydra leaves source reading and search to the agent, and routes only the noisy work: test and build logs, git history, system inspection. Full method and numbers in [evaluations](https://github.com/rahul05ranjan/hydra/blob/main/docs/evaluations.md).
|
|
136
102
|
|
|
137
|
-
|
|
103
|
+
## Commands
|
|
138
104
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
Benchmarks failure extraction and noise reduction across Vitest, Jest, Pytest, Cargo, TSC, Go, node:test, and Mocha.
|
|
154
|
-
|
|
155
|
-
- **Solved**: **100% (20/20)**
|
|
156
|
-
- **Test Name Recall**: **100%**
|
|
157
|
-
- **File / Line Location Recall**: **100%**
|
|
158
|
-
- **Assertion Diff Recall**: **100%**
|
|
159
|
-
- **Cleanliness**: **100%** (zero framework or `node_modules` stack frame pollution)
|
|
160
|
-
- **Token Savings**: **49.6% net token reduction** overall, and **96.4% to 96.7%** on verbose test suites.
|
|
161
|
-
- **Runtime**: **3.2s** across all 20 tasks.
|
|
105
|
+
```bash
|
|
106
|
+
hydra ask "which branch am I on and what changed?" # git, files or os, routed by the question
|
|
107
|
+
hydra run -- pytest -q # a test or build run, digested
|
|
108
|
+
hydra os "what is using port 8080?" # read-only system inspection
|
|
109
|
+
hydra read src/app.py create_app # one symbol, a line range or an outline
|
|
110
|
+
hydra smell src/ # detect Refactoring.Guru code smells (or --diff / --staged)
|
|
111
|
+
hydra refactor src/app.py process_order # actionable step-by-step refactoring recipe
|
|
112
|
+
hydra design "need flexible algorithms at runtime" # GoF design pattern advisor & architecture guide
|
|
113
|
+
hydra stats # tokens kept out of context
|
|
114
|
+
hydra improve --since 2026-10-17 # what the local telemetry says to improve
|
|
115
|
+
hydra agents status # Hydra in each coding tool
|
|
116
|
+
hydra doctor # is the local model ready?
|
|
117
|
+
```
|
|
162
118
|
|
|
163
|
-
|
|
119
|
+
Need the raw log for one run? Prefix it with `HYDRA_RAW=1` and the hook lets it through.
|
|
164
120
|
|
|
165
|
-
|
|
121
|
+
## Privacy and control
|
|
166
122
|
|
|
167
|
-
|
|
123
|
+
- **Local only.** The model, the runtime and the telemetry live in `~/.hydra`. Nothing is sent anywhere.
|
|
124
|
+
- **Turn telemetry off** with `HYDRA_TELEMETRY=0`.
|
|
125
|
+
- **Skip parts of the install** with `--no-agents` (no other tools), `--no-hooks` (no hooks) or `--runtime-only` (no skill).
|
|
126
|
+
- **Uninstall cleanly.** `hydra agents remove` and `hydra hooks remove` undo every integration and restore your settings; `hydra stop` stops the local server; deleting `~/.hydra` removes the runtime, the model and the telemetry.
|
|
168
127
|
|
|
169
|
-
|
|
170
|
-
- **Target Line Recall**: **100%**
|
|
171
|
-
- **Cleanliness**: **100%** (zero unrelated function/code leak)
|
|
172
|
-
- **Token Savings**: **48.1% net token reduction** overall, and **77% to 92%** on targeted line and symbol slices.
|
|
173
|
-
- **Runtime**: **0.01s** (instantaneous local extraction).
|
|
128
|
+
## Learn more
|
|
174
129
|
|
|
175
|
-
|
|
130
|
+
- [How Hydra works](https://github.com/rahul05ranjan/hydra/blob/main/docs/how-it-works.md): heads, backends (llama.cpp or Ollama), telemetry, every install path and the code layout.
|
|
131
|
+
- [Evaluations and trials](https://github.com/rahul05ranjan/hydra/blob/main/docs/evaluations.md): how each number above was measured.
|
|
132
|
+
- [What real use teaches](https://github.com/rahul05ranjan/hydra/blob/main/IMPROVEMENTS.md): the open and fixed findings from Hydra's own telemetry.
|
|
133
|
+
- [Hydra Nano on Hugging Face](https://huggingface.co/rahul05ranjan/hydra-nano-git).
|
|
176
134
|
|
|
177
|
-
##
|
|
135
|
+
## License
|
|
178
136
|
|
|
179
|
-
|
|
180
|
-
- `skills/hydra/scripts/hydra.mjs`: the CLI.
|
|
181
|
-
- `skills/hydra/scripts/lib/`:
|
|
182
|
-
- `runtime.mjs`: selectable Ollama/llama.cpp API client and per-head model configuration.
|
|
183
|
-
- `route.mjs`: route questions between heads.
|
|
184
|
-
- `git.mjs`: git head probes and plan step.
|
|
185
|
-
- `files.mjs`: search and walk head.
|
|
186
|
-
- `read.mjs`: file slice and symbol reader head.
|
|
187
|
-
- `test_logs.mjs`: test runner and build log reader head.
|
|
188
|
-
- `answer.mjs`: verbatim line selection and lead generation.
|
|
189
|
-
- `ollama.mjs`: compatibility exports for existing evaluation callers.
|
|
190
|
-
- `ledger.mjs`: local token accounting ledger.
|
|
191
|
-
- `test/`: unit test suite (`npm test`).
|
|
192
|
-
- `evals/git1/`: 1000-task sealed test set for git head.
|
|
193
|
-
- `evals/test_logs/`: 20-task cross-language benchmark for test and build logs.
|
|
194
|
-
- `evals/read/`: 20-task cross-language benchmark for file slice reading.
|
|
137
|
+
MIT. See [LICENSE](https://github.com/rahul05ranjan/hydra/blob/main/LICENSE).
|
package/package.json
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hydra-nano",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Small local models that
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Small local models that take the noisy work off your coding agent: git history, test and build digests and OS inspection run on your machine, and only the lines that matter reach Claude Code, Codex, Cursor, OpenCode, Gemini CLI or Antigravity. Skill, MCP server and hooks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
7
7
|
"codex",
|
|
8
|
+
"cursor",
|
|
9
|
+
"opencode",
|
|
10
|
+
"gemini-cli",
|
|
11
|
+
"antigravity",
|
|
12
|
+
"mcp",
|
|
13
|
+
"mcp-server",
|
|
8
14
|
"agent-skill",
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"coding-agent",
|
|
9
17
|
"local-llm",
|
|
10
18
|
"llama.cpp",
|
|
19
|
+
"token-saving",
|
|
20
|
+
"context-window",
|
|
11
21
|
"git",
|
|
12
22
|
"test-runner",
|
|
13
|
-
"
|
|
23
|
+
"developer-tools"
|
|
14
24
|
],
|
|
15
25
|
"license": "MIT",
|
|
16
26
|
"author": "rahul05ranjan",
|
|
@@ -42,7 +52,8 @@
|
|
|
42
52
|
"eval:frontier": "node evals/trial/frontier_trial.mjs --run",
|
|
43
53
|
"eval:real:prepare": "node evals/trial/real_repo_trial.mjs",
|
|
44
54
|
"eval:real": "node evals/trial/real_repo_trial.mjs --run",
|
|
45
|
-
"dashboard": "node dashboard/server.mjs"
|
|
55
|
+
"dashboard": "node dashboard/server.mjs",
|
|
56
|
+
"stats:readme": "node evals/usage/readme_stats.mjs"
|
|
46
57
|
},
|
|
47
58
|
"engines": {
|
|
48
59
|
"node": ">=18"
|
package/skills/hydra/SKILL.md
CHANGED
|
@@ -1,41 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hydra
|
|
3
|
-
description:
|
|
3
|
+
description: Run test and build commands, git history/diff/blame questions, and machine inspections (ports, processes, disk) through hydra, a local model that returns only the lines that matter. Use before running npm test, pytest, cargo test, tsc or a build, before reading git log, diff, show or blame output, and before ps, lsof or df dumps.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Hydra
|
|
7
7
|
|
|
8
|
-
`hydra` runs read-only
|
|
8
|
+
`hydra` runs a noisy read-only command on this machine and prints only the lines that answer the question; the raw output stays out of your context. It pays off where output is long and mostly noise: test and build logs, git history and diffs, process and port listings.
|
|
9
9
|
|
|
10
10
|
## Call it
|
|
11
11
|
|
|
12
|
-
From the repository the question is about
|
|
12
|
+
From the repository the question is about:
|
|
13
13
|
|
|
14
14
|
```
|
|
15
|
+
node scripts/hydra.mjs run -- <test or build command...>
|
|
15
16
|
node scripts/hydra.mjs ask --head git "<question>"
|
|
16
|
-
node scripts/hydra.mjs ask --head files "<question>"
|
|
17
|
-
node scripts/hydra.mjs ask --head read "<question>"
|
|
18
|
-
node scripts/hydra.mjs ask --head test "<question>"
|
|
19
|
-
node scripts/hydra.mjs ask --head os "<question>"
|
|
20
|
-
node scripts/hydra.mjs search <term...>
|
|
21
|
-
node scripts/hydra.mjs read <file> [symbol|--lines <start-end>|--outline]
|
|
22
|
-
node scripts/hydra.mjs run -- <command...>
|
|
23
17
|
node scripts/hydra.mjs os [question...]
|
|
24
18
|
```
|
|
25
19
|
|
|
26
|
-
`scripts/` is in this skill's directory.
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
20
|
+
`scripts/` is in this skill's directory.
|
|
21
|
+
|
|
22
|
+
- **Tests and builds:** `run --` executes the command and returns the failing tests, assertion diffs and source locations with the exit code, or a short pass summary. A run you already cut to a few lines yourself (`| tail -n 20`) gains nothing from Hydra.
|
|
23
|
+
- **Git:** ask one full question per call and name the file, branch, commit or author when you know it; the model may only use a path, revision or name that appears in your question. A short check such as `git status --short` is cheaper to run yourself.
|
|
24
|
+
- **Machine:** ports, processes, disk, memory, system info and environment variable names, with secrets withheld.
|
|
25
|
+
|
|
26
|
+
Read and search source files with your own tools: a measured trial found routing that work through Hydra cost 72% more tokens. Hydra also has `search`, `read`, `smell`, `refactor` and `design` commands (`node scripts/hydra.mjs` with no arguments lists them) for when the user asks for them.
|
|
31
27
|
|
|
32
28
|
## What it answers
|
|
33
29
|
|
|
30
|
+
- **test**: test and build output (`npm test`, `pytest`, `cargo test`, `go test`, `tsc` and others). On failure, the failing test name, assertion diff and the user's own file:line, with node_modules and framework frames dropped.
|
|
34
31
|
- **git**: current branch and sync state, uncommitted and staged changes, commit history, what this branch adds over a base branch, one commit's patch, blame, branches, worktrees, remotes, stashes, tags.
|
|
35
|
-
- **
|
|
36
|
-
- **read**: extracts symbol definitions (functions, classes, methods), line ranges (`--lines 10-50`), or structural definition outlines across TypeScript, JavaScript, Python, Rust, and Go without dumping whole files into context.
|
|
37
|
-
- **test**: runs and parses test and build outputs (`npm test`, `pytest`, `cargo test`, `tsc`). If tests fail, extracts the failing test name, assertion diff, and exact user file:line location, stripping node_modules and framework traces.
|
|
38
|
-
- **os**: inspects listening ports (`lsof`), running processes / CPU consumers (`ps`), disk space (`df -h`), and system info (`uptime`, `uname`) while strictly guarding against printing secrets.
|
|
32
|
+
- **os**: listening ports, running processes and CPU consumers, disk space, memory, system info, environment variable names, never their values.
|
|
39
33
|
|
|
40
34
|
Changes to the repository, and questions that need reasoning about what code does, stay with you.
|
|
41
35
|
|
|
@@ -1,22 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// keeps failing test names, assertion diffs and source locations and drops the rest
|
|
4
|
-
//
|
|
2
|
+
// Shell-command hook: a test or build run goes through `hydra run --` (or the hydra_run MCP tool),
|
|
3
|
+
// whose digest keeps failing test names, assertion diffs and source locations and drops the rest.
|
|
4
|
+
// A run already cut to a few lines by its own pipeline (| tail -n 15, | grep -c) passes: Hydra would
|
|
5
|
+
// save little and a retry costs more. Prefix a command with HYDRA_RAW=1 when the raw log is really needed.
|
|
6
|
+
// --format picks the tool's hook protocol:
|
|
7
|
+
// claude, codex PreToolUse; command at tool_input.command; deny via hookSpecificOutput.
|
|
8
|
+
// gemini BeforeTool on run_shell_command; deny via {"decision": "deny", "reason"}.
|
|
9
|
+
// cursor beforeShellExecution; command at command; must always answer with a permission.
|
|
10
|
+
// Each decision goes to the local ledger with the hook's own time, for `hydra improve`; a command
|
|
11
|
+
// that simply passes is recorded without its text.
|
|
5
12
|
import path from 'node:path';
|
|
6
13
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { testRun } from '../lib/claude_hooks.mjs';
|
|
14
|
+
import { rawBypass, testRun, trimmedRun } from '../lib/claude_hooks.mjs';
|
|
15
|
+
import { record } from '../lib/ledger.mjs';
|
|
8
16
|
|
|
9
17
|
const hydra = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'hydra.mjs');
|
|
18
|
+
const flag = process.argv.indexOf('--format');
|
|
19
|
+
const format = flag >= 0 ? process.argv[flag + 1] : 'claude';
|
|
20
|
+
|
|
21
|
+
const answers = {
|
|
22
|
+
claude: { pass: null, deny: reason => ({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } }) },
|
|
23
|
+
gemini: { pass: { decision: 'allow' }, deny: reason => ({ decision: 'deny', reason }) },
|
|
24
|
+
cursor: { pass: { permission: 'allow' }, deny: reason => ({ permission: 'deny', agent_message: reason,
|
|
25
|
+
user_message: 'Hydra sent this test/build run through hydra run to keep the full log out of context.' }) },
|
|
26
|
+
};
|
|
27
|
+
answers.codex = answers.claude;
|
|
28
|
+
const answer = answers[format] ?? answers.claude;
|
|
29
|
+
|
|
10
30
|
let input = '';
|
|
11
31
|
process.stdin.on('data', chunk => { input += chunk; }).on('end', () => {
|
|
12
|
-
let
|
|
13
|
-
try {
|
|
32
|
+
let parsed;
|
|
33
|
+
try { parsed = JSON.parse(input) ?? {}; } catch {
|
|
34
|
+
if (answer.pass) process.stdout.write(JSON.stringify(answer.pass));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const command = String((format === 'cursor' ? parsed.command : parsed.tool_input?.command) ?? '');
|
|
38
|
+
const session = parsed.session_id ?? parsed.conversation_id;
|
|
39
|
+
const event = (decision, withCommand = true) => ({ ts: new Date().toISOString(), kind: 'hook', hook: 'route-tests',
|
|
40
|
+
...(format === 'claude' ? {} : { agent: format }), decision, ...(withCommand ? { command: command.slice(0, 300) } : {}),
|
|
41
|
+
...(session ? { session } : {}), hookMs: Math.round(process.uptime() * 1000) });
|
|
14
42
|
const run = testRun(command);
|
|
15
|
-
if (!run)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
43
|
+
if (!run) {
|
|
44
|
+
record(rawBypass(command) ? event('raw') : trimmedRun(command) ? event('trimmed') : event('pass', false));
|
|
45
|
+
if (answer.pass) process.stdout.write(JSON.stringify(answer.pass));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
record({ ...event('deny'), run });
|
|
49
|
+
process.stdout.write(JSON.stringify(answer.deny(`Test/build runs go through Hydra so the full log stays out of context. Run it as:\n` +
|
|
50
|
+
` node "${hydra}" run -- ${run}\n${format === 'claude' ? '' : 'or call the hydra_run tool with that command. '}` +
|
|
51
|
+
`(Keep any cd or env prefix before it.) Hydra returns the failing tests, assertion diffs and source locations ` +
|
|
52
|
+
`verbatim, or a short pass summary. A run you cut to a few lines yourself (| tail -n 40 or less, or | grep ... | head -40) also passes. ` +
|
|
53
|
+
`If you truly need the raw log, prefix the original command with HYDRA_RAW=1.`)));
|
|
22
54
|
});
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// Session-start hook: tells the agent where Hydra pays off, so it uses it without being asked.
|
|
3
|
+
// --format claude or codex answers with hookSpecificOutput; cursor with additional_context.
|
|
4
|
+
// The session start goes to the local ledger, so `hydra improve` can tell how many sessions used Hydra.
|
|
3
5
|
import path from 'node:path';
|
|
4
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { record } from '../lib/ledger.mjs';
|
|
5
8
|
|
|
6
9
|
const hydra = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'hydra.mjs');
|
|
7
|
-
process.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
const flag = process.argv.indexOf('--format');
|
|
11
|
+
const format = flag >= 0 ? process.argv[flag + 1] : 'claude';
|
|
12
|
+
const mcp = format === 'claude' ? '' : ' (or the hydra_git / hydra_run MCP tools)';
|
|
13
|
+
const guide = `Hydra is installed: it runs noisy read-only commands on a small local model and returns only the lines that matter.\n` +
|
|
14
|
+
`- For git history, diff, blame or "what changed" questions, first run: node "${hydra}" ask --head git "<question>"${mcp} ` +
|
|
10
15
|
`from the repository, instead of reading git log, git diff or git show output yourself. Use plain git for writes ` +
|
|
11
16
|
`and for short checks such as git status --short.\n` +
|
|
12
17
|
`- A hook sends test and build runs through: node "${hydra}" run -- <command>\n` +
|
|
13
|
-
`- Keep using
|
|
18
|
+
`- Keep using your own file reading and search for source files; Hydra does not save tokens there.`;
|
|
19
|
+
|
|
20
|
+
let input = '';
|
|
21
|
+
process.stdin.on('data', chunk => { input += chunk; }).on('end', () => {
|
|
22
|
+
let start = {};
|
|
23
|
+
try { start = JSON.parse(input) ?? {}; } catch { /* The tool always sends JSON; record what there is. */ }
|
|
24
|
+
const session = start.session_id ?? start.conversation_id;
|
|
25
|
+
record({ ts: new Date().toISOString(), kind: 'session', ...(format === 'claude' ? {} : { agent: format }),
|
|
26
|
+
...(session ? { session } : {}), ...(start.source ? { source: start.source } : {}) });
|
|
27
|
+
process.stdout.write(JSON.stringify(format === 'cursor' ? { additional_context: guide }
|
|
28
|
+
: { hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: guide } }));
|
|
29
|
+
});
|