happenin 0.4.0 → 0.6.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.
@@ -0,0 +1,175 @@
1
+ ---
2
+ name: happenin
3
+ description: Use the happenin CLI to capture, query, and dashboard Cursor and Claude Code agent events from the local machine.
4
+ allowed-tools:
5
+ - exec
6
+ - read
7
+ - grep
8
+ ---
9
+
10
+ # Using happenin
11
+
12
+ `happenin` is a local CLI that captures Cursor and Claude Code hook events into a SQLite database and serves a real-time dashboard. All data stays on the user's machine.
13
+
14
+ This is a cross-agent skill. Any agent that supports `SKILL.md` files can load it.
15
+
16
+ ## Install
17
+
18
+ If `happenin` is not installed, install the CLI first:
19
+
20
+ ```bash
21
+ npm install -g happenin
22
+ ```
23
+
24
+ Or run from source:
25
+
26
+ ```bash
27
+ nub install
28
+ nub run build
29
+ ```
30
+
31
+ The Cursor and Claude Code plugins bundle this skill, so installing the plugin is enough for those clients. For any other agent, add it from the repository:
32
+
33
+ ```bash
34
+ npx skills add YogliB/happenin --skill happenin
35
+ ```
36
+
37
+ For a global install, add the `-g` flag. You can also copy `skills/happenin/SKILL.md` from this repository into your agent's skills directory.
38
+
39
+ ## `happenin install [--cursor] [--claude]`
40
+
41
+ Shows the supported plugin setup for Cursor and Claude Code. The packaged hooks use `npx -y happenin record`, so the normal setup does not edit user configuration. Use `--cursor` or `--claude` to show one client only.
42
+
43
+ Migrating from a pre-plugin install? Remove the old `happenin record` entries from `~/.cursor/hooks.json` and `~/.claude/settings.json` by hand (one-time step). Keep every unrelated hook.
44
+
45
+ ## `happenin record <source> [event]`
46
+
47
+ The hook target. It reads a JSON payload from stdin, writes it to `~/.happenin/happenin.db`, and prints the required response the agent expects.
48
+
49
+ - `<source>` — `cursor` or `claude`.
50
+ - `[event]` — only required for Claude; Cursor payloads include `hook_event_name`.
51
+
52
+ Record an event directly by piping JSON to stdin:
53
+
54
+ ```bash
55
+ echo '{"hook_event_name":"sessionStart","sessionId":"abc123","projectPath":"/path/to/project"}' | happenin record cursor
56
+
57
+ echo '{"sessionId":"abc123","projectPath":"/path/to/project"}' | happenin record claude SessionStart
58
+ ```
59
+
60
+ ### Field extraction
61
+
62
+ `record` extracts common fields from the raw payload before storing it:
63
+
64
+ | Stored field | Payload keys searched (first match wins) |
65
+ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | `event` | `hook_event_name` (Cursor only); otherwise the second CLI argument |
67
+ | `sessionId` | `sessionId`, `session_id`; for `subagentStart` also `parent_conversation_id`, `conversation_id` |
68
+ | `happenedAt` | `happenedAt`, `timestamp`, `happened_at`, `time`, `ts`, `createdAt`, `created_at` |
69
+ | `projectPath` | `projectPath`, `cwd`, `project_path`, `workspaceRoot`, `workspaceRoots`, `workspace_roots`, `workspace_root`, `workspace_path` |
70
+ | `filePath` | `filePath`, `file_path`, `path` at the top level; otherwise `tool_input.file_path`/`notebook_path`/`path` for `Read`/`Edit`/`Write`/`MultiEdit`/`NotebookEdit` |
71
+ | `toolName` | `toolName`, `tool_name`, `tool` |
72
+ | `skillName` | `tool_input.skill`, only when `toolName` is `Skill` |
73
+ | `client` | `client`; defaults to `cursor` or `claude_code` |
74
+ | `subagentId` | `subagent_id` (Cursor `subagentStart` only) |
75
+ | `subagentType` | `subagent_type` (Cursor `subagentStart` only) |
76
+ | `transcriptPath` | `transcript_path` (Cursor `subagentStart` only) |
77
+
78
+ For Cursor `subagentStart` payloads, `parent_conversation_id` and `conversation_id` are used as `sessionId` fallbacks so the subagent event groups with the main Cursor session. `conversation_id` and `parent_conversation_id` are not used as `sessionId` fallbacks for any other event.
79
+
80
+ The entire raw JSON is always stored in the `payload` column, so any field not extracted is still available.
81
+
82
+ ### Required responses for blocking hooks
83
+
84
+ If the event is a blocking hook, `record` prints a JSON response to stdout so the agent can continue:
85
+
86
+ - **Cursor**
87
+ - `beforeSubmitPrompt` → `{"continue":true}`
88
+ - `preToolUse`, `beforeShellExecution`, `beforeMCPExecution`, `beforeReadFile`, `subagentStart` → `{"permission":"allow"}`
89
+ - **Claude**
90
+ - `UserPromptSubmit`, `UserPromptExpansion` → `{"continue":true}`
91
+ - `PreToolUse`, `PermissionRequest`, `SubagentStart`, `SubagentStop`, `TaskCreated`, `TaskCompleted`, `Stop`, `WorktreeCreate`, `WorktreeRemove` → `{"decision":"approve"}`
92
+
93
+ Observer hooks produce no stdout output.
94
+
95
+ `record` is fail-open: if the database is locked by a concurrent operation (for example, the one-time backfill after an upgrade), it still prints the expected response for a blocking hook, but the event is not written to the database.
96
+
97
+ ## `happenin import [--force]`
98
+
99
+ Imports existing transcripts:
100
+
101
+ - Claude Code JSONL from `~/.claude/projects/<project>/<session>.jsonl`. Each `tool_use` block in an
102
+ assistant message is recorded as its own event with `toolName` set (and `filePath` for
103
+ `Read`/`Edit`/`Write`/`MultiEdit`/`NotebookEdit`, `skillName` for `Skill` calls), so tool usage,
104
+ skills used, and files touched are queryable. `happenin sessions` also lists `tools`, `skills`, and
105
+ `files` per session, and the dashboard's session detail view shows the same three lists.
106
+ - Cursor `prompt_history.json` and `meta.json` from `~/.cursor/chats/<hash>/<session>/`
107
+
108
+ `store.db` is skipped because it is encrypted.
109
+
110
+ After upgrading, run `happenin import` or `happenin dashboard` once to migrate the database schema and backfill existing Cursor `subagentStart` rows with `subagentId`, `subagentType`, `transcriptPath`, and the correct `sessionId`.
111
+
112
+ Files are only re-parsed when their modification time changes. Pass `--force` to clear that tracking and re-import every discovered file from scratch — use this after upgrading `happenin` to pick up extraction changes for transcripts that were already imported.
113
+
114
+ ## `happenin query [options]`
115
+
116
+ Query captured events and print them as JSON, JSONL, or a summary.
117
+
118
+ ```bash
119
+ happenin query --source cursor --event sessionStart --limit 10
120
+ happenin query --q "subagent" --format jsonl
121
+ happenin query --session abc123 --format summary
122
+ ```
123
+
124
+ - `--source <source>` — filter by `cursor` or `claude`.
125
+ - `--event <event>` — filter by event name.
126
+ - `--session <id>` — filter by session id (partial match).
127
+ - `--q <text>` — search event payloads.
128
+ - `--since <id>` — events with an id greater than `<id>`.
129
+ - `--limit <n>` — maximum rows (default `100`).
130
+ - `--offset <n>` — skip the first `<n>` rows.
131
+ - `--format <json|jsonl|summary>` — output format (default `json`).
132
+ - `--db <path>` — database path.
133
+
134
+ ## `happenin sessions [options]`
135
+
136
+ Summarize recorded events grouped by session. Useful for reviewing activity across many sessions and event volumes.
137
+
138
+ ```bash
139
+ happenin sessions --limit 10
140
+ happenin sessions --source cursor --format jsonl
141
+ happenin sessions --session abc123 --format summary
142
+ ```
143
+
144
+ - `--source <source>` — filter by `cursor` or `claude`.
145
+ - `--event <event>` — filter by event name.
146
+ - `--session <id>` — filter by session id (partial match).
147
+ - `--q <text>` — search event payloads.
148
+ - `--since <id>` — events with an id greater than `<id>`.
149
+ - `--limit <n>` — maximum sessions (default `100`).
150
+ - `--offset <n>` — skip the first `<n>` sessions.
151
+ - `--format <json|jsonl|summary>` — output format (default `json`).
152
+ - `--db <path>` — database path.
153
+
154
+ ## `happenin dashboard [--port <port>] [--no-open] [--silent]`
155
+
156
+ Starts the local HTTP dashboard. Default port is `8765`.
157
+
158
+ ```bash
159
+ happenin dashboard
160
+ happenin dashboard --port 9000 --no-open
161
+ ```
162
+
163
+ Use `--no-open` or `--silent` to start without launching the browser.
164
+
165
+ ## Environment variables
166
+
167
+ - `HAPPENIN_DB` — override the SQLite database path. Default: `~/.happenin/happenin.db`.
168
+ - `NO_COLOR` — disable colored help output.
169
+
170
+ ## When to use
171
+
172
+ - To start recording events from an existing agent setup, run `happenin install`, add the plugin it prints to the agent, and restart the agent.
173
+ - To record a one-off event manually, pipe JSON to `happenin record <source> [event]`.
174
+ - To backfill existing agent transcripts, run `happenin import`.
175
+ - To inspect events, run `happenin query`, `happenin sessions`, or start `happenin dashboard`.