@klars/agentobs 0.1.0 → 0.1.2
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 +231 -190
- package/dist/commands/hook-config.js +25 -1
- package/dist/core/queries.js +117 -42
- package/dist/server/index.js +4 -2
- package/dist/server/public/app.css +961 -668
- package/dist/server/public/app.js +647 -502
- package/dist/server/public/index.html +212 -196
- package/dist/server/public/logo.svg +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,190 +1,231 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
AgentObs
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[](https://www.npmjs.com/package/@klars/agentobs)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
|
|
13
|
+
[Website](https://agents.klars.ai) · [npm](https://www.npmjs.com/package/@klars/agentobs) · [Contributing](CONTRIBUTING.md)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<br>
|
|
18
|
+
|
|
19
|
+
<picture>
|
|
20
|
+
<source srcset="docs/assets/dashboard-dark.png" media="(prefers-color-scheme: dark)" />
|
|
21
|
+
<img src="docs/assets/dashboard.png" alt="The AgentObs dashboard: spend for the week, tool call and error-rate tiles with trend sparklines, an activity chart, and tables of tools and sessions." />
|
|
22
|
+
</picture>
|
|
23
|
+
|
|
24
|
+
<br>
|
|
25
|
+
|
|
26
|
+
## Guardrails that actually stop things
|
|
27
|
+
|
|
28
|
+
<img src="docs/assets/demo.gif" alt="Terminal demo: agentobs policy test blocks an rm -rf command, then agentobs stats shows the cost, calls, errors and blocked totals." width="820" />
|
|
29
|
+
|
|
30
|
+
AgentObs is an observability and control layer for AI coding agents. It runs
|
|
31
|
+
entirely on your machine: a CLI, a local SQLite database, and a dashboard. No
|
|
32
|
+
account, no cloud, no telemetry.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @klars/agentobs
|
|
38
|
+
agentobs init
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`init` prints a hook configuration block. Paste it into `~/.claude/settings.json`
|
|
42
|
+
(or a project's `.claude/settings.json`), then:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
agentobs dashboard
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Run Claude Code as usual. Tool calls appear in the dashboard within seconds.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What you get
|
|
53
|
+
|
|
54
|
+
| | |
|
|
55
|
+
| ---------------------- | ------------------------------------------------------------ |
|
|
56
|
+
| **Cost tracking** | Per session, per tool, per day — or blank if the model's price is unknown. Never guessed. |
|
|
57
|
+
| **Tool-call timeline** | Every call, its duration, status, and truncated input. |
|
|
58
|
+
| **Guardrails** | Block `rm -rf`, require approval for `.env` edits, stop `curl \| sh`. |
|
|
59
|
+
| **Audit trail** | Every policy decision recorded with the rule that fired. |
|
|
60
|
+
| **Any agent** | Native Claude Code hooks; JSONL ingestion or process-wrapping for everything else. |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Privacy
|
|
65
|
+
|
|
66
|
+
This is the part that matters most, since AgentObs sits in the middle of
|
|
67
|
+
everything your agent does.
|
|
68
|
+
|
|
69
|
+
- **Nothing leaves your machine.** No network calls, no analytics, no account.
|
|
70
|
+
- **Secrets are redacted before anything is written to disk.** Tool inputs and
|
|
71
|
+
outputs pass through a redaction layer that recognises AWS keys, Anthropic /
|
|
72
|
+
OpenAI / GitHub / GitLab / Slack / Stripe / Google / npm tokens, JWTs, PEM
|
|
73
|
+
private keys, `KEY=value` assignments, `--flag secret` arguments,
|
|
74
|
+
`Authorization:` headers, and credentials embedded in URLs.
|
|
75
|
+
- **Summaries are truncated** to ~500 characters.
|
|
76
|
+
- The redaction rules are unit-tested in
|
|
77
|
+
[`src/core/redact.test.ts`](src/core/redact.test.ts) — the tests are the
|
|
78
|
+
guarantee, and they have caught real leaks during development.
|
|
79
|
+
|
|
80
|
+
Everything lives in `~/.agentobs/`. Uninstalling is `rm -rf ~/.agentobs`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
agentobs init Set up ~/.agentobs and print the hook config
|
|
88
|
+
agentobs dashboard [--port] [--host] Serve the dashboard (default 127.0.0.1:4300)
|
|
89
|
+
agentobs stats [--today] [--since] Print totals in the terminal
|
|
90
|
+
agentobs run -- <command...> Observe any command (coarse detail)
|
|
91
|
+
agentobs watch <file.jsonl> Ingest a JSONL agent log
|
|
92
|
+
agentobs export --format csv|json Export sessions, tool calls, or decisions
|
|
93
|
+
|
|
94
|
+
agentobs policy init Write a starter policy.json
|
|
95
|
+
agentobs policy check Validate it and list active rules
|
|
96
|
+
agentobs policy test <tool> <input> Dry-run a call against the policy
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Guardrails
|
|
102
|
+
|
|
103
|
+
`agentobs policy init` writes `~/.agentobs/policy.json`:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"rules": [
|
|
108
|
+
{
|
|
109
|
+
"name": "no-recursive-force-delete",
|
|
110
|
+
"match": { "tool": "Bash", "command_pattern": "*rm -rf*" },
|
|
111
|
+
"decision": "block",
|
|
112
|
+
"message": "Recursive force-delete is blocked by AgentObs policy."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "protect-env-files",
|
|
116
|
+
"match": { "tool": "*", "path_pattern": "**/.env*" },
|
|
117
|
+
"decision": "needs_approval"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"default_decision": "allow"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Rules are evaluated top to bottom; **the first match wins**, so you can put a
|
|
125
|
+
narrow `allow` above a broad `block`. Check what a rule will do *before* it
|
|
126
|
+
fires mid-task:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
$ agentobs policy test Bash "rm -rf ./build"
|
|
130
|
+
|
|
131
|
+
Tool Bash
|
|
132
|
+
Input rm -rf ./build
|
|
133
|
+
Decision BLOCK
|
|
134
|
+
Rule no-recursive-force-delete
|
|
135
|
+
|
|
136
|
+
This call would be BLOCKED before running.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Two deliberate behaviours worth knowing:
|
|
140
|
+
|
|
141
|
+
- **`needs_approval` currently behaves as a block** with a clearer message.
|
|
142
|
+
There is no channel for a hook to prompt you interactively mid-call.
|
|
143
|
+
- **A broken policy file fails open.** Invalid JSON or a malformed rule
|
|
144
|
+
degrades to allow-everything and reports the problem, because a guardrail
|
|
145
|
+
that wedges your agent is worse than no guardrail. Run `agentobs policy check`.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Agent support
|
|
150
|
+
|
|
151
|
+
| Agent | How | Detail |
|
|
152
|
+
| --------------- | -------------------------- | ------------------------------------------------- |
|
|
153
|
+
| **Claude Code** | Native hooks | **Rich** — every tool call, plus policy enforcement |
|
|
154
|
+
| Any CLI agent | `agentobs run -- <cmd>` | **Coarse** — duration and exit code only |
|
|
155
|
+
| Custom / in-house | `agentobs watch <file>` | **Rich**, if it writes JSONL |
|
|
156
|
+
|
|
157
|
+
The dashboard labels coarse sessions as `coarse` rather than implying detail it
|
|
158
|
+
does not have.
|
|
159
|
+
|
|
160
|
+
### A note on cost accuracy
|
|
161
|
+
|
|
162
|
+
Claude Code's `PostToolUse` hook payload carries **no token or cost fields**.
|
|
163
|
+
AgentObs therefore reads token usage from the session transcript at
|
|
164
|
+
`SessionEnd`, which makes **session-level cost accurate** but leaves
|
|
165
|
+
**per-tool-call cost blank** for hook-sourced data. It does not divide a total
|
|
166
|
+
across calls to manufacture a number.
|
|
167
|
+
|
|
168
|
+
Model prices live in `~/.agentobs/pricing.json` and are yours to edit. A model
|
|
169
|
+
missing from that file shows cost as `—`, never `$0.00`.
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
### Hook latency
|
|
173
|
+
|
|
174
|
+
The hook does its own work in **well under 1ms** (measured: ~0.3ms per
|
|
175
|
+
invocation, including the SQLite write). What you actually pay per tool call is
|
|
176
|
+
**Node.js process startup**, since Claude Code spawns the hook as a fresh
|
|
177
|
+
process each time.
|
|
178
|
+
|
|
179
|
+
On a typical Linux/macOS machine that is ~40-80ms. On Windows with real-time
|
|
180
|
+
antivirus scanning it can reach **1-1.5 seconds** - and that cost is not
|
|
181
|
+
specific to AgentObs: a bare `node -e "0"` measures the same. Check yours with:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
node -e "0" # time this; it is the floor for any Node-based hook
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If it is slow, adding an exclusion for your Node install directory and
|
|
188
|
+
`~/.agentobs` in your antivirus settings is the fix. There is no code change
|
|
189
|
+
that avoids it - the cost is paid before AgentObs runs at all.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Dashboard access
|
|
194
|
+
|
|
195
|
+
Binds to `127.0.0.1` with no authentication — same machine, same user, same
|
|
196
|
+
trust boundary as the database file.
|
|
197
|
+
|
|
198
|
+
Binding anywhere else **requires a token**, printed at startup and included in
|
|
199
|
+
the URL:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
agentobs dashboard --host 0.0.0.0
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Never expose the dashboard to the public internet.** It shows tool inputs and
|
|
206
|
+
file paths from your repositories.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Requirements
|
|
211
|
+
|
|
212
|
+
Node.js **≥ 22.5** — AgentObs uses the built-in `node:sqlite` module, so there
|
|
213
|
+
is no native addon to compile and no C++ toolchain to install.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm install
|
|
221
|
+
npm run build
|
|
222
|
+
npm test
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Adding an adapter for another agent: see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT © [Klars AI](https://klars.ai)
|
|
@@ -22,7 +22,31 @@ import { existsSync } from 'node:fs';
|
|
|
22
22
|
*/
|
|
23
23
|
export function hookCommandPath() {
|
|
24
24
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
25
|
-
//
|
|
25
|
+
// On Windows, prefer npm's generated .cmd shim in the global bin directory.
|
|
26
|
+
//
|
|
27
|
+
// The raw bin/agentobs-hook file has no extension, and Windows cannot
|
|
28
|
+
// execute an extensionless file - cmd.exe reports "not recognized as an
|
|
29
|
+
// internal or external command". Claude Code swallows that, so the hook
|
|
30
|
+
// silently never runs and no data is ever recorded: the worst possible
|
|
31
|
+
// failure for an observability tool, because it looks like "no activity"
|
|
32
|
+
// rather than "broken". npm generates the .cmd shim for exactly this.
|
|
33
|
+
if (process.platform === 'win32') {
|
|
34
|
+
// dist/commands -> .../node_modules/@klars/agentobs -> up to the dir
|
|
35
|
+
// holding npm's shims (node_modules/.bin, or the global npm root).
|
|
36
|
+
const packageRoot = resolve(here, '..', '..');
|
|
37
|
+
const shims = [
|
|
38
|
+
resolve(packageRoot, '..', '..', '..', 'agentobs-hook.cmd'), // global npm root
|
|
39
|
+
resolve(packageRoot, '..', '..', '.bin', 'agentobs-hook.cmd'), // local node_modules/.bin
|
|
40
|
+
];
|
|
41
|
+
for (const shim of shims) {
|
|
42
|
+
if (existsSync(shim))
|
|
43
|
+
return shim;
|
|
44
|
+
}
|
|
45
|
+
// No shim found (e.g. running from a source checkout): fall back to the
|
|
46
|
+
// bare name so PATH resolution can still find it, rather than emitting a
|
|
47
|
+
// path that is guaranteed not to execute.
|
|
48
|
+
return 'agentobs-hook.cmd';
|
|
49
|
+
}
|
|
26
50
|
const candidate = resolve(here, '..', '..', 'bin', 'agentobs-hook');
|
|
27
51
|
if (existsSync(candidate))
|
|
28
52
|
return candidate;
|