hawkeye-ai 0.1.2 → 0.1.3
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 +682 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<pre align="center">
|
|
3
|
+
██╗ ██╗
|
|
4
|
+
██║ ██║
|
|
5
|
+
███████║ <b>Hawkeye</b>
|
|
6
|
+
██╔══██║ The flight recorder for AI agents
|
|
7
|
+
██║ ██║
|
|
8
|
+
╚═╝ ╚═╝
|
|
9
|
+
</pre>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<strong>Open-source observability & security for AI agents</strong><br/>
|
|
14
|
+
<em>Claude Code · Aider · AutoGPT · CrewAI · Open Interpreter · any LLM-powered agent</em>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="#installation">Install</a> •
|
|
19
|
+
<a href="#quick-start">Quick Start</a> •
|
|
20
|
+
<a href="#features">Features</a> •
|
|
21
|
+
<a href="#cli-commands">CLI</a> •
|
|
22
|
+
<a href="#dashboard">Dashboard</a> •
|
|
23
|
+
<a href="#driftdetect">DriftDetect</a> •
|
|
24
|
+
<a href="#guardrails">Guardrails</a> •
|
|
25
|
+
<a href="#security">Security</a> •
|
|
26
|
+
<a href="#architecture">Architecture</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## What is Hawkeye?
|
|
32
|
+
|
|
33
|
+
Hawkeye is a **flight recorder** for AI agents. It captures every action an agent performs — terminal commands, file operations, LLM calls, API requests — and provides:
|
|
34
|
+
|
|
35
|
+
- **Session recording & replay** — Full timeline of every agent action with costs and metadata
|
|
36
|
+
- **DriftDetect** — Real-time objective drift detection using heuristic + LLM scoring
|
|
37
|
+
- **Guardrails** — File protection, command blocking, cost limits, token limits, directory scoping
|
|
38
|
+
- **Visual dashboard** — Mobile-responsive web UI with session explorer, drift charts, and settings management
|
|
39
|
+
- **Remote tasks** — Submit prompts from your phone via dashboard, with image attachments, auto-approve, and persistent agent memory
|
|
40
|
+
- **Interactive TUI** — Terminal-responsive CLI with arrow-key navigation and slash commands
|
|
41
|
+
- **OpenTelemetry export** — Push traces to Grafana Tempo, Jaeger, Datadog, Honeycomb
|
|
42
|
+
- **Universal ingestion API** — Accept events from any source (MCP servers, custom tools)
|
|
43
|
+
- **Multi-agent support** — Claude Code (hooks), Aider, Open Interpreter, AutoGPT, CrewAI, or any custom command
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
### npm (recommended)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install -g @mklamine/hawkeye-cli
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### npx (no install)
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx @mklamine/hawkeye-cli
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Homebrew (macOS/Linux)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
brew tap mklamine/hawkeye
|
|
63
|
+
brew install hawkeye
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### From source
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/lamine/hawkeye.git
|
|
70
|
+
cd hawkeye
|
|
71
|
+
pnpm install && pnpm build
|
|
72
|
+
cd packages/cli && npm link
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Initialize in your project
|
|
79
|
+
hawkeye init
|
|
80
|
+
|
|
81
|
+
# Record an agent session
|
|
82
|
+
hawkeye record -o "Build a REST API" -- claude chat
|
|
83
|
+
|
|
84
|
+
# Or launch the interactive TUI
|
|
85
|
+
hawkeye
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Features
|
|
89
|
+
|
|
90
|
+
### Session Recording
|
|
91
|
+
|
|
92
|
+
Wrap any LLM-powered agent with `hawkeye record` to capture everything:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
hawkeye record -o "Refactor auth module" -- claude chat
|
|
96
|
+
hawkeye record -o "Fix bug #42" --agent cursor -- cursor .
|
|
97
|
+
hawkeye record -o "Deploy to staging" --no-drift -- node deploy.js
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Hawkeye automatically detects the agent (Claude Code, Aider, AutoGPT, CrewAI, Open Interpreter) and intercepts:
|
|
101
|
+
|
|
102
|
+
| Interceptor | What it captures |
|
|
103
|
+
| -------------- | ------------------------------------------------------ |
|
|
104
|
+
| **Terminal** | Commands executed, exit codes, stdout/stderr |
|
|
105
|
+
| **Filesystem** | File reads, writes, deletes, renames |
|
|
106
|
+
| **Network** | HTTP requests, LLM API calls with token counts & costs |
|
|
107
|
+
|
|
108
|
+
### Claude Code Hooks
|
|
109
|
+
|
|
110
|
+
For agents with bundled Node.js runtimes (where `NODE_OPTIONS` injection doesn't work), Hawkeye integrates via **Claude Code hooks**:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
hawkeye hooks install # Install PreToolUse + PostToolUse hooks
|
|
114
|
+
hawkeye hooks install --guardrails-only # Only install guardrail enforcement
|
|
115
|
+
hawkeye hooks status # Check installation
|
|
116
|
+
hawkeye hooks uninstall # Remove hooks
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Hooks provide:
|
|
120
|
+
|
|
121
|
+
- **PreToolUse** — Guardrails enforcement (exit code 2 blocks the action)
|
|
122
|
+
- **PostToolUse** — Event recording to SQLite
|
|
123
|
+
- **Stop** — Drift score update (fires after every response, does not end session)
|
|
124
|
+
- Sessions auto-created per `session_id`
|
|
125
|
+
|
|
126
|
+
### Interactive TUI
|
|
127
|
+
|
|
128
|
+
Launch the interactive mode by running `hawkeye` with no subcommand:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
██╗ ██╗
|
|
132
|
+
██║ ██║
|
|
133
|
+
███████║ Hawkeye v0.1.0
|
|
134
|
+
██╔══██║ The flight recorder for AI agents
|
|
135
|
+
██║ ██║ /Users/you/project
|
|
136
|
+
╚═╝ ╚═╝
|
|
137
|
+
|
|
138
|
+
● Recording: "Build REST API" (5m 23s)
|
|
139
|
+
|
|
140
|
+
› /
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Type `/` to open the command picker with arrow-key navigation and live filtering:
|
|
144
|
+
|
|
145
|
+
| Command | Description |
|
|
146
|
+
| -------------- | ---------------------------------------------- |
|
|
147
|
+
| `/new` | New session — pick agent, model, objective |
|
|
148
|
+
| `/sessions` | List & manage recorded sessions |
|
|
149
|
+
| `/active` | Show current recording |
|
|
150
|
+
| `/stats` | Session statistics |
|
|
151
|
+
| `/end` | End active sessions |
|
|
152
|
+
| `/restart` | Restart a session (with picker) |
|
|
153
|
+
| `/delete` | Delete a session |
|
|
154
|
+
| `/tasks` | List, create, clear remote tasks |
|
|
155
|
+
| `/tasks journal` | View agent memory (task history) |
|
|
156
|
+
| `/remote` | Launch serve + daemon + Cloudflare tunnel |
|
|
157
|
+
| `/remote stop` | Stop tunnel + daemon |
|
|
158
|
+
| `/settings` | Configure DriftDetect, Guardrails, API keys |
|
|
159
|
+
| `/serve` | Open the web dashboard |
|
|
160
|
+
| `/mcp` | Show MCP server setup instructions |
|
|
161
|
+
| `/revert` | Revert file changes from a session |
|
|
162
|
+
| `/init` | Initialize Hawkeye |
|
|
163
|
+
| `/clear` | Clear screen |
|
|
164
|
+
| `/quit` | Exit |
|
|
165
|
+
|
|
166
|
+
## CLI Commands
|
|
167
|
+
|
|
168
|
+
### `hawkeye init`
|
|
169
|
+
|
|
170
|
+
Initialize Hawkeye in the current directory. Creates `.hawkeye/` directory and config files.
|
|
171
|
+
|
|
172
|
+
### `hawkeye record`
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
hawkeye record -o <objective> [options] -- <command...>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
| Option | Description |
|
|
179
|
+
| ----------------- | --------------------------------------- |
|
|
180
|
+
| `-o, --objective` | Session objective **(required)** |
|
|
181
|
+
| `-a, --agent` | Agent name (auto-detected from command) |
|
|
182
|
+
| `-m, --model` | Model name |
|
|
183
|
+
| `--no-drift` | Disable DriftDetect |
|
|
184
|
+
| `--no-guardrails` | Disable guardrails |
|
|
185
|
+
|
|
186
|
+
### `hawkeye sessions`
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
hawkeye sessions [-n 10] [-s recording|completed|aborted]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `hawkeye stats <session-id>`
|
|
193
|
+
|
|
194
|
+
Display statistics for a session (accepts ID prefix).
|
|
195
|
+
|
|
196
|
+
### `hawkeye replay <session-id>`
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
hawkeye replay <session-id> [--speed 2] [--no-delay]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Replay a session action-by-action with timing.
|
|
203
|
+
|
|
204
|
+
### `hawkeye serve`
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
hawkeye serve [-p 4242]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Launch the web dashboard on `http://localhost:4242`. Auto-reloads after `pnpm build` — watches `dist/` and restarts the server when compiled files change.
|
|
211
|
+
|
|
212
|
+
### `hawkeye daemon`
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
hawkeye daemon [--agent claude] [--interval 30]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Run the task daemon — polls `.hawkeye/tasks.json` for pending tasks and executes them. Features:
|
|
219
|
+
|
|
220
|
+
- **Persistent memory**: writes a task journal (`.hawkeye/task-journal.md`) after each task
|
|
221
|
+
- **Conversation continuity**: uses `claude --continue` within 30-min windows
|
|
222
|
+
- **Context injection**: enriches prompts with git status, recent commits, and task history
|
|
223
|
+
- Works with any agent CLI, not just Claude
|
|
224
|
+
|
|
225
|
+
### `hawkeye export`
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
hawkeye export <session-id> [-f json|html] [-o report.html]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `hawkeye end`
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
hawkeye end [-s <session-id>] [--all] [--status completed|aborted]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `hawkeye restart`
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
hawkeye restart [session-id] [-o <objective>] [-a <agent>] [-m <model>]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Restart a session — inherits objective, agent, and model from the original if not overridden. Interactive picker when no ID is given.
|
|
244
|
+
|
|
245
|
+
### `hawkeye otel-export`
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
hawkeye otel-export <session-id> [-o traces.json]
|
|
249
|
+
hawkeye otel-export <session-id> --endpoint https://tempo.example.com/v1/traces
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Export as OTLP JSON traces. Compatible with Grafana Tempo, Jaeger, Datadog, Honeycomb.
|
|
253
|
+
|
|
254
|
+
### `hawkeye hooks`
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
hawkeye hooks install [--local] [--guardrails-only]
|
|
258
|
+
hawkeye hooks uninstall [--local]
|
|
259
|
+
hawkeye hooks status
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `hawkeye mcp`
|
|
263
|
+
|
|
264
|
+
Start the MCP (Model Context Protocol) server over stdio. Agents connect automatically.
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
hawkeye mcp [--db <path>]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Add to `.mcp.json` at project root for Claude Code:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"mcpServers": {
|
|
275
|
+
"hawkeye": {
|
|
276
|
+
"command": "node",
|
|
277
|
+
"args": ["path/to/hawkeye/packages/cli/dist/index.js", "mcp"]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**27 tools** for agent self-awareness:
|
|
284
|
+
|
|
285
|
+
| Category | Tools |
|
|
286
|
+
|----------|-------|
|
|
287
|
+
| **Observability** (9) | `list_sessions`, `get_session`, `get_session_events`, `get_session_drift`, `get_session_stats`, `get_global_stats`, `compare_sessions`, `get_violations`, `get_cost_by_file` |
|
|
288
|
+
| **Self-awareness** (8) | `check_drift`, `get_objective`, `check_cost`, `check_guardrail`, `check_progress`, `log_event`, `list_changes`, `get_config` |
|
|
289
|
+
| **Intelligence** (4) | `get_session_timeline`, `get_error_summary`, `suggest_correction`, `post_mortem` |
|
|
290
|
+
| **Actions** (4) | `end_session`, `pause_session`, `resume_session`, `set_objective` |
|
|
291
|
+
| **Cross-session** (2) | `search_events`, `revert_file` |
|
|
292
|
+
|
|
293
|
+
## Dashboard
|
|
294
|
+
|
|
295
|
+
The web dashboard (`hawkeye serve`) is fully **mobile responsive** and provides:
|
|
296
|
+
|
|
297
|
+
### Sessions Page
|
|
298
|
+
|
|
299
|
+
- List all sessions with status filtering (recording / completed / aborted)
|
|
300
|
+
- Search by objective or agent name
|
|
301
|
+
- Auto-refresh every 5 seconds, module-level cache (no flash on page change)
|
|
302
|
+
- Shows costs, drift scores, action counts
|
|
303
|
+
|
|
304
|
+
### Session Detail Page
|
|
305
|
+
|
|
306
|
+
- **Drift score chart** — Line chart with warning/critical reference zones
|
|
307
|
+
- **Event timeline** — Filterable, searchable list with type badges (CMD, FILE, LLM, GUARD, etc.)
|
|
308
|
+
- **Expandable details** — Full event payload for each action
|
|
309
|
+
- **Live mode** — Auto-refreshes every 3 seconds for active sessions
|
|
310
|
+
- **Export** — Download session as JSON
|
|
311
|
+
|
|
312
|
+
### Tasks Page (Remote)
|
|
313
|
+
|
|
314
|
+
- Submit prompts remotely from your phone
|
|
315
|
+
- **Image attachments** — Upload photos to include with prompts
|
|
316
|
+
- **Auto-approve toggle** — Automatically approve all guardrail-blocked actions
|
|
317
|
+
- **Approve/Deny buttons** — Manually review dangerous actions
|
|
318
|
+
- **Agent memory** — View/clear the persistent task journal
|
|
319
|
+
- Status tracking: pending, running, completed, failed
|
|
320
|
+
|
|
321
|
+
### Compare Page
|
|
322
|
+
|
|
323
|
+
- Select two sessions to compare side by side
|
|
324
|
+
- Stats comparison (actions, cost, tokens, drift)
|
|
325
|
+
|
|
326
|
+
### Settings Page
|
|
327
|
+
|
|
328
|
+
- Configure DriftDetect (provider, model, thresholds, check frequency)
|
|
329
|
+
- Manage guardrail rules (enable/disable, toggle warn/block)
|
|
330
|
+
- Provider model selection with live lookup
|
|
331
|
+
|
|
332
|
+
### REST API
|
|
333
|
+
|
|
334
|
+
| Endpoint | Method | Description |
|
|
335
|
+
| --------------------------------- | ------ | -------------------------------- |
|
|
336
|
+
| `/api/sessions` | GET | List sessions |
|
|
337
|
+
| `/api/sessions/:id` | GET | Session details |
|
|
338
|
+
| `/api/sessions/:id/events` | GET | Session events |
|
|
339
|
+
| `/api/sessions/:id/drift` | GET | Drift snapshots |
|
|
340
|
+
| `/api/sessions/:id/cost-by-file` | GET | Cost breakdown by file |
|
|
341
|
+
| `/api/sessions/:id/end` | POST | End a session |
|
|
342
|
+
| `/api/sessions/:id/pause` | POST | Pause a session |
|
|
343
|
+
| `/api/sessions/:id/resume` | POST | Resume a paused session |
|
|
344
|
+
| `/api/compare?ids=id1,id2` | GET | Compare sessions side by side |
|
|
345
|
+
| `/api/stats` | GET | Global statistics |
|
|
346
|
+
| `/api/settings` | GET | Get configuration |
|
|
347
|
+
| `/api/settings` | POST | Save configuration (Zod-validated) |
|
|
348
|
+
| `/api/providers` | GET | Available LLM providers & models |
|
|
349
|
+
| `/api/ingest` | POST | Universal event ingestion (Zod-validated) |
|
|
350
|
+
| `/api/revert` | POST | Revert a file change |
|
|
351
|
+
| `/api/tasks` | GET | List remote tasks |
|
|
352
|
+
| `/api/tasks` | POST | Create a task (with attachments) |
|
|
353
|
+
| `/api/tasks/:id/cancel` | POST | Cancel a pending task |
|
|
354
|
+
| `/api/tasks/journal` | GET | Read agent memory journal |
|
|
355
|
+
| `/api/tasks/journal/clear` | POST | Clear agent memory |
|
|
356
|
+
| `/api/tasks/attachments/:file` | GET | Serve task image attachments |
|
|
357
|
+
| `/api/pending-reviews` | GET | List pending review gate items |
|
|
358
|
+
| `/api/review-approve` | POST | Approve a review gate item |
|
|
359
|
+
| `/api/review-deny` | POST | Deny a review gate item |
|
|
360
|
+
|
|
361
|
+
## DriftDetect
|
|
362
|
+
|
|
363
|
+
DriftDetect monitors agent behavior in real-time and assigns a **drift score** (0–100):
|
|
364
|
+
|
|
365
|
+
| Score | Status | Meaning |
|
|
366
|
+
| ------ | ----------- | --------------------------------- |
|
|
367
|
+
| 70–100 | ✅ OK | Agent is on track |
|
|
368
|
+
| 40–69 | ⚠️ Warning | Possible deviation from objective |
|
|
369
|
+
| 0–39 | 🔴 Critical | Significant drift detected |
|
|
370
|
+
|
|
371
|
+
### Scoring Engines
|
|
372
|
+
|
|
373
|
+
**Heuristic scorer** (always active, zero-cost):
|
|
374
|
+
|
|
375
|
+
- Penalizes dangerous commands (`rm -rf`, `DROP TABLE`, `curl | bash`)
|
|
376
|
+
- Flags suspicious paths (`/etc`, `~/.ssh`, `/root`)
|
|
377
|
+
- Detects sensitive file extensions (`.pem`, `.key`, `.env`)
|
|
378
|
+
- Monitors error rates
|
|
379
|
+
|
|
380
|
+
**LLM scorer** (optional, configurable):
|
|
381
|
+
|
|
382
|
+
- Evaluates actions against the stated objective using an LLM
|
|
383
|
+
- Supports 6 providers:
|
|
384
|
+
|
|
385
|
+
| Provider | Models |
|
|
386
|
+
| --------- | ---------------------------------------------------------------------------------------------------- |
|
|
387
|
+
| Ollama | llama4, llama3.2, mistral, codellama, deepseek-coder, phi3 |
|
|
388
|
+
| Anthropic | claude-sonnet-4-6, claude-opus-4-6, claude-haiku-4-5, claude-sonnet-4-5, claude-opus-4-5 |
|
|
389
|
+
| OpenAI | gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-5, gpt-5-mini, o3, o3-mini, o4-mini |
|
|
390
|
+
| DeepSeek | deepseek-chat, deepseek-reasoner |
|
|
391
|
+
| Mistral | mistral-large-latest, mistral-medium-latest, mistral-small-latest, codestral-latest, devstral-latest |
|
|
392
|
+
| Google | gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.0-flash |
|
|
393
|
+
|
|
394
|
+
## Guardrails
|
|
395
|
+
|
|
396
|
+
Guardrails are evaluated **synchronously before** events are persisted. Violations can `warn` (log only) or `block` (prevent the action).
|
|
397
|
+
|
|
398
|
+
| Rule Type | Description | Config |
|
|
399
|
+
| ----------------- | -------------------------------------- | ------------------------------------- |
|
|
400
|
+
| `file_protect` | Protect files/dirs from modification | `paths: string[]` (glob patterns) |
|
|
401
|
+
| `command_block` | Block dangerous commands | `patterns: string[]` (regex patterns) |
|
|
402
|
+
| `cost_limit` | Limit spending per session/hour | `maxUsdPerSession`, `maxUsdPerHour` |
|
|
403
|
+
| `token_limit` | Limit token consumption | `maxTokensPerSession` |
|
|
404
|
+
| `directory_scope` | Restrict agent to specific directories | `allowedDirs`, `blockedDirs` |
|
|
405
|
+
| `network_lock` | Allow/block specific API hostnames | `allowedHosts`, `blockedHosts` |
|
|
406
|
+
| `review_gate` | Require human approval for commands | `patterns: string[]` (regex patterns) |
|
|
407
|
+
|
|
408
|
+
Example configuration (via `/settings` in TUI or dashboard):
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"guardrails": [
|
|
413
|
+
{
|
|
414
|
+
"name": "Protect secrets",
|
|
415
|
+
"type": "file_protect",
|
|
416
|
+
"enabled": true,
|
|
417
|
+
"action": "block",
|
|
418
|
+
"config": { "paths": ["**/.env", "**/*.key", "**/*.pem"] }
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"name": "No destructive commands",
|
|
422
|
+
"type": "command_block",
|
|
423
|
+
"enabled": true,
|
|
424
|
+
"action": "block",
|
|
425
|
+
"config": { "patterns": ["rm\\s+-rf\\s+/", "DROP\\s+TABLE", "curl.*\\|.*bash"] }
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"name": "Budget limit",
|
|
429
|
+
"type": "cost_limit",
|
|
430
|
+
"enabled": true,
|
|
431
|
+
"action": "warn",
|
|
432
|
+
"config": { "maxUsdPerSession": 5.0, "maxUsdPerHour": 2.0 }
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Configuration
|
|
439
|
+
|
|
440
|
+
Configuration is stored at `.hawkeye/config.json`:
|
|
441
|
+
|
|
442
|
+
```json
|
|
443
|
+
{
|
|
444
|
+
"drift": {
|
|
445
|
+
"enabled": true,
|
|
446
|
+
"checkEvery": 5,
|
|
447
|
+
"provider": "ollama",
|
|
448
|
+
"model": "llama3.2",
|
|
449
|
+
"warningThreshold": 60,
|
|
450
|
+
"criticalThreshold": 30,
|
|
451
|
+
"contextWindow": 10
|
|
452
|
+
},
|
|
453
|
+
"guardrails": [],
|
|
454
|
+
"apiKeys": {
|
|
455
|
+
"anthropic": "sk-ant-...",
|
|
456
|
+
"openai": "sk-..."
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Manage settings via:
|
|
462
|
+
|
|
463
|
+
- **TUI**: `/settings` command with interactive sub-menus
|
|
464
|
+
- **Dashboard**: Settings page at `http://localhost:4242/settings`
|
|
465
|
+
- **Direct edit**: `.hawkeye/config.json`
|
|
466
|
+
|
|
467
|
+
## Security
|
|
468
|
+
|
|
469
|
+
Hawkeye is designed to run locally. The dashboard server binds to `localhost` and includes multiple security layers:
|
|
470
|
+
|
|
471
|
+
| Protection | Description |
|
|
472
|
+
|---|---|
|
|
473
|
+
| **CORS** | Only `localhost` / `127.0.0.1` origins accepted |
|
|
474
|
+
| **WebSocket origin check** | Upgrade requests from cross-origin pages are rejected |
|
|
475
|
+
| **POST body limit** | 5 MB max — oversized requests are destroyed (prevents DoS) |
|
|
476
|
+
| **Path traversal** | Static file serving and attachment endpoints verify resolved paths stay within their root |
|
|
477
|
+
| **No command injection** | All git operations use `execFile()` with argument arrays, never shell strings |
|
|
478
|
+
| **Config file permissions** | `.hawkeye/config.json` written with `0o600` (owner-only) to protect API keys |
|
|
479
|
+
| **Concurrent write safety** | Hook handler uses exclusive lockfile for `hook-sessions.json` writes |
|
|
480
|
+
|
|
481
|
+
### API Keys
|
|
482
|
+
|
|
483
|
+
API keys for LLM providers (Anthropic, OpenAI, etc.) are stored in `.hawkeye/config.json`. The file is created with restricted permissions (`0o600`), but you should also add `.hawkeye/` to your global `.gitignore` to avoid accidental commits.
|
|
484
|
+
|
|
485
|
+
## Architecture
|
|
486
|
+
|
|
487
|
+
TypeScript monorepo using **pnpm workspaces** + **Turborepo**:
|
|
488
|
+
|
|
489
|
+
```
|
|
490
|
+
packages/
|
|
491
|
+
├── core/ Node.js SDK — recorder, interceptors, storage, DriftDetect, guardrails
|
|
492
|
+
├── cli/ CLI (Commander.js + chalk) — commands, interactive TUI
|
|
493
|
+
└── dashboard/ React 19 + Vite + Tailwind CSS + Recharts — web UI
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Data Flow
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
Agent ──► Interceptors ──► Recorder ──► Guardrails (sync) ──► SQLite
|
|
500
|
+
│
|
|
501
|
+
└──► DriftDetect (async)
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Network Interception
|
|
505
|
+
|
|
506
|
+
For child processes, Hawkeye injects a preload ESM script via `NODE_OPTIONS="--import ..."` that monkey-patches `http/https.request` and `globalThis.fetch`. It detects LLM API calls by hostname and path, parses SSE streaming responses, and sends captured events back to the parent via Node.js IPC.
|
|
507
|
+
|
|
508
|
+
### Storage
|
|
509
|
+
|
|
510
|
+
SQLite via `better-sqlite3` with WAL mode. Four tables:
|
|
511
|
+
|
|
512
|
+
| Table | Purpose |
|
|
513
|
+
| ---------------------- | ------------------------------------------------------------- |
|
|
514
|
+
| `sessions` | Session metadata (objective, agent, status, timestamps) |
|
|
515
|
+
| `events` | Captured events (type, data, timestamps, token counts, costs) |
|
|
516
|
+
| `drift_snapshots` | Drift score history per session |
|
|
517
|
+
| `guardrail_violations` | Guardrail violation log |
|
|
518
|
+
|
|
519
|
+
## Development
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
pnpm install # Install all dependencies
|
|
523
|
+
pnpm build # Production build (all packages)
|
|
524
|
+
pnpm dev # Dev mode (Turborepo watch)
|
|
525
|
+
pnpm test # Run all tests (Vitest)
|
|
526
|
+
pnpm --filter @hawkeye/core test # Run only core tests
|
|
527
|
+
pnpm --filter @hawkeye/cli build # Build only CLI
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Requirements
|
|
531
|
+
|
|
532
|
+
- Node.js ≥ 20
|
|
533
|
+
- pnpm 9.x
|
|
534
|
+
|
|
535
|
+
### Tech Stack
|
|
536
|
+
|
|
537
|
+
| Package | Stack |
|
|
538
|
+
| -------------------- | -------------------------------------- |
|
|
539
|
+
| `@hawkeye/core` | TypeScript, better-sqlite3, Vitest |
|
|
540
|
+
| `@hawkeye/cli` | TypeScript, Commander.js, chalk v5 |
|
|
541
|
+
| `@hawkeye/dashboard` | React 19, Vite, Tailwind CSS, Recharts |
|
|
542
|
+
|
|
543
|
+
### Code Conventions
|
|
544
|
+
|
|
545
|
+
- TypeScript strict mode, ES2022 target, ESM modules
|
|
546
|
+
- File names in kebab-case
|
|
547
|
+
- Named exports only (no default exports except React components)
|
|
548
|
+
- `Result<T, E>` pattern for error handling (no throwing in core)
|
|
549
|
+
- Prettier: semi, singleQuote, trailingComma: all, printWidth: 100
|
|
550
|
+
|
|
551
|
+
## Publishing
|
|
552
|
+
|
|
553
|
+
### npm
|
|
554
|
+
|
|
555
|
+
Hawkeye is published as two packages on npm:
|
|
556
|
+
|
|
557
|
+
- [`@mklamine/hawkeye-core`](https://www.npmjs.com/package/@mklamine/hawkeye-core) — Core SDK
|
|
558
|
+
- [`@mklamine/hawkeye-cli`](https://www.npmjs.com/package/@mklamine/hawkeye-cli) — CLI with bundled dashboard
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
# Build everything
|
|
562
|
+
pnpm build
|
|
563
|
+
|
|
564
|
+
# Publish (pnpm resolves workspace:* to real versions)
|
|
565
|
+
pnpm -r publish --access public --no-git-checks
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
The CLI `prepack` script automatically copies the dashboard build into the CLI package so it ships as a single installable.
|
|
569
|
+
|
|
570
|
+
### Homebrew
|
|
571
|
+
|
|
572
|
+
To distribute via Homebrew, create a tap repository (e.g. `homebrew-hawkeye`) with a formula:
|
|
573
|
+
|
|
574
|
+
```ruby
|
|
575
|
+
# Formula/hawkeye.rb
|
|
576
|
+
class Hawkeye < Formula
|
|
577
|
+
desc "The flight recorder for AI agents"
|
|
578
|
+
homepage "https://github.com/mklamine/hawkeye"
|
|
579
|
+
url "https://registry.npmjs.org/@mklamine/hawkeye-cli/-/hawkeye-cli-0.1.1.tgz"
|
|
580
|
+
sha256 "SHA256_OF_TARBALL"
|
|
581
|
+
|
|
582
|
+
depends_on "node@20"
|
|
583
|
+
|
|
584
|
+
def install
|
|
585
|
+
system "npm", "install", *std_npm_args
|
|
586
|
+
bin.install_symlink libexec/"bin/hawkeye"
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
test do
|
|
590
|
+
assert_match "hawkeye", shell_output("#{bin}/hawkeye --version")
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
Then:
|
|
596
|
+
|
|
597
|
+
```bash
|
|
598
|
+
# Create the tap repo
|
|
599
|
+
gh repo create mklamine/homebrew-hawkeye --public
|
|
600
|
+
|
|
601
|
+
# Users install with:
|
|
602
|
+
brew tap mklamine/hawkeye
|
|
603
|
+
brew install hawkeye
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### GitHub Releases
|
|
607
|
+
|
|
608
|
+
Automate releases with a GitHub Actions workflow:
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
# Tag a release
|
|
612
|
+
git tag v0.1.0
|
|
613
|
+
git push origin v0.1.0
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
Add a `.github/workflows/release.yml` to auto-publish to npm on tag push (see below).
|
|
617
|
+
|
|
618
|
+
## CI/CD
|
|
619
|
+
|
|
620
|
+
<details>
|
|
621
|
+
<summary><code>.github/workflows/ci.yml</code> — Test & Build</summary>
|
|
622
|
+
|
|
623
|
+
```yaml
|
|
624
|
+
name: CI
|
|
625
|
+
on: [push, pull_request]
|
|
626
|
+
jobs:
|
|
627
|
+
build:
|
|
628
|
+
runs-on: ubuntu-latest
|
|
629
|
+
steps:
|
|
630
|
+
- uses: actions/checkout@v4
|
|
631
|
+
- uses: pnpm/action-setup@v4
|
|
632
|
+
- uses: actions/setup-node@v4
|
|
633
|
+
with:
|
|
634
|
+
node-version: 20
|
|
635
|
+
cache: pnpm
|
|
636
|
+
- run: pnpm install --frozen-lockfile
|
|
637
|
+
- run: pnpm build
|
|
638
|
+
- run: pnpm test
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
</details>
|
|
642
|
+
|
|
643
|
+
<details>
|
|
644
|
+
<summary><code>.github/workflows/release.yml</code> — Publish to npm on tag</summary>
|
|
645
|
+
|
|
646
|
+
```yaml
|
|
647
|
+
name: Release
|
|
648
|
+
on:
|
|
649
|
+
push:
|
|
650
|
+
tags: ['v*']
|
|
651
|
+
jobs:
|
|
652
|
+
publish:
|
|
653
|
+
runs-on: ubuntu-latest
|
|
654
|
+
permissions:
|
|
655
|
+
contents: write
|
|
656
|
+
steps:
|
|
657
|
+
- uses: actions/checkout@v4
|
|
658
|
+
- uses: pnpm/action-setup@v4
|
|
659
|
+
- uses: actions/setup-node@v4
|
|
660
|
+
with:
|
|
661
|
+
node-version: 20
|
|
662
|
+
cache: pnpm
|
|
663
|
+
registry-url: https://registry.npmjs.org
|
|
664
|
+
- run: pnpm install --frozen-lockfile
|
|
665
|
+
- run: pnpm build
|
|
666
|
+
- run: pnpm -r publish --access public --no-git-checks
|
|
667
|
+
env:
|
|
668
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
669
|
+
- uses: softprops/action-gh-release@v2
|
|
670
|
+
with:
|
|
671
|
+
generate_release_notes: true
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
</details>
|
|
675
|
+
|
|
676
|
+
## Acknowledgments
|
|
677
|
+
|
|
678
|
+
Special thanks to **Lamine** for their contributions and support.
|
|
679
|
+
|
|
680
|
+
## License
|
|
681
|
+
|
|
682
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hawkeye-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for Hawkeye — the flight recorder for AI agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dev": "tsc --watch",
|
|
35
35
|
"test": "vitest run --passWithNoTests",
|
|
36
36
|
"lint": "eslint src/",
|
|
37
|
-
"prepack": "node -e \"const{cpSync,existsSync,mkdirSync}=require('fs');const{join}=require('path');const src=join(__dirname,'..','dashboard','dist');const dst=join(__dirname,'dashboard');if(existsSync(src)){mkdirSync(dst,{recursive:true});cpSync(src,dst,{recursive:true});console.log('Bundled dashboard dist into CLI package')}else{console.warn('Dashboard dist not found — run pnpm build first')}\""
|
|
37
|
+
"prepack": "node -e \"const{cpSync,existsSync,mkdirSync}=require('fs');const{join}=require('path');const src=join(__dirname,'..','dashboard','dist');const dst=join(__dirname,'dashboard');if(existsSync(src)){mkdirSync(dst,{recursive:true});cpSync(src,dst,{recursive:true});console.log('Bundled dashboard dist into CLI package')}else{console.warn('Dashboard dist not found — run pnpm build first')};const readme=join(__dirname,'..','..','README.md');if(existsSync(readme)){cpSync(readme,join(__dirname,'README.md'));console.log('Copied README.md')}\""
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@mklamine/hawkeye-core": "^0.1.1",
|