spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

sec-default: collector records continue past the user tierBrowse files
poteat authored 27 days ago parent 7779afb · commit 3bcaee1f5d70
5 changed files+56 -2compared with 7779afb
Mmods/sec-default/README.md
Mmods/sec-default/hooks/register.ts
Mmods/sec-default/tests/fixtures/index.ts
Amods/sec-default/tests/fixtures/withholding.ts
Mmods/sec-default/tests/register.test.ts
@@ -26,6 +26,7 @@
2626 | `classic.*` | Continue past the user tier: the organization's settings hooks see the engine's input and their answer stands. |
2727 | `prompt.section`, `prompt.context`, `skill.prompt`, `attribution.text` | Continue past the user tier: managed CLAUDE.md, rules and policy skills reach the model as written. A person's plugins keep `prompt.submit` and its additive context. |
2828 | `settings.read` | Continue past the user tier: no user hook rewrites what any caller reads as settings, this plugin's own policy reads included. |
29+| `telemetry.log` `{ to: "collector" }` | Continue past the user tier: no plugin a person installed drops or rewrites a record on its way to the collector the organization configured. The organization's own plugins, in `prepend` and `append`, still may. |
2930 | `tool.describe`, `command.describe`, `agent.offer`, `agent.spawn` | When the subject's pinned `e.provider.tier` is `prepend` or `append` (a policy-installed plugin, the managed folder, a policy MCP server), continue past the user tier; a subject provided by `user`, `builtin` or `core` passes. |
3031 | `tool.register` | A caller in `prepend` or `append` continues past the user tier. A `user`-tier caller is refused by name while managed settings hold `allowedMcpServers` (set at all, empty included); otherwise it passes. |
3132 | `tool.list` | The tools of the organization's managed MCP servers are listed as the organization's tiers listed them; every other tool as the user tier left it. With no policy to read, or a refusal from either listing, the organization's listing stands whole. |
@@ -34,8 +35,9 @@
3435 ## What it hooks
3536
3637 `classic.*`, `prompt.section`, `prompt.context`, `skill.prompt`,
37-`attribution.text`, `settings.read`, `tool.describe`, `command.describe`,
38-`agent.offer`, `agent.spawn`, `tool.register`, `tool.list`.
38+`attribution.text`, `settings.read`, `telemetry.log` (the collector's
39+stream), `tool.describe`, `command.describe`, `agent.offer`, `agent.spawn`,
40+`tool.register`, `tool.list`.
3941
4042 ## What it calls on `$`
4143
@@ -26,6 +26,10 @@
2626
2727 on('settings.read', ($, e, next) => next.to(e, 'append'))
2828
29+ on('telemetry.log', { to: 'collector' }, ($, e, next) =>
30+ next.to(e, 'append'),
31+ )
32+
2933 on('tool.describe', ($, e, next) => pastUsers(e, next))
3034 on('command.describe', ($, e, next) => pastUsers(e, next))
3135 on('agent.offer', ($, e, next) => pastUsers(e, next))
@@ -28,5 +28,6 @@
2828 export * from './tools-command.js'
2929 export * from './tools-registered.js'
3030 export * from './user-reachable-providers.js'
31+export * from './withholding.js'
3132
3233 export * as default from '.'
@@ -1,0 +1,16 @@
1+import type { Plugin } from 'claude-code/testing'
2+
3+/**
4+ * A plugin the person installed that keeps the collector record named
5+ * `withheld` from the collector and marks every other one `edited`.
6+ */
7+export const withholding: Plugin = {
8+ name: 'withholding',
9+ register(on) {
10+ on('telemetry.log', { to: 'collector' }, ($, e, next) =>
11+ e.to === 'collector' && e.event !== 'withheld'
12+ ? next({ ...e, attributes: { ...e.attributes, edited: true } })
13+ : { deny: 'kept from the collector' },
14+ )
15+ },
16+}
@@ -138,6 +138,37 @@
138138 )
139139
140140 test(
141+ 'a collector record passes over the plugins the person installed',
142+ { plugins: [Fixtures.withholding] },
143+ async ($, on) => {
144+ const reached: unknown[] = []
145+ on('telemetry.log', { to: 'collector' }, ($, e) => {
146+ reached.push([e.event, e.to === 'collector' && e.attributes.edited])
147+
148+ return { value: undefined }
149+ })
150+
151+ await $.telemetry.log({
152+ to: 'collector',
153+ event: 'kept',
154+ attributes: {},
155+ loggedAt: '2026-09-26T10:00:00.000Z',
156+ })
157+ await $.telemetry.log({
158+ to: 'collector',
159+ event: 'withheld',
160+ attributes: {},
161+ loggedAt: '2026-09-26T10:00:01.000Z',
162+ })
163+
164+ expect(reached).toEqual([
165+ ['kept', undefined],
166+ ['withheld', undefined],
167+ ])
168+ },
169+ )
170+
171+ test(
141172 "a user plugin's rewrite of policy is skipped for every other reader",
142173 {
143174 plugins: [