Zero-auth, zero-inference account-cell broker feasibility spike

This is a zero-auth, zero-inference, non-production fixture for docs/claude-account-cell-feasibility.md. It targets the exact Claude Code 2.1.292 binary bundled through @anthropic-ai/claude-agent-sdk@0.3.292.
The retained Mod demonstrates a broker-only model surface:
Read, Write, Edit, Bash, search, agent, web, MCP, and other account-cell tools are not delegated to core;$.fs, $.http, $.model, $.tool.call, $.agent.spawn, or $.prompt.submit call;The fake Worker/account/Run model demonstrates workspace and symlink containment, shell namespace separation on macOS, exact pre-bound routing, native-session ownership, generation and Run-recovery fencing, logout quiescence, restart/cleanup separation, a one-way network topology, and serialized canonical fake credential mutation. The credential fixture is an explicit canary and is not a provider credential.
Using the exact retained Claude Code binary:
.pi/tmp/claude-mods-reassessment/packages/darwin/claude \
plugin validate spikes/claude-account-cell-feasibility
workers/bun/node_modules/.bin/tsc \
-p spikes/claude-account-cell-feasibility/tsconfig.json --noEmit
.pi/tmp/claude-mods-reassessment/packages/darwin/claude \
plugin test spikes/claude-account-cell-feasibility
workers/bun/node_modules/.bin/tsc \
-p spikes/claude-account-cell-feasibility/proof-tsconfig.json --noEmit
bun test ./spikes/claude-account-cell-feasibility/proof.check.ts
Expected results for the pinned fixture are 12 Mod tests and 12 fake architecture tests with no failures. claude plugin test uses mocked engine events and operations and does not sign in or contact a model.
The safe local startup sequence first sends a fixed synthetic stream-input message with shouldQuery: false, validates system/init and its zero-turn result, and only then sends /qe_account_cell_probe to the already validated Mod. With an empty disposable CLAUDE_CONFIG_DIR, --restricted, and an exact --tools list, both stages reported num_turns: 0, total_cost_usd: 0, empty modelUsage, the eight registered tools, and matching Mod/CLI session IDs while the process remained alive. Sending the slash command before proving that the Mod loaded is unsafe. The report records the exact evidence and production constraints.
This retained fixture does not itself implement ProviderAccount state, a real broker, Claude v4, a profile, authentication, or provider inference. The production generic broker, strict local protocol, cancellation/certainty, and physical two-SBX evidence now live in docs/workspace-tool-broker.md and the Worker/server implementation. Managed Mod integration and all provider behavior remain later gates; this spike stays a zero-auth research fixture.
hooks/register.ts 533 lines1import type {
2 EngineInterface,
3 Next,
4 PluginRegisterInput,
5 Register,
6 TurnStepInput,
7} from "claude-code";
8
9const PROTOCOL = "qe_claude_account_cell_feasibility_v1";
10const BRIDGE = "/opt/qe/bin/qe-account-cell-bridge";
11const MAX_BRIDGE_OUTPUT = 65_536;
12const MAX_OPERATION_INPUT = 1_048_576;
13
14const PREFIX = "mcp__qe-account-cell-feasibility__";
15const TOOLS = {
16 read: `${PREFIX}qe_workspace_read`,
17 list: `${PREFIX}qe_workspace_list`,
18 write: `${PREFIX}qe_workspace_write`,
19 edit: `${PREFIX}qe_workspace_edit`,
20 search: `${PREFIX}qe_workspace_search`,
21 shell: `${PREFIX}qe_run_shell`,
22 complete: `${PREFIX}qe_complete_step`,
23 attention: `${PREFIX}qe_request_human_assistance_and_wait`,
24} as const;
25const ALLOWED_TOOLS = new Set<string>(Object.values(TOOLS));
26
27type JsonObject = Record<string, unknown>;
28
29function object(value: unknown, label: string): JsonObject {
30 if (typeof value !== "object" || value === null || Array.isArray(value))
31 throw new Error(`${label} must be an object.`);
32 return value as JsonObject;
33}
34
35function boundedString(value: unknown, label: string, maximum: number): string {
36 if (typeof value !== "string" || value.length === 0 || value.length > maximum)
37 throw new Error(`${label} is invalid.`);
38 return value;
39}
40
41function optionalInteger(
42 value: unknown,
43 label: string,
44 minimum: number,
45 maximum: number,
46): number | undefined {
47 if (value === undefined) return undefined;
48 if (
49 typeof value !== "number" ||
50 !Number.isSafeInteger(value) ||
51 value < minimum ||
52 value > maximum
53 )
54 throw new Error(`${label} is invalid.`);
55 return value;
56}
57
58function workspacePath(value: unknown, label: string): string {
59 const path = boundedString(value, label, 4_096);
60 if (
61 path.startsWith("/") ||
62 path.includes("\\") ||
63 path.includes("\0") ||
64 path.split("/").some((segment) => segment === "..")
65 )
66 throw new Error(`${label} must remain relative to the Run workspace.`);
67 return path;
68}
69
70function boundedJson(value: unknown, label: string, maximum: number): string {
71 const encoded = JSON.stringify(value);
72 if (encoded === undefined || encoded.length > maximum)
73 throw new Error(`${label} is invalid or too large.`);
74 return encoded;
75}
76
77function parseBridgeOutput(text: string): JsonObject {
78 if (text.length > MAX_BRIDGE_OUTPUT)
79 throw new Error("QE broker output exceeded the spike limit.");
80 return object(JSON.parse(text), "QE broker output");
81}
82
83function parseEffort(value: string): NonNullable<TurnStepInput["effort"]> {
84 switch (value) {
85 case "low":
86 case "medium":
87 case "high":
88 case "xhigh":
89 case "max":
90 return value;
91 default:
92 throw new Error("QE_CLAUDE_EFFORT is invalid.");
93 }
94}
95
96async function runBridge(
97 $: EngineInterface,
98 operation: JsonObject,
99): Promise<JsonObject> {
100 const input = boundedJson(
101 operation,
102 "QE broker operation",
103 MAX_OPERATION_INPUT,
104 );
105 const execution = await $.process.run([BRIDGE, "bound-operation"], {
106 stdin: input,
107 timeoutMs: 600_000,
108 });
109 if (
110 execution.exitCode !== 0 ||
111 execution.isStdoutTruncated ||
112 execution.isStderrTruncated
113 )
114 throw new Error(`QE broker failed with exit code ${execution.exitCode}.`);
115 return parseBridgeOutput(execution.stdout);
116}
117
118async function waitForHuman(
119 $: EngineInterface,
120 operation: JsonObject,
121): Promise<JsonObject> {
122 const input = boundedJson(
123 operation,
124 "QE HumanAttention operation",
125 MAX_OPERATION_INPUT,
126 );
127 const stream = $.process.spawn({
128 argv: [BRIDGE, "bound-human-attention-wait"],
129 input,
130 });
131 let stdout = "";
132 let stderr = "";
133 let item = await stream.next();
134 while (item.done !== true) {
135 if (item.value.stream === "stdout") stdout += item.value.text;
136 else stderr += item.value.text;
137 if (stdout.length + stderr.length > MAX_BRIDGE_OUTPUT) {
138 await stream.return({ code: null, signal: "SIGTERM" });
139 throw new Error("QE HumanAttention output exceeded the spike limit.");
140 }
141 item = await stream.next();
142 }
143 if (item.value.code !== 0 || item.value.signal !== null)
144 throw new Error("QE HumanAttention bridge did not exit successfully.");
145 return parseBridgeOutput(stdout);
146}
147
148async function checkPlugin(
149 _$: EngineInterface,
150 event: PluginRegisterInput,
151 next: Next<"plugin.register">,
152) {
153 if (event.tier === "user")
154 return {
155 refuse:
156 "QE account-cell policy permits only immutable organization and built-in Mods.",
157 } as const;
158 return next(event);
159}
160
161function brokerOperation(tool: string, event: JsonObject): JsonObject {
162 switch (tool) {
163 case TOOLS.read:
164 return {
165 type: "workspace_read",
166 path: workspacePath(event.path, "path"),
167 ...(optionalInteger(event.offset, "offset", 0, 10_000_000) === undefined
168 ? {}
169 : { offset: event.offset }),
170 ...(optionalInteger(event.limit, "limit", 1, 100_000) === undefined
171 ? {}
172 : { limit: event.limit }),
173 };
174 case TOOLS.list:
175 return {
176 type: "workspace_list",
177 path: workspacePath(event.path ?? ".", "path"),
178 };
179 case TOOLS.write:
180 return {
181 type: "workspace_write",
182 path: workspacePath(event.path, "path"),
183 content: boundedString(event.content, "content", 262_144),
184 };
185 case TOOLS.edit:
186 return {
187 type: "workspace_edit",
188 path: workspacePath(event.path, "path"),
189 oldText: boundedString(event.oldText, "oldText", 262_144),
190 newText:
191 typeof event.newText === "string" && event.newText.length <= 262_144
192 ? event.newText
193 : (() => {
194 throw new Error("newText is invalid.");
195 })(),
196 replaceAll: event.replaceAll === true,
197 };
198 case TOOLS.search:
199 return {
200 type: "workspace_search",
201 query: boundedString(event.query, "query", 4_096),
202 path: workspacePath(event.path ?? ".", "path"),
203 ...(optionalInteger(event.maxResults, "maxResults", 1, 1_000) ===
204 undefined
205 ? {}
206 : { maxResults: event.maxResults }),
207 };
208 case TOOLS.shell:
209 return {
210 type: "run_shell",
211 command: boundedString(event.command, "command", 32_768),
212 ...(optionalInteger(event.timeoutMs, "timeoutMs", 1, 600_000) ===
213 undefined
214 ? {}
215 : { timeoutMs: event.timeoutMs }),
216 };
217 case TOOLS.complete:
218 return {
219 type: "complete_step",
220 outputs: object(event.outputs, "outputs"),
221 };
222 default:
223 throw new Error("The tool is not a synchronous QE broker operation.");
224 }
225}
226
227export const register: Register = (on) => {
228 let ready = false;
229 let expectedModel = "";
230 let expectedEffort: NonNullable<TurnStepInput["effort"]> | "" = "";
231 let nativeSessionId = "";
232
233 on("plugin.register", checkPlugin).catch(async (_$, event, next) => {
234 if (event.tier === "user")
235 return {
236 refuse: "QE failed closed while checking an unapproved Mod.",
237 };
238 return next(event);
239 });
240
241 on("session.start", async ($, event, next) => {
242 ready = false;
243 const protocol = await $.env.get("QE_ACCOUNT_CELL_MOD_PROTOCOL");
244 expectedModel = (await $.env.get("QE_CLAUDE_MODEL")) ?? "";
245 expectedEffort = parseEffort((await $.env.get("QE_CLAUDE_EFFORT")) ?? "");
246 nativeSessionId = await $.session.id();
247 if (
248 protocol !== PROTOCOL ||
249 expectedModel.length === 0 ||
250 nativeSessionId.length === 0
251 )
252 throw new Error("QE account-cell Mod environment is incomplete.");
253
254 await $.tool.register({
255 name: "qe_workspace_read",
256 description:
257 "Read a UTF-8 file from the pre-bound Quest Engineering Run workspace. Paths are relative to that workspace; this tool cannot address the Claude account cell.",
258 inputSchema: {
259 type: "object",
260 properties: {
261 path: { type: "string", minLength: 1, maxLength: 4_096 },
262 offset: { type: "integer", minimum: 0, maximum: 10_000_000 },
263 limit: { type: "integer", minimum: 1, maximum: 100_000 },
264 },
265 required: ["path"],
266 additionalProperties: false,
267 },
268 });
269 await $.tool.register({
270 name: "qe_workspace_list",
271 description:
272 "List a directory in the pre-bound Quest Engineering Run workspace. The account-cell filesystem is not in this tool's namespace.",
273 inputSchema: {
274 type: "object",
275 properties: {
276 path: { type: "string", minLength: 1, maxLength: 4_096 },
277 },
278 additionalProperties: false,
279 },
280 });
281 await $.tool.register({
282 name: "qe_workspace_write",
283 description:
284 "Write a UTF-8 file in the pre-bound Quest Engineering Run workspace.",
285 inputSchema: {
286 type: "object",
287 properties: {
288 path: { type: "string", minLength: 1, maxLength: 4_096 },
289 content: { type: "string", minLength: 1, maxLength: 262_144 },
290 },
291 required: ["path", "content"],
292 additionalProperties: false,
293 },
294 });
295 await $.tool.register({
296 name: "qe_workspace_edit",
297 description:
298 "Replace exact text in a file in the pre-bound Quest Engineering Run workspace.",
299 inputSchema: {
300 type: "object",
301 properties: {
302 path: { type: "string", minLength: 1, maxLength: 4_096 },
303 oldText: { type: "string", minLength: 1, maxLength: 262_144 },
304 newText: { type: "string", maxLength: 262_144 },
305 replaceAll: { type: "boolean" },
306 },
307 required: ["path", "oldText", "newText"],
308 additionalProperties: false,
309 },
310 });
311 await $.tool.register({
312 name: "qe_workspace_search",
313 description:
314 "Search only the pre-bound Quest Engineering Run workspace and return bounded matches.",
315 inputSchema: {
316 type: "object",
317 properties: {
318 query: { type: "string", minLength: 1, maxLength: 4_096 },
319 path: { type: "string", minLength: 1, maxLength: 4_096 },
320 maxResults: { type: "integer", minimum: 1, maximum: 1_000 },
321 },
322 required: ["query"],
323 additionalProperties: false,
324 },
325 });
326 await $.tool.register({
327 name: "qe_run_shell",
328 description:
329 "Execute a command only inside the pre-bound credential-free Quest Engineering Run SBX. No command executes in the Claude account cell.",
330 inputSchema: {
331 type: "object",
332 properties: {
333 command: { type: "string", minLength: 1, maxLength: 32_768 },
334 timeoutMs: { type: "integer", minimum: 1, maximum: 600_000 },
335 },
336 required: ["command"],
337 additionalProperties: false,
338 },
339 });
340 await $.tool.register({
341 name: "qe_complete_step",
342 description:
343 "Submit the declared structured outputs to the pre-bound Quest Engineering completion authority.",
344 inputSchema: {
345 type: "object",
346 properties: { outputs: { type: "object" } },
347 required: ["outputs"],
348 additionalProperties: false,
349 },
350 });
351 await $.tool.register({
352 name: "qe_request_human_assistance_and_wait",
353 description:
354 "Create a durable Quest Engineering HumanAttention request and wait for its exact response without opening a local account-cell prompt.",
355 inputSchema: {
356 type: "object",
357 properties: {
358 category: {
359 type: "string",
360 enum: [
361 "needs_input",
362 "needs_permission",
363 "needs_authentication",
364 "needs_confirmation",
365 "blocked_external",
366 "interactive_prompt",
367 "unknown_interactive_block",
368 ],
369 },
370 message: { type: "string", minLength: 1, maxLength: 16_384 },
371 interaction: {
372 type: "string",
373 enum: [
374 "confirmation",
375 "text",
376 "choice",
377 "multiline_response",
378 "conversational_intervention",
379 ],
380 },
381 responseSchema: { type: "object" },
382 },
383 required: ["category", "message"],
384 additionalProperties: false,
385 },
386 });
387 await $.command.register({
388 name: "qe_account_cell_probe",
389 description: "Report local QE Mod readiness without a model request.",
390 });
391 ready = true;
392 return next(event);
393 });
394
395 on("command.run", { command: "qe_account_cell_probe" }, async () => ({
396 text: JSON.stringify({
397 protocol: PROTOCOL,
398 ready,
399 nativeSessionId,
400 tools: [...ALLOWED_TOOLS].sort(),
401 }),
402 }));
403
404 on("command.run", () => ({
405 text: "QE account-cell policy refused this local command.",
406 })).catch(() => ({
407 text: "QE account-cell command policy failed closed.",
408 }));
409
410 on("agent.offer", () => ({ isOffered: false })).catch(() => ({
411 isOffered: false,
412 }));
413
414 on("agent.spawn", () => ({
415 deny: "QE account-cell policy disables Claude subagents.",
416 })).catch(() => ({
417 deny: "QE account-cell subagent policy failed closed.",
418 }));
419
420 on("tool.call", async ($, event) => {
421 if (!ready) return { deny: "QE account-cell Mod is not ready." };
422 if (event.agentId)
423 return { deny: "QE account-cell policy denies subagent tool calls." };
424 if (!ALLOWED_TOOLS.has(event.tool))
425 return {
426 deny: `QE account-cell policy did not authorize ${event.tool}.`,
427 };
428
429 const input = object(event, "tool input");
430 if (event.tool === TOOLS.attention) {
431 const category = boundedString(input.category, "category", 64);
432 const message = boundedString(input.message, "message", 16_384);
433 const interaction =
434 input.interaction === undefined
435 ? undefined
436 : boundedString(input.interaction, "interaction", 64);
437 const responseSchema =
438 input.responseSchema === undefined
439 ? undefined
440 : object(input.responseSchema, "responseSchema");
441 if (responseSchema !== undefined)
442 boundedJson(responseSchema, "responseSchema", 16_384);
443 const result = await waitForHuman($, {
444 type: "request_human_assistance_and_wait",
445 category,
446 message,
447 ...(interaction === undefined ? {} : { interaction }),
448 ...(responseSchema === undefined ? {} : { responseSchema }),
449 });
450 return { result: JSON.stringify(result) };
451 }
452
453 const result = await runBridge($, brokerOperation(event.tool, input));
454 return { result: JSON.stringify(result) };
455 }).catch((_$, event, next) => ({
456 deny: `QE account-cell tool mediation failed closed for ${event.tool}: ${next.error.kind}.`,
457 }));
458
459 on("tool.check", async (_$, event, next) => {
460 if (!ready || event.agentId || !ALLOWED_TOOLS.has(event.tool))
461 return {
462 decision: "deny",
463 reason: "QE account-cell exact tool policy denied this call.",
464 };
465 const lower = await next(event);
466 if (lower.decision === "deny") return lower;
467 if (event.ceiling === "ask" || event.ceiling === "deny")
468 return {
469 decision: event.ceiling,
470 reason: "QE preserved the managed policy ceiling.",
471 };
472 return {
473 decision: "allow",
474 reason: "QE allowed an exact pre-bound broker tool.",
475 };
476 }).catch(() => ({
477 decision: "deny",
478 reason: "QE account-cell permission mediation failed closed.",
479 }));
480
481 on("prompt.submit", async (_$, event, next) => {
482 if (!ready)
483 return {
484 drop: "QE account-cell Mod is not ready; refusing the prompt.",
485 };
486 return next({
487 ...event,
488 context: [
489 ...(event.context ?? []),
490 "Quest Engineering account-cell contract: every filesystem, search, and shell operation must use the QE broker tools. No local account-cell coding tool exists. Use qe_complete_step for completion and qe_request_human_assistance_and_wait for human input.",
491 ],
492 });
493 }).catch(() => ({
494 drop: "QE account-cell prompt mediation failed closed.",
495 }));
496
497 on("turn.step", async function* (_$, event, next) {
498 if (
499 !ready ||
500 event.agentId !== undefined ||
501 event.model !== expectedModel ||
502 event.effort !== expectedEffort
503 )
504 return {
505 turnId: event.turnId,
506 index: event.index,
507 answer: "",
508 toolUses: [],
509 stopReason: "refusal",
510 usage: null,
511 };
512 const chunks = [];
513 const downstream = next(event);
514 let item = await downstream.next();
515 while (item.done !== true) {
516 chunks.push(item.value);
517 item = await downstream.next();
518 }
519 if ((item.value.serverToolUses?.length ?? 0) > 0)
520 return {
521 turnId: event.turnId,
522 index: event.index,
523 answer: "",
524 toolUses: [],
525 serverToolUses: item.value.serverToolUses,
526 stopReason: "refusal",
527 usage: item.value.usage,
528 };
529 for (const chunk of chunks) yield chunk;
530 return item.value;
531 });
532};
533