opencode-skill-audit 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/README.md +93 -39
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  [![CI](https://github.com/DepickereSven/skill-audit/actions/workflows/ci.yml/badge.svg)](https://github.com/DepickereSven/skill-audit/actions/workflows/ci.yml)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![npm](https://img.shields.io/npm/v/opencode-skill-audit?logo=npm&logoColor=white&color=CB3837)](https://www.npmjs.com/package/opencode-skill-audit)
6
+ [![Claude Code](https://img.shields.io/badge/Claude_Code-supported-D97757?logo=claude&logoColor=white)](#claude-code)
7
+ [![Codex](https://img.shields.io/badge/Codex-supported-000000?logoColor=white)](#codex)
8
+ [![OpenCode](https://img.shields.io/badge/OpenCode-supported-FBBF24?logo=opencode&logoColor=white)](#opencode)
5
9
 
6
10
  Deterministic audit trail for [Claude Code](https://code.claude.com),
7
11
  [Codex](https://developers.openai.com/codex/) and [opencode](https://opencode.ai) sessions: which
@@ -29,7 +33,7 @@ with no command to run.
29
33
  You ask an agent to follow a skill. Did it? Reading the transcript to find out is slow, and asking
30
34
  another model to judge costs tokens and is itself non-deterministic.
31
35
 
32
- LLMs are not deterministic; hook events are. This plugin logs the facts exposed by each host's
36
+ LLMs are not deterministic. Hook events are. This plugin logs the facts exposed by each host's
33
37
  documented hook API:
34
38
 
35
39
  - **No LLM judging, no tokens.** Everything except the two in-session slash/skill commands runs
@@ -43,6 +47,7 @@ documented hook API:
43
47
 
44
48
  ## Contents
45
49
 
50
+ - [Why](#why)
46
51
  - [How it works](#how-it-works)
47
52
  - [Install](#install)
48
53
  - [Verify the install](#verify-the-install)
@@ -60,8 +65,9 @@ documented hook API:
60
65
  `PostToolUse` hooks capture skill-tool calls and file edits. On Codex, a `UserPromptSubmit` hook
61
66
  also captures explicit `$skill-name` references, and `apply_patch` payloads are expanded into one
62
67
  file event per path. On opencode a plugin does the same job through the `tool.execute.after` hook.
63
- Events are appended as NDJSON to `~/.claude/skill-audit/<session_id>.ndjson`; override the location
64
- with `SKILL_AUDIT_DIR`.
68
+ Events are appended as NDJSON to `~/.claude/skill-audit/<session_id>.ndjson`. All three hosts
69
+ write to that one directory on purpose, so any viewer can read any host's session. Override the
70
+ location with `SKILL_AUDIT_DIR`.
65
71
 
66
72
  ```text
67
73
  Claude Code / Codex ──hooks───▶ logger.sh ──┐
@@ -111,12 +117,14 @@ Invoke the bundled Codex skill with `$skill-audit`.
111
117
  opencode plugin opencode-skill-audit --global
112
118
  ```
113
119
 
114
- Restart opencode so the plugin loads. It registers two things: a server hook that logs
115
- `skill`, `edit`, `write` and `apply_patch` tool calls, and a sidebar section that renders the
116
- current session's timeline live.
120
+ The plugin is published on npm as
121
+ [`opencode-skill-audit`](https://www.npmjs.com/package/opencode-skill-audit).
117
122
 
123
+ Restart opencode so the plugin loads. It registers two things: a server hook that logs
124
+ `skill`, `edit`, `write`, `multiedit`, `apply_patch` and `patch` tool calls, and a sidebar section
125
+ that renders the current session's timeline live.
118
126
 
119
- ![OpenCode Image](docs/opencode.png)
127
+ ![The opencode sidebar rendering a live skill-audit timeline beside a conversation](docs/opencode.png)
120
128
 
121
129
  Click the header to collapse the section, or a skill row to fold its files away.
122
130
 
@@ -146,7 +154,7 @@ ln -sf ~/.codex/plugins/cache/*/skill-audit/*/scripts/skill-audit ~/.local/bin/s
146
154
 
147
155
  You can also clone this repository and link `scripts/skill-audit` directly.
148
156
 
149
- `~/.local/bin` is not on every system's `PATH`. Check with `command -v skill-audit`; if it prints
157
+ `~/.local/bin` is not on every system's `PATH`. Check with `command -v skill-audit`. If it prints
150
158
  nothing, add the directory in your shell profile:
151
159
 
152
160
  ```bash
@@ -182,7 +190,8 @@ installing.
182
190
  - Claude Code: `/skill-audit`
183
191
  - Codex: `$skill-audit`
184
192
  - opencode: watch the sidebar section appear
185
- 2. Check that a log exists and is growing:
193
+ 2. Check that a log exists and is growing. Look in `~/.claude/skill-audit`, or in the directory
194
+ you set as `SKILL_AUDIT_DIR`:
186
195
 
187
196
  ```bash
188
197
  ls -la ~/.claude/skill-audit/
@@ -195,7 +204,7 @@ installing.
195
204
  skill-audit status # counts + recent timeline for the newest session
196
205
  ```
197
206
 
198
- If `list` prints `no session logs in ...`, nothing was written go to
207
+ If `list` prints `no session logs in ...`, nothing was written. Go to
199
208
  [Troubleshooting](#troubleshooting).
200
209
 
201
210
  ## Usage
@@ -204,16 +213,16 @@ If `list` prints `no session logs in ...`, nothing was written — go to
204
213
  |----------------------------|------------------------------------------------------------------|-----------:|
205
214
  | `skill-audit status [sid]` | Compact counts and recent timeline | 0 |
206
215
  | `skill-audit report [sid]` | Full timeline | 0 |
207
- | `skill-audit watch [sid]` | Live view, refreshed every two seconds; `q` quits | 0 |
216
+ | `skill-audit watch [sid]` | Live view, refreshed every two seconds. `q` quits | 0 |
208
217
  | `skill-audit list` | Recent sessions | 0 |
209
218
  | `skill-audit --help` | Usage summary | 0 |
210
- | `! skill-audit status` | Run inside a Claude Code session; queues while the model is busy | 0 |
211
- | opencode sidebar | Live timeline beside the conversation; no command to run | 0 |
219
+ | `! skill-audit status` | Run inside a Claude Code session. Queues while the model is busy | 0 |
220
+ | opencode sidebar | Live timeline beside the conversation. No command to run | 0 |
212
221
  | `/skill-audit` | Show the report inside Claude Code | Model turn |
213
222
  | `$skill-audit` | Show the report inside Codex | Model turn |
214
223
 
215
224
  `status`, `report` and `watch` all take an optional session ID. Without one they use the most
216
- recently modified log, which is the wrong session if you run several at once get the ID from
225
+ recently modified log, which is the wrong session if you run several at once. Get the ID from
217
226
  `skill-audit list` and pass it explicitly.
218
227
 
219
228
  The `⚠ edits outside skill context` counter is the compliance red flag: files changed while no
@@ -231,13 +240,13 @@ One NDJSON file per session, one event per line, appended in chronological order
231
240
  | Field | On | Meaning |
232
241
  |-----------|---------|-------------------------------------------------------------------------------|
233
242
  | `ts` | both | UTC timestamp, `YYYY-MM-DDThh:mm:ssZ` |
234
- | `kind` | both | `skill` or `file` the only two event kinds |
243
+ | `kind` | both | `skill` or `file`, the only two event kinds |
235
244
  | `cwd` | both | Session working directory as reported by the host |
236
245
  | `name` | `skill` | Skill identifier, e.g. `superpowers:test-driven-development` |
237
- | `args` | `skill` | Arguments passed to the skill tool; empty string when there were none |
246
+ | `args` | `skill` | Arguments passed to the skill tool, empty string when there were none |
238
247
  | `source` | `skill` | `tool` for an observed skill tool call, `prompt` for a Codex `$skill-name` |
239
- | `turn_id` | `skill` | Codex turn identifier; present only when the host supplies one |
240
- | `tool` | `file` | Tool that made the edit: `Edit`, `Write`, `NotebookEdit`, `apply_patch`… |
248
+ | `turn_id` | `skill` | Codex turn identifier, present only when the host supplies one |
249
+ | `tool` | `file` | Tool that made the edit: `Edit`, `Write`, `MultiEdit`, `apply_patch`, etc. |
241
250
  | `path` | `file` | Absolute path of the changed file (relative paths are resolved against `cwd`) |
242
251
 
243
252
  Within a Codex turn, a repeated `(turn_id, name)` skill pair is written once, so a skill named
@@ -257,7 +266,7 @@ find ~/.claude/skill-audit -name '*.ndjson' -mtime +30 -delete
257
266
  session keeps running without them.
258
267
  - Confirm the plugin is installed: `claude plugin list`, `codex plugin list`, or check the
259
268
  `plugin` array in `~/.config/opencode/opencode.json`.
260
- - On Codex, hooks only run after you review and trust them accept the prompt.
269
+ - On Codex, hooks only run after you review and trust them, so accept the prompt.
261
270
  - Is `jq` installed? `logger.sh` exits silently without it, by design: the hook must never block a
262
271
  session. Check with `command -v jq`.
263
272
 
@@ -269,13 +278,13 @@ recently modified log, which is the wrong one when sessions run in parallel. Run
269
278
  and pass the ID: `skill-audit report <sid>`.
270
279
 
271
280
  **The CLI finds nothing but the logs exist.** Writer and viewer disagree about the directory. If
272
- you set `SKILL_AUDIT_DIR` for the host, export it for your shell too otherwise the CLI looks in
281
+ you set `SKILL_AUDIT_DIR` for the host, export it for your shell too. Otherwise the CLI looks in
273
282
  `~/.claude/skill-audit`.
274
283
 
275
- **`skill-audit: command not found`.** The symlink is missing or its directory is not on `PATH`;
276
- see [CLI on your PATH](#cli-on-your-path-recommended).
284
+ **`skill-audit: command not found`.** The symlink is missing or its directory is not on `PATH`.
285
+ See [CLI on your PATH](#cli-on-your-path-recommended).
277
286
 
278
- **A skill ran but is missing from the timeline.** Expected in some cases — see
287
+ **A skill ran but is missing from the timeline.** Expected in some cases. See
279
288
  [Honest limitations](#honest-limitations).
280
289
 
281
290
  ## Honest limitations
@@ -283,19 +292,19 @@ see [CLI on your PATH](#cli-on-your-path-recommended).
283
292
  - **Invocation is not compliance.** The log proves that a skill was explicitly selected or exposed
284
293
  as a tool event, not that the result followed every instruction.
285
294
  - **Codex automatic skill loading is not a hook event today.** Explicit `$skill-name` references
286
- are captured; skills that Codex chooses automatically are not. No transcript parsing is used to
295
+ are captured. Skills that Codex chooses automatically are not. No transcript parsing is used to
287
296
  fill that gap.
288
297
  - **Prompt-sourced entries are syntax-level evidence.** Codex supplies plain prompt text to the
289
298
  hook, so a lower-case dollar-prefixed token can be logged even if it does not resolve to an
290
299
  installed skill. The NDJSON `source: "prompt"` field distinguishes these entries.
291
- - **Only observable file tools are captured.** Claude `Edit`/`Write`/`NotebookEdit`, Codex
292
- `apply_patch`, and opencode `edit`/`write`/`apply_patch` edits are logged. Files created
293
- indirectly by shell commands are not visible as separate file events.
300
+ - **Only observable file tools are captured.** Claude `Edit`/`Write`/`MultiEdit`/`NotebookEdit`,
301
+ Codex `apply_patch`, and opencode `edit`/`write`/`multiedit`/`apply_patch`/`patch` edits are
302
+ logged. Files created indirectly by shell commands are not visible as separate file events.
294
303
  - **opencode agents and subagents are not logged.** They have no equivalent on the other two
295
304
  hosts, so logging them would add an event kind only one host can emit. The audit keeps one data
296
305
  model across all three.
297
306
  - **Session-start injected skills** are context, not skill tool calls, and do not appear.
298
- - **Concurrent sessions:** the newest-log default can pick the wrong session; pass the session ID
307
+ - **Concurrent sessions:** the newest-log default can pick the wrong session. Pass the session ID
299
308
  explicitly after using `skill-audit list`.
300
309
 
301
310
  ## Uninstall
@@ -312,7 +321,7 @@ Codex:
312
321
  codex plugin remove skill-audit@depickeresven-skill-audit
313
322
  ```
314
323
 
315
- opencode has no removal subcommand delete the `"opencode-skill-audit"` entry from the `plugin`
324
+ opencode has no removal subcommand. Delete the `"opencode-skill-audit"` entry from the `plugin`
316
325
  array in `~/.config/opencode/opencode.json` (or the project-local `opencode.json`), and remove the
317
326
  skill symlink if you made one:
318
327
 
@@ -327,17 +336,23 @@ rm -f ~/.local/bin/skill-audit
327
336
  rm -rf ~/.claude/skill-audit
328
337
  ```
329
338
 
330
- ## Requirements
331
-
332
- - macOS or Linux
333
- - `bash` and `jq` for the CLI viewer and the Claude Code / Codex hooks
334
- - opencode `>= 1.14` for the plugin and its sidebar
335
-
336
339
  ## Development
337
340
 
338
341
  The hooks and the CLI viewer are plain bash (`scripts/`) with no build step. The opencode plugin
339
342
  and sidebar are TypeScript (`src/`) built with [Bun](https://bun.sh).
340
343
 
344
+ | Path | What |
345
+ |-------------------|----------------------------------------------------------------------------|
346
+ | `scripts/` | `logger.sh` hook target, the `skill-audit` CLI, `sync-versions.mjs` |
347
+ | `src/` | opencode plugin (`index.ts`), sidebar (`tui.ts`), shared log and view code |
348
+ | `test/` | Bun tests, fixtures, and `test/format-contract.sh` |
349
+ | `.claude-plugin/` | Claude Code plugin manifest and marketplace entry |
350
+ | `.codex-plugin/` | Codex plugin manifest |
351
+ | `.agents/` | Codex marketplace manifest |
352
+ | `skills/` | The `skill-audit` skill used by Codex and opencode |
353
+ | `commands/` | The `/skill-audit` slash command for Claude Code |
354
+ | `.opencode/` | Local opencode workspace for testing the plugin during development |
355
+
341
356
  ```bash
342
357
  bun install
343
358
  bun run check # format:check + lint + typecheck (src and test) + tests
@@ -355,12 +370,51 @@ bun run build # dist/index.js (plugin) and dist/tui.js (sidebar)
355
370
  | `bun run sync:versions` | Rewrite the plugin manifests from `package.json` |
356
371
 
357
372
  Tests live in `test/`. `test/format-contract.sh` pins the rendered CLI output against fixtures, so
358
- a change to the timeline format has to be updated there deliberately that output is the contract
373
+ a change to the timeline format has to be updated there deliberately. That output is the contract
359
374
  the sidebar and any third-party viewer rely on.
360
375
 
361
- Version bumps go through `npm version`, which runs `scripts/sync-versions.mjs` and stages
362
- `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` alongside it. CI (`.github/workflows/ci.yml`)
363
- runs `bun run check` plus a manifest-version job on every push and pull request.
376
+ ### Releasing
377
+
378
+ Two workflows, chained.
379
+
380
+ `.github/workflows/ci.yml` runs four jobs: it checks that both plugin manifests carry the same
381
+ version as `package.json`, runs `bun run check` on Bun 1.2.0 and on the latest Bun, builds the
382
+ bundles, and packs the npm tarball to confirm it ships every entry point `package.json` exports.
383
+ It runs on pull requests and on pushes to `main`, not on every branch, so a pull request is never
384
+ tested twice.
385
+
386
+ `.github/workflows/publish.yml` starts only when a CI run on `main` finishes successfully. It
387
+ checks out that exact commit and asks npm whether the version in `package.json` already exists:
388
+
389
+ - **Already on npm.** Nothing is released. This is what an ordinary push to `main` does.
390
+ - **Not on npm.** It publishes with provenance over OIDC, tags the commit, and opens a GitHub
391
+ release with notes generated from the merged commits.
392
+
393
+ So a version bump landing on `main` *is* the release, and it can only happen after CI has gone
394
+ green on that commit.
395
+
396
+ To cut one:
397
+
398
+ ```bash
399
+ npm version patch --no-git-tag-version # or minor / major
400
+ git commit -am "chore: release $(node -p 'require("./package.json").version')"
401
+ git push
402
+ ```
403
+
404
+ `--no-git-tag-version` matters. The workflow creates the `v<version>` tag itself, and it aborts
405
+ the release if that tag already exists while npm has never seen the version. The bump still runs
406
+ `scripts/sync-versions.mjs` and stages `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json`
407
+ alongside it, keeping both manifests on the same version as `package.json`, which CI fails the
408
+ build over if they ever drift.
409
+
410
+ Use the publish workflow's manual trigger (`workflow_dispatch`) with *dry run* enabled to rehearse
411
+ a publication without releasing anything.
412
+
413
+ ## Requirements
414
+
415
+ - macOS or Linux
416
+ - `bash` and `jq` for the CLI viewer and the Claude Code / Codex hooks
417
+ - opencode `>= 1.14` for the plugin and its sidebar
364
418
 
365
419
  ## License
366
420
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skill-audit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Audit trail of skill invocations and file changes, with a live timeline in the opencode sidebar",
5
5
  "type": "module",
6
6
  "license": "MIT",