agentacta 1.3.4 → 2026.3.5
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 +100 -79
- package/db.js +1 -0
- package/index.js +60 -3
- package/package.json +1 -1
- package/public/app.js +740 -55
- package/public/index.html +17 -5
- package/public/style.css +519 -3
package/README.md
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/agentacta)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
**Your
|
|
7
|
+
**Your agent did 1000s of things today. Can you find the 1 that broke prod?**
|
|
8
8
|
|
|
9
|
-
AgentActa is
|
|
9
|
+
AgentActa is a local audit trail and search engine for AI agent sessions.
|
|
10
|
+
|
|
11
|
+
It indexes messages, tool calls, file edits, searches, and decisions into a fast UI you can query in seconds.
|
|
10
12
|
|
|
11
13
|
One command. Zero config. Full visibility.
|
|
12
14
|
|
|
@@ -18,24 +20,25 @@ npx agentacta
|
|
|
18
20
|
<img src="screenshots/demo.gif" alt="AgentActa demo" width="800">
|
|
19
21
|
</p>
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
## Why this exists
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
Agents move fast. Your memory of what happened doesn’t.
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
When you need to answer “what changed, when, and why,” you’re usually scraping logs, scrolling transcripts, or asking the same assistant that forgot 20 minutes ago.
|
|
26
28
|
|
|
27
|
-
AgentActa gives you
|
|
29
|
+
AgentActa gives you one place to inspect the full trail.
|
|
28
30
|
|
|
29
|
-
## What
|
|
31
|
+
## What you get
|
|
30
32
|
|
|
31
|
-
🔍
|
|
32
|
-
📋
|
|
33
|
-
📅
|
|
34
|
-
📁
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
- 🔍 Full-text search across messages, tool calls, and results
|
|
34
|
+
- 📋 Session browser with summaries, token breakdowns, and model info
|
|
35
|
+
- 📅 Timeline view with live updates for today
|
|
36
|
+
- 📁 File activity across all indexed sessions
|
|
37
|
+
- 🌗 Light and dark themes
|
|
38
|
+
- 📊 Stats for sessions, messages, tools, and tokens
|
|
39
|
+
- ⚡ Live indexing via file watching
|
|
40
|
+
- 📱 Mobile-friendly UI
|
|
41
|
+
- 💡 Search suggestions based on real data
|
|
39
42
|
|
|
40
43
|
## Demo
|
|
41
44
|
|
|
@@ -51,62 +54,81 @@ https://github.com/mirajchokshi/agentacta/raw/main/screenshots/demo-final.mp4
|
|
|
51
54
|

|
|
52
55
|

|
|
53
56
|
|
|
54
|
-
## Quick
|
|
57
|
+
## Quick start
|
|
55
58
|
|
|
56
59
|
```bash
|
|
57
|
-
#
|
|
60
|
+
# run directly
|
|
58
61
|
npx agentacta
|
|
59
62
|
|
|
60
|
-
#
|
|
63
|
+
# or install globally
|
|
61
64
|
npm install -g agentacta
|
|
62
65
|
agentacta
|
|
63
66
|
```
|
|
64
67
|
|
|
65
|
-
Open `http://localhost:4003`
|
|
68
|
+
Open: `http://localhost:4003`
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
Auto-detected session paths:
|
|
68
71
|
- `~/.openclaw/agents/*/sessions/` (OpenClaw)
|
|
69
72
|
- `~/.claude/projects/*/` (Claude Code)
|
|
70
73
|
- `~/.codex/sessions/` (Codex CLI)
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
Custom path:
|
|
73
76
|
|
|
74
77
|
```bash
|
|
75
78
|
AGENTACTA_SESSIONS_PATH=/path/to/sessions agentacta
|
|
76
79
|
```
|
|
77
80
|
|
|
78
|
-
##
|
|
81
|
+
## Core features
|
|
79
82
|
|
|
80
83
|
### Search
|
|
81
|
-
|
|
84
|
+
|
|
85
|
+
SQLite FTS5 full-text search with filters for message type (messages, tool calls, results) and role (user, assistant).
|
|
86
|
+
|
|
87
|
+
Suggestions come from your own dataset: top tools, common topics, frequently touched files.
|
|
82
88
|
|
|
83
89
|
### Sessions
|
|
84
|
-
|
|
90
|
+
|
|
91
|
+
Browse indexed sessions with auto-generated summaries, token splits (input/output), and model details. Click into any session to see the full event history.
|
|
92
|
+
|
|
93
|
+
Session types get tagged so noisy categories are easier to spot (cron, sub-agent, heartbeat).
|
|
85
94
|
|
|
86
95
|
### Timeline
|
|
87
|
-
|
|
96
|
+
|
|
97
|
+
Pick a date, see everything that happened, newest first. Today's view updates live as new events come in.
|
|
88
98
|
|
|
89
99
|
### File Activity
|
|
90
|
-
|
|
100
|
+
|
|
101
|
+
See what files were touched, how often, and by which sessions.
|
|
102
|
+
|
|
103
|
+
Sort by recency, frequency, or session count. Filter by extension. Group by directory. Click any file to see which sessions touched it.
|
|
91
104
|
|
|
92
105
|
### Export
|
|
93
|
-
Download any session or search results as Markdown or JSON. Great for sharing, auditing, or archiving.
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
Export sessions or search results as Markdown or JSON.
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
Useful for handoffs, incident writeups, and audit archives.
|
|
98
110
|
|
|
99
|
-
|
|
111
|
+
## How it works
|
|
100
112
|
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
AgentActa parses JSONL session files (OpenClaw, Claude Code, Codex CLI), then indexes events into local SQLite with FTS5.
|
|
114
|
+
|
|
115
|
+
The UI is a single-page app served by a lightweight Node HTTP server.
|
|
116
|
+
|
|
117
|
+
No framework build pipeline. Minimal moving parts.
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
Session JSONL files -> SQLite + FTS5 index -> HTTP API -> Web UI
|
|
103
121
|
```
|
|
104
122
|
|
|
105
|
-
|
|
123
|
+
Everything stays on your machine.
|
|
106
124
|
|
|
107
125
|
## Configuration
|
|
108
126
|
|
|
109
|
-
On first run, AgentActa creates
|
|
127
|
+
On first run, AgentActa creates:
|
|
128
|
+
- `~/.config/agentacta/config.json`
|
|
129
|
+
- or `agentacta.config.json` in current directory (if present)
|
|
130
|
+
|
|
131
|
+
Default config:
|
|
110
132
|
|
|
111
133
|
```json
|
|
112
134
|
{
|
|
@@ -118,85 +140,82 @@ On first run, AgentActa creates a config file with sensible defaults at `~/.conf
|
|
|
118
140
|
}
|
|
119
141
|
```
|
|
120
142
|
|
|
121
|
-
### Storage
|
|
143
|
+
### Storage modes
|
|
122
144
|
|
|
123
|
-
-
|
|
124
|
-
-
|
|
145
|
+
- `reference` (default): index parsed events in SQLite, keep source JSONL on disk. Lightweight.
|
|
146
|
+
- `archive`: store full JSONL in SQLite. Sessions survive even if original files are deleted. Uses more disk.
|
|
125
147
|
|
|
126
|
-
### Environment
|
|
148
|
+
### Environment variables
|
|
127
149
|
|
|
128
150
|
| Variable | Default | Description |
|
|
129
151
|
|---|---|---|
|
|
130
152
|
| `PORT` | `4003` | Server port |
|
|
131
|
-
| `AGENTACTA_HOST` | `127.0.0.1` | Bind address
|
|
132
|
-
| `AGENTACTA_SESSIONS_PATH` |
|
|
133
|
-
| `AGENTACTA_DB_PATH` | `./agentacta.db` | Database
|
|
134
|
-
| `AGENTACTA_STORAGE` | `reference` |
|
|
135
|
-
| `AGENTACTA_PROJECT_ALIASES_JSON` | unset |
|
|
153
|
+
| `AGENTACTA_HOST` | `127.0.0.1` | Bind address |
|
|
154
|
+
| `AGENTACTA_SESSIONS_PATH` | auto-detected | Custom sessions directory |
|
|
155
|
+
| `AGENTACTA_DB_PATH` | `./agentacta.db` | Database path |
|
|
156
|
+
| `AGENTACTA_STORAGE` | `reference` | `reference` or `archive` |
|
|
157
|
+
| `AGENTACTA_PROJECT_ALIASES_JSON` | unset | Rename inferred project labels |
|
|
136
158
|
|
|
137
159
|
## API
|
|
138
160
|
|
|
139
|
-
AgentActa exposes a JSON API for programmatic access — useful for integrating search into your agent's workflow.
|
|
140
|
-
|
|
141
161
|
| Endpoint | Description |
|
|
142
162
|
|---|---|
|
|
143
|
-
| `GET /api/stats` |
|
|
144
|
-
| `GET /api/sessions` |
|
|
145
|
-
| `GET /api/sessions/:id` | Full session
|
|
146
|
-
| `GET /api/search?q=<query>` | Full-text search
|
|
147
|
-
| `GET /api/suggestions` |
|
|
148
|
-
| `GET /api/timeline?date=YYYY-MM-DD` |
|
|
149
|
-
| `GET /api/files` |
|
|
150
|
-
| `GET /api/export/session/:id?format=md` | Export session
|
|
163
|
+
| `GET /api/stats` | Session/message/tool/token totals |
|
|
164
|
+
| `GET /api/sessions` | Session list with metadata |
|
|
165
|
+
| `GET /api/sessions/:id` | Full session events |
|
|
166
|
+
| `GET /api/search?q=<query>` | Full-text search + filters |
|
|
167
|
+
| `GET /api/suggestions` | Search suggestions |
|
|
168
|
+
| `GET /api/timeline?date=YYYY-MM-DD` | Events for one day |
|
|
169
|
+
| `GET /api/files` | Touched-file inventory |
|
|
170
|
+
| `GET /api/export/session/:id?format=md` | Export one session |
|
|
171
|
+
| `GET /api/timeline/stream?after=<ts>` | SSE stream for live timeline updates |
|
|
172
|
+
| `POST /api/maintenance` | VACUUM + WAL checkpoint (returns size before/after) |
|
|
151
173
|
| `GET /api/export/search?q=<query>&format=md` | Export search results |
|
|
152
174
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Your AI agent can query AgentActa for better recall:
|
|
175
|
+
Agent integration example:
|
|
156
176
|
|
|
157
177
|
```javascript
|
|
158
|
-
const
|
|
159
|
-
const data = await
|
|
160
|
-
// Agent now has context from past sessions
|
|
178
|
+
const res = await fetch('http://localhost:4003/api/search?q=deployment+issue&limit=5');
|
|
179
|
+
const data = await res.json();
|
|
161
180
|
```
|
|
162
181
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Want to see what AgentActa looks like with data? Run with demo sessions:
|
|
182
|
+
## Demo mode
|
|
166
183
|
|
|
167
184
|
```bash
|
|
168
|
-
#
|
|
185
|
+
# seed demo data + run
|
|
169
186
|
npm run demo
|
|
170
187
|
|
|
171
|
-
#
|
|
188
|
+
# or split steps
|
|
172
189
|
node scripts/seed-demo.js
|
|
173
190
|
node index.js --demo
|
|
174
191
|
```
|
|
175
192
|
|
|
176
|
-
|
|
193
|
+
Demo mode creates 7 realistic sessions (weather app build path: scaffolding, API, frontend, debugging, deployment, tests, sub-agent task).
|
|
177
194
|
|
|
178
195
|
## Security
|
|
179
196
|
|
|
180
|
-
|
|
197
|
+
AgentActa binds to `127.0.0.1` by default.
|
|
181
198
|
|
|
182
|
-
|
|
199
|
+
If you expose it on a network, do it intentionally:
|
|
183
200
|
|
|
184
201
|
```bash
|
|
185
202
|
AGENTACTA_HOST=0.0.0.0 agentacta
|
|
186
203
|
```
|
|
187
204
|
|
|
188
|
-
|
|
205
|
+
**Important:** Session data can contain sensitive content (file snippets, API payloads, personal messages, tool args). There is no built-in auth yet, so only expose on trusted networks.
|
|
189
206
|
|
|
190
|
-
## Tech
|
|
207
|
+
## Tech stack
|
|
191
208
|
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
209
|
+
- Node.js (built-in `http`)
|
|
210
|
+
- `better-sqlite3` + SQLite FTS5
|
|
211
|
+
- Vanilla HTML/CSS/JS
|
|
212
|
+
- PWA support
|
|
196
213
|
|
|
197
214
|
## Privacy
|
|
198
215
|
|
|
199
|
-
|
|
216
|
+
No telemetry. No cloud sync. No external indexing service.
|
|
217
|
+
|
|
218
|
+
Your session history stays local.
|
|
200
219
|
|
|
201
220
|
## Compatibility
|
|
202
221
|
|
|
@@ -207,13 +226,15 @@ All data stays local. AgentActa runs entirely on your machine — no cloud servi
|
|
|
207
226
|
|
|
208
227
|
## Contributing
|
|
209
228
|
|
|
210
|
-
PRs welcome
|
|
229
|
+
PRs welcome.
|
|
230
|
+
|
|
231
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). If you’re adding a new agent format, start in `indexer.js`.
|
|
211
232
|
|
|
212
|
-
##
|
|
233
|
+
## Name
|
|
213
234
|
|
|
214
|
-
*Acta*
|
|
235
|
+
*Acta* is Latin for “things done.”
|
|
215
236
|
|
|
216
|
-
|
|
237
|
+
That’s the job here: keep a readable record of what your agents actually did.
|
|
217
238
|
|
|
218
239
|
## License
|
|
219
240
|
|
|
@@ -221,4 +242,4 @@ MIT
|
|
|
221
242
|
|
|
222
243
|
---
|
|
223
244
|
|
|
224
|
-
Built in Chicago by humans and agents
|
|
245
|
+
Built in Chicago by humans and agents.
|
package/db.js
CHANGED
|
@@ -54,6 +54,7 @@ function init(dbPath) {
|
|
|
54
54
|
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_start_time ON sessions(start_time DESC);
|
|
57
58
|
CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);
|
|
58
59
|
CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
|
|
59
60
|
CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
|
package/index.js
CHANGED
|
@@ -428,13 +428,70 @@ const server = http.createServer((req, res) => {
|
|
|
428
428
|
const date = query.date || (() => { const n = new Date(); return `${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,'0')}-${String(n.getDate()).padStart(2,'0')}`; })();
|
|
429
429
|
const from = new Date(date + 'T00:00:00').toISOString();
|
|
430
430
|
const to = new Date(date + 'T23:59:59.999').toISOString();
|
|
431
|
+
const limit = Math.min(parseInt(query.limit || '100', 10) || 100, 500);
|
|
432
|
+
const offset = Math.max(parseInt(query.offset || '0', 10) || 0, 0);
|
|
431
433
|
const events = db.prepare(
|
|
432
434
|
`SELECT e.*, s.summary as session_summary FROM events e
|
|
433
435
|
JOIN sessions s ON s.id = e.session_id
|
|
434
436
|
WHERE e.timestamp >= ? AND e.timestamp <= ?
|
|
435
|
-
ORDER BY e.timestamp DESC
|
|
436
|
-
|
|
437
|
-
|
|
437
|
+
ORDER BY e.timestamp DESC
|
|
438
|
+
LIMIT ? OFFSET ?`
|
|
439
|
+
).all(from, to, limit, offset);
|
|
440
|
+
const total = db.prepare(
|
|
441
|
+
`SELECT COUNT(*) as c FROM events e
|
|
442
|
+
WHERE e.timestamp >= ? AND e.timestamp <= ?`
|
|
443
|
+
).get(from, to).c;
|
|
444
|
+
json(res, { date, events, total, limit, offset, hasMore: offset + events.length < total });
|
|
445
|
+
}
|
|
446
|
+
else if (pathname === '/api/timeline/stream') {
|
|
447
|
+
res.writeHead(200, {
|
|
448
|
+
'Content-Type': 'text/event-stream',
|
|
449
|
+
'Cache-Control': 'no-cache',
|
|
450
|
+
'Connection': 'keep-alive',
|
|
451
|
+
'X-Accel-Buffering': 'no'
|
|
452
|
+
});
|
|
453
|
+
res.write(': connected\n\n');
|
|
454
|
+
|
|
455
|
+
let lastTs = query.after || new Date().toISOString();
|
|
456
|
+
let lastId = query.afterId || '';
|
|
457
|
+
|
|
458
|
+
const onUpdate = () => {
|
|
459
|
+
try {
|
|
460
|
+
const rows = db.prepare(
|
|
461
|
+
`SELECT e.*, s.summary as session_summary FROM events e
|
|
462
|
+
JOIN sessions s ON s.id = e.session_id
|
|
463
|
+
WHERE (e.timestamp > ?) OR (e.timestamp = ? AND e.id > ?)
|
|
464
|
+
ORDER BY e.timestamp ASC, e.id ASC`
|
|
465
|
+
).all(lastTs, lastTs, lastId);
|
|
466
|
+
if (rows.length) {
|
|
467
|
+
const tail = rows[rows.length - 1];
|
|
468
|
+
lastTs = tail.timestamp || lastTs;
|
|
469
|
+
lastId = tail.id || lastId;
|
|
470
|
+
res.write(`id: ${lastTs}:${lastId}\ndata: ${JSON.stringify(rows)}\n\n`);
|
|
471
|
+
}
|
|
472
|
+
} catch (err) {
|
|
473
|
+
console.error('Timeline SSE error:', err.message);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
sseEmitter.on('session-update', onUpdate);
|
|
478
|
+
|
|
479
|
+
const ping = setInterval(() => {
|
|
480
|
+
try { res.write(': ping\n\n'); } catch {}
|
|
481
|
+
}, 30000);
|
|
482
|
+
|
|
483
|
+
req.on('close', () => {
|
|
484
|
+
sseEmitter.off('session-update', onUpdate);
|
|
485
|
+
clearInterval(ping);
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
else if (pathname === '/api/maintenance') {
|
|
489
|
+
if (req.method !== 'POST') return json(res, { error: 'Method not allowed' }, 405);
|
|
490
|
+
const sizeBefore = getDbSize();
|
|
491
|
+
db.pragma('wal_checkpoint(TRUNCATE)');
|
|
492
|
+
db.exec('VACUUM');
|
|
493
|
+
const sizeAfter = getDbSize();
|
|
494
|
+
json(res, { ok: true, sizeBefore, sizeAfter });
|
|
438
495
|
}
|
|
439
496
|
else if (pathname === '/api/files') {
|
|
440
497
|
const limit = parseInt(query.limit) || 100;
|