SLOPSHOPPER

qe-control-spike

Zero-inference spike for a Quest Engineering Claude Code Mod control bridge

newguardcommandprompttoolprocess
★ 1v0.0.0no licenseupdated 2026-10-12emeraldarcher/quest-engineering/spikes/claude-mod-harness
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · qe-control-spike
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Read(/work/app/src/auth.ts) ⎿ Denied by qe-control-spike: QE control configuration is not initialized. ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

Claude Code Mod harness spike

This is a zero-inference, non-production fixture for the Claude harness reassessment. It targets the Mods API embedded in Claude Code 2.1.292 and is kept because it records executable evidence that a Mod can:

  • register QE completion and HumanAttention tools;
  • mediate tool calls and permission decisions fail-closed;
  • refuse a model or effort mismatch at turn.step, before a mocked provider request;
  • disable subagents;
  • invoke QE's existing qe-harness-bridge local-control transport for structured completion;
  • block native Stop with a QE correction;
  • map lifecycle facts to current generic QE harness event shapes and preserve an opaque native session reference without a terminal identity; and
  • hold a tool call open while a streamed local helper waits for a mocked human response.

The tests run under claude plugin test, which Anthropic documents as running without a session, sign-in, or network. They never invoke a model.

Deliberate gap

local-control-wait and the request_human_assistance_and_wait operation are a proposed generic control bridge extension, not current production behavior. The current bridge can create a HumanAttention request but cannot keep a Mod call waiting and return the eventual structured human response. A production Mod architecture would need that provider-neutral operation (including cancellation and process-loss semantics) before it could claim structured-attention parity.

No production adapter or bridge code is changed by this spike.

Validate

Using the exact pinned Claude Code binary:

claude plugin validate spikes/claude-mod-harness
workers/bun/node_modules/.bin/tsc -p spikes/claude-mod-harness/tsconfig.json
claude plugin test spikes/claude-mod-harness

The expected test result is 10 pass, 0 fail with Claude Code 2.1.292.

Source 1 files
hooks/register.ts 348 lines
1import type {
2  EngineInterface,
3  Register,
4  TurnStepChunk,
5  TurnStepInput,
6} from "claude-code";
7
8const PROTOCOL = "qe_claude_mod_spike_v1";
9const COMPLETE_TOOL = "mcp__qe-control-spike__qe_complete_step";
10const ATTENTION_TOOL =
11  "mcp__qe-control-spike__qe_request_human_assistance";
12const MAX_BRIDGE_OUTPUT = 65_536;
13
14function object(value: unknown): Record<string, unknown> {
15  if (typeof value !== "object" || value === null || Array.isArray(value))
16    throw new Error("Expected an object from the QE control bridge.");
17  return value as Record<string, unknown>;
18}
19
20function parseBridgeOutput(text: string): Record<string, unknown> {
21  if (text.length > MAX_BRIDGE_OUTPUT)
22    throw new Error("QE control bridge output exceeded the spike limit.");
23  return object(JSON.parse(text));
24}
25
26function parseEffort(value: string): NonNullable<TurnStepInput["effort"]> {
27  switch (value) {
28    case "low":
29    case "medium":
30    case "high":
31    case "xhigh":
32    case "max":
33      return value;
34    default: {
35      const numeric = Number(value);
36      if (Number.isFinite(numeric) && numeric >= 0) return numeric;
37      throw new Error("QE_CLAUDE_EFFORT is invalid.");
38    }
39  }
40}
41
42function parseAllowedTools(value: string): Set<string> {
43  const parsed = JSON.parse(value);
44  if (
45    !Array.isArray(parsed) ||
46    parsed.length === 0 ||
47    !parsed.every(
48      (entry) =>
49        typeof entry === "string" && entry.length > 0 && entry.length < 256,
50    )
51  )
52    throw new Error("QE_CLAUDE_ALLOWED_TOOLS_JSON is invalid.");
53  return new Set(parsed);
54}
55
56async function runControl(
57  $: EngineInterface,
58  bridge: string,
59  operation: Record<string, unknown>,
60): Promise<Record<string, unknown>> {
61  const execution = await $.process.run([bridge, "local-control"], {
62    stdin: JSON.stringify(operation),
63    timeoutMs: 30_000,
64  });
65  if (
66    execution.exitCode !== 0 ||
67    execution.isStdoutTruncated ||
68    execution.isStderrTruncated
69  )
70    throw new Error(
71      `QE control bridge failed (${execution.exitCode}): ${execution.stderr}`,
72    );
73  return parseBridgeOutput(execution.stdout);
74}
75
76async function waitForHuman(
77  $: EngineInterface,
78  bridge: string,
79  operation: Record<string, unknown>,
80): Promise<Record<string, unknown>> {
81  const stream = $.process.spawn({
82    argv: [bridge, "local-control-wait"],
83    input: JSON.stringify(operation),
84  });
85  let stdout = "";
86  let stderr = "";
87  let item = await stream.next();
88  while (item.done !== true) {
89    if (item.value.stream === "stdout") stdout += item.value.text;
90    else stderr += item.value.text;
91    if (stdout.length + stderr.length > MAX_BRIDGE_OUTPUT) {
92      await stream.return({ code: null, signal: "SIGTERM" });
93      throw new Error("QE control bridge output exceeded the spike limit.");
94    }
95    item = await stream.next();
96  }
97  if (item.value.code !== 0 || item.value.signal !== null)
98    throw new Error(
99      `QE control bridge wait failed (${item.value.code ?? item.value.signal}): ${stderr}`,
100    );
101  return parseBridgeOutput(stdout);
102}
103
104function invalidConfigurationReason(): string {
105  return "QE Claude Mod control configuration was not initialized; refusing the model turn.";
106}
107
108export const register: Register = (on) => {
109  let ready = false;
110  let bridge = "";
111  let expectedModel = "";
112  let expectedEffort: NonNullable<TurnStepInput["effort"]> | "" = "";
113  let allowedTools = new Set<string>();
114  let observedModel: string | undefined;
115  let completionReason = "unknown";
116
117  on("session.start", async ($, e, next) => {
118    ready = false;
119    const protocol = await $.env.get("QE_CLAUDE_MOD_PROTOCOL");
120    bridge = (await $.env.get("QE_BRIDGE")) ?? "";
121    expectedModel = (await $.env.get("QE_CLAUDE_MODEL")) ?? "";
122    expectedEffort = parseEffort(
123      (await $.env.get("QE_CLAUDE_EFFORT")) ?? "",
124    );
125    allowedTools = parseAllowedTools(
126      (await $.env.get("QE_CLAUDE_ALLOWED_TOOLS_JSON")) ?? "",
127    );
128    if (protocol !== PROTOCOL || bridge.length === 0 || expectedModel.length === 0)
129      throw new Error("QE Claude Mod control environment is incomplete.");
130
131    await $.tool.register({
132      name: "qe_complete_step",
133      description:
134        "Submit the declared structured outputs to Quest Engineering. Call exactly once when the step is complete.",
135      inputSchema: {
136        type: "object",
137        properties: {
138          outputs: {
139            type: "object",
140            additionalProperties: true,
141          },
142        },
143        required: ["outputs"],
144        additionalProperties: false,
145      },
146    });
147    await $.tool.register({
148      name: "qe_request_human_assistance",
149      description:
150        "Pause for a Quest Engineering human response when blocked on a decision or information.",
151      inputSchema: {
152        type: "object",
153        properties: {
154          category: {
155            type: "string",
156            enum: [
157              "needs_input",
158              "needs_permission",
159              "needs_authentication",
160              "needs_confirmation",
161              "blocked_external",
162              "interactive_prompt",
163              "unknown_interactive_block",
164            ],
165          },
166          message: { type: "string" },
167          interaction: {
168            type: "string",
169            enum: [
170              "confirmation",
171              "text",
172              "choice",
173              "multiline_response",
174              "conversational_intervention",
175            ],
176          },
177          responseSchema: {},
178        },
179        required: ["category", "message"],
180        additionalProperties: false,
181      },
182    });
183    await $.command.register({
184      name: "qe_mod_probe",
185      description: "Report QE Mod readiness without starting a model turn.",
186    });
187    allowedTools.add(COMPLETE_TOOL);
188    allowedTools.add(ATTENTION_TOOL);
189    ready = true;
190    return next(e);
191  });
192
193  on("command.run", { command: "qe_mod_probe" }, async ($, e) => ({
194    text: JSON.stringify({ protocol: PROTOCOL, ready, interactive: false }),
195  }));
196
197  on("prompt.submit", async ($, e, next) => {
198    if (!ready) return { drop: invalidConfigurationReason() };
199    return next({
200      ...e,
201      context: [
202        ...(e.context ?? []),
203        `Quest Engineering control contract: use ${COMPLETE_TOOL} exactly once with every declared output when complete. Use ${ATTENTION_TOOL} instead of AskUserQuestion when human input is required. Do not claim completion in prose before the completion tool is accepted.`,
204      ],
205    });
206  }).catch(() => ({ drop: invalidConfigurationReason() }));
207
208  on("agent.offer", () => ({ isOffered: false })).catch(() => ({
209    isOffered: false,
210  }));
211
212  on("agent.spawn", () => ({
213    deny: "QE disables Claude subagents until their authorization and accounting semantics are implemented.",
214  })).catch(() => ({
215    deny: "QE denied a subagent because the QE policy hook failed.",
216  }));
217
218  on("tool.call", async ($, e, next) => {
219    if (!ready)
220      return { deny: "QE control configuration is not initialized." };
221    if (e.agentId)
222      return { deny: "QE does not permit tool calls from Claude subagents." };
223    if (!allowedTools.has(e.tool))
224      return { deny: `QE did not authorize tool ${e.tool}.` };
225
226    if (e.tool === COMPLETE_TOOL) {
227      const input = object(e);
228      const result = await runControl($, bridge, {
229        type: "complete_step",
230        outputs: object(input.outputs),
231      });
232      if (result.accepted !== true)
233        throw new Error("QE rejected the structured completion.");
234      return {
235        result: JSON.stringify({
236          accepted: true,
237          duplicate: result.duplicate === true,
238          semanticAccepted: result.semanticAccepted === true,
239        }),
240      };
241    }
242
243    if (e.tool === ATTENTION_TOOL) {
244      const input = object(e);
245      const result = await waitForHuman($, bridge, {
246        type: "request_human_assistance_and_wait",
247        category: input.category,
248        message: input.message,
249        ...(input.interaction === undefined
250          ? {}
251          : { interaction: input.interaction }),
252        ...(input.responseSchema === undefined
253          ? {}
254          : { responseSchema: input.responseSchema }),
255      });
256      if (result.accepted !== true || result.humanResponse === undefined)
257        throw new Error("QE did not return a human response.");
258      return { result: JSON.stringify(result.humanResponse) };
259    }
260
261    return next(e);
262  }).catch(($, e, next) => ({
263    deny: `QE tool mediation failed closed: ${next.error.kind}.`,
264  }));
265
266  on("tool.check", async ($, e, next) => {
267    if (!ready || e.agentId || !allowedTools.has(e.tool))
268      return { decision: "deny", reason: "QE exact tool policy denied this call." };
269    const lower = await next(e);
270    if (lower.decision === "deny") return lower;
271    if (e.ceiling === "ask" || e.ceiling === "deny")
272      return { decision: e.ceiling, reason: "QE preserved the managed ceiling." };
273    return { decision: "allow", reason: "QE exact tool policy allowed this call." };
274  }).catch(() => ({
275    decision: "deny",
276    reason: "QE permission mediation failed closed.",
277  }));
278
279  on("turn.start", async ($, e, next) => next(e));
280
281  on("turn.step", async function* ($, e, next) {
282    if (
283      !ready ||
284      e.model !== expectedModel ||
285      e.effort !== expectedEffort
286    )
287      return {
288        turnId: e.turnId,
289        index: e.index,
290        answer: "",
291        toolUses: [],
292        stopReason: "refusal",
293        usage: null,
294      };
295    const chunks: TurnStepChunk[] = [];
296    const downstream = next(e);
297    let item = await downstream.next();
298    while (item.done !== true) {
299      chunks.push(item.value);
300      item = await downstream.next();
301    }
302    const result = item.value;
303    if (result.usage !== null && result.usage.model !== expectedModel)
304      return {
305        turnId: e.turnId,
306        index: e.index,
307        answer: "",
308        toolUses: [],
309        stopReason: "refusal",
310        usage: result.usage,
311      };
312    for (const chunk of chunks) yield chunk;
313    return result;
314  });
315
316  on("turn.complete", async ($, e, next) => {
317    observedModel = e.usage?.model;
318    completionReason = e.reason;
319    return next(e);
320  });
321
322  on("classic.Stop", async ($, e, next) => {
323    const execution = await $.process.run([bridge, "hook", "stop"], {
324      stdin: JSON.stringify({
325        terminationReason: completionReason,
326        fullyIdle: true,
327        ...(observedModel === undefined ? {} : { modelName: observedModel }),
328      }),
329      timeoutMs: 30_000,
330    });
331    if (
332      execution.exitCode !== 0 ||
333      execution.isStdoutTruncated ||
334      execution.isStderrTruncated
335    )
336      return {
337        block:
338          "QE completion enforcement failed. Continue without repeating finished work and retry the QE completion tool.",
339      };
340    const decision = parseBridgeOutput(execution.stdout);
341    if (decision.decision === "continue")
342      return { block: String(decision.reason ?? "Continue.") };
343    return next(e);
344  }).catch(() => ({
345    block: "QE completion enforcement failed closed. Retry the QE completion tool.",
346  }));
347};
348