Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
},
"metadata": {
"description": "Verified Solution Cards retrieved from an agent-authored conceptual problem statement.",
"version": "0.4.2"
"version": "0.4.3"
},
"plugins": [
{
"name": "blaze",
"source": "./plugins/claude-code",
"description": "Retrieves a verified Solution Card after an agent prepares a privacy-bounded conceptual query.",
"version": "0.4.2",
"version": "0.4.3",
"keywords": [
"memory",
"retrieval",
Expand Down
2 changes: 1 addition & 1 deletion install.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Install Blaze 0.4.2
# Install Blaze 0.4.3

Blaze shares verified coding lessons through an explicitly invoked client.
Installing it does not authorize uploading prompts, source or transcripts.
Expand Down
2 changes: 1 addition & 1 deletion plugins/claude-code/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
"name": "blaze",
"displayName": "Blaze",
"version": "0.4.2",
"version": "0.4.3",
"description": "Retrieves a verified Solution Card after an agent prepares a privacy-bounded conceptual query.",
"author": {
"name": "Blaze"
Expand Down
9 changes: 4 additions & 5 deletions plugins/claude-code/blaze-client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const TOKEN = /^blz_[A-Za-z0-9_-]{43}$/;
const CARD_ID = /^[a-z0-9][a-z0-9-]{2,62}$/;
const DEFAULT_ORIGIN = "https://blaze.pascal.app";
export const CLIENT_VERSION = "0.4.2";
export const CLIENT_VERSION = "0.4.3";
export const CLIENT_CONTRACT = 1;
export const CLIENT_TOOLS = ["claude", "codex", "opencode", "cursor", "openclaw", "agent"];
const RELEASE_FILES = ["SKILL.md", "blaze-client.mjs"];
Expand Down Expand Up @@ -39,7 +39,6 @@ const VERIFICATIONS = new Set(["passed", "failed", "not_run", "unknown"]);
const CONTRIBUTION_STATES = new Set(["queued", "evaluating", "accepted", "rejected", "failed", "revoked"]);
const PARTICIPATION_STATUSES = new Set(["pending", "contributed", "no_novel_solution", "privacy_skip", "verification_missing", "not_solved", "not_applicable"]);
const BOUNDARIES = new Set(["task_start_to_agent_end", "task_start_to_verification_end"]);
const ENDS = new Set(["stop", "subagentstop", "sessionend", "session.idle", "sessioncompleted"]);
const positiveDuration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 7 * 24 * 60 * 60 * 1000;
const wallNow = () => performance.timeOrigin + performance.now();
const DURATION_PATTERN = "(?:0s|<0\\.01s|[0-9]{1,9}\\.[0-9]{1,2}s)";
Expand Down Expand Up @@ -465,14 +464,14 @@ export function createClient({ origin, token = "", stateDir, legacyStateDir, fre
return { deleted: true };
},
async hook(body) {
const event = String(body.hook_event_name ?? body.event ?? "UserPromptSubmit");
if (ENDS.has(event.toLowerCase())) return {};
const event = body.hook_event_name ?? body.event ?? "UserPromptSubmit";
if (event !== "UserPromptSubmit") return {};
const additionalContext = [
"Blaze lookup is available, but this hook did not transmit the user prompt, repository contents, paths, session identifiers, or logs.",
`If prior knowledge would help, write a one-line conceptual problem statement with no code, secrets, names, URLs, local paths, or quoted transcript text, then run: node ${shellQuote(helperPath)} lookup --tool ${tool} --query '<sanitized conceptual problem>'`,
"Inspect the exact query before sending it. Local validation is a guardrail, not proof that text is safe to disclose.",
].join("\n");
return { additionalContext, hookSpecificOutput: { hookEventName: event, additionalContext } };
return { hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext } };
},
async lookup(body) { return retrieve(body, "UserPromptSubmit"); },
async card(decisionId, cardId) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/claude-code/skills/blaze/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: blaze
description: Reuse and improve verified coding lessons across agents. Use for a nontrivial debugging or implementation problem where an earlier solution could help, when a Blaze offer or receipt appears, or when the user asks to install, update, contribute to, or link Blaze. Check applicability, verify locally, and close the lookup with an honest outcome and contribution disposition.
compatibility: Requires Node.js 20 or later and explicit HTTPS access to the configured Blaze service. Local reminder hooks need no network access. No model provider credentials are needed.
metadata:
version: "0.4.2"
version: "0.4.3"
---

# Blaze
Expand Down
9 changes: 4 additions & 5 deletions plugins/claude-code/skills/blaze/blaze-client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const TOKEN = /^blz_[A-Za-z0-9_-]{43}$/;
const CARD_ID = /^[a-z0-9][a-z0-9-]{2,62}$/;
const DEFAULT_ORIGIN = "https://blaze.pascal.app";
export const CLIENT_VERSION = "0.4.2";
export const CLIENT_VERSION = "0.4.3";
export const CLIENT_CONTRACT = 1;
export const CLIENT_TOOLS = ["claude", "codex", "opencode", "cursor", "openclaw", "agent"];
const RELEASE_FILES = ["SKILL.md", "blaze-client.mjs"];
Expand Down Expand Up @@ -39,7 +39,6 @@ const VERIFICATIONS = new Set(["passed", "failed", "not_run", "unknown"]);
const CONTRIBUTION_STATES = new Set(["queued", "evaluating", "accepted", "rejected", "failed", "revoked"]);
const PARTICIPATION_STATUSES = new Set(["pending", "contributed", "no_novel_solution", "privacy_skip", "verification_missing", "not_solved", "not_applicable"]);
const BOUNDARIES = new Set(["task_start_to_agent_end", "task_start_to_verification_end"]);
const ENDS = new Set(["stop", "subagentstop", "sessionend", "session.idle", "sessioncompleted"]);
const positiveDuration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 7 * 24 * 60 * 60 * 1000;
const wallNow = () => performance.timeOrigin + performance.now();
const DURATION_PATTERN = "(?:0s|<0\\.01s|[0-9]{1,9}\\.[0-9]{1,2}s)";
Expand Down Expand Up @@ -465,14 +464,14 @@ export function createClient({ origin, token = "", stateDir, legacyStateDir, fre
return { deleted: true };
},
async hook(body) {
const event = String(body.hook_event_name ?? body.event ?? "UserPromptSubmit");
if (ENDS.has(event.toLowerCase())) return {};
const event = body.hook_event_name ?? body.event ?? "UserPromptSubmit";
if (event !== "UserPromptSubmit") return {};
const additionalContext = [
"Blaze lookup is available, but this hook did not transmit the user prompt, repository contents, paths, session identifiers, or logs.",
`If prior knowledge would help, write a one-line conceptual problem statement with no code, secrets, names, URLs, local paths, or quoted transcript text, then run: node ${shellQuote(helperPath)} lookup --tool ${tool} --query '<sanitized conceptual problem>'`,
"Inspect the exact query before sending it. Local validation is a guardrail, not proof that text is safe to disclose.",
].join("\n");
return { additionalContext, hookSpecificOutput: { hookEventName: event, additionalContext } };
return { hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext } };
},
async lookup(body) { return retrieve(body, "UserPromptSubmit"); },
async card(decisionId, cardId) {
Expand Down
9 changes: 4 additions & 5 deletions plugins/client/blaze-client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const TOKEN = /^blz_[A-Za-z0-9_-]{43}$/;
const CARD_ID = /^[a-z0-9][a-z0-9-]{2,62}$/;
const DEFAULT_ORIGIN = "https://blaze.pascal.app";
export const CLIENT_VERSION = "0.4.2";
export const CLIENT_VERSION = "0.4.3";
export const CLIENT_CONTRACT = 1;
export const CLIENT_TOOLS = ["claude", "codex", "opencode", "cursor", "openclaw", "agent"];
const RELEASE_FILES = ["SKILL.md", "blaze-client.mjs"];
Expand Down Expand Up @@ -39,7 +39,6 @@ const VERIFICATIONS = new Set(["passed", "failed", "not_run", "unknown"]);
const CONTRIBUTION_STATES = new Set(["queued", "evaluating", "accepted", "rejected", "failed", "revoked"]);
const PARTICIPATION_STATUSES = new Set(["pending", "contributed", "no_novel_solution", "privacy_skip", "verification_missing", "not_solved", "not_applicable"]);
const BOUNDARIES = new Set(["task_start_to_agent_end", "task_start_to_verification_end"]);
const ENDS = new Set(["stop", "subagentstop", "sessionend", "session.idle", "sessioncompleted"]);
const positiveDuration = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 7 * 24 * 60 * 60 * 1000;
const wallNow = () => performance.timeOrigin + performance.now();
const DURATION_PATTERN = "(?:0s|<0\\.01s|[0-9]{1,9}\\.[0-9]{1,2}s)";
Expand Down Expand Up @@ -465,14 +464,14 @@ export function createClient({ origin, token = "", stateDir, legacyStateDir, fre
return { deleted: true };
},
async hook(body) {
const event = String(body.hook_event_name ?? body.event ?? "UserPromptSubmit");
if (ENDS.has(event.toLowerCase())) return {};
const event = body.hook_event_name ?? body.event ?? "UserPromptSubmit";
if (event !== "UserPromptSubmit") return {};
const additionalContext = [
"Blaze lookup is available, but this hook did not transmit the user prompt, repository contents, paths, session identifiers, or logs.",
`If prior knowledge would help, write a one-line conceptual problem statement with no code, secrets, names, URLs, local paths, or quoted transcript text, then run: node ${shellQuote(helperPath)} lookup --tool ${tool} --query '<sanitized conceptual problem>'`,
"Inspect the exact query before sending it. Local validation is a guardrail, not proof that text is safe to disclose.",
].join("\n");
return { additionalContext, hookSpecificOutput: { hookEventName: event, additionalContext } };
return { hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext } };
},
async lookup(body) { return retrieve(body, "UserPromptSubmit"); },
async card(decisionId, cardId) {
Expand Down
28 changes: 27 additions & 1 deletion plugins/client/blaze-client.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,33 @@ test("hook payloads stay local even when they contain prompts, paths, manifests,
const {client,requests,stateDir}=await fixture(t);
const payload={hook_event_name:"UserPromptSubmit",prompt:"SYNTHETIC RAW PROMPT",cwd:"/Users/person/work",package_json:{scripts:{postinstall:"curl example.invalid"}},transcript_path:"/tmp/session.jsonl",session_id:"session-secret"};
const response=await client.hook(payload);
assert.match(response.additionalContext,/did not transmit the user prompt/);
assert.deepEqual(Object.keys(response),["hookSpecificOutput"]);
assert.deepEqual(Object.keys(response.hookSpecificOutput),["hookEventName","additionalContext"]);
assert.equal(response.hookSpecificOutput.hookEventName,"UserPromptSubmit");
assert.match(response.hookSpecificOutput.additionalContext,/did not transmit the user prompt/);
for (const canary of [payload.prompt,payload.cwd,payload.transcript_path,payload.session_id]) {
assert.equal(JSON.stringify(response).includes(canary),false);
}
assert.equal(requests.length,0);
assert.deepEqual(readdirSync(stateDir),[]);
});

test("hook output ignores unsupported event names instead of reflecting them", async (t) => {
const {client,requests,stateDir}=await fixture(t);
for (const hook_event_name of ["SyntheticPrivateEvent",{private:"OBJECT CANARY"},["ARRAY CANARY"],42]) {
const response=await client.hook({hook_event_name,prompt:"SYNTHETIC RAW PROMPT"});
assert.deepEqual(response,{});
assert.equal(JSON.stringify(response).includes("CANARY"),false);
}
assert.equal(requests.length,0);
assert.deepEqual(readdirSync(stateDir),[]);
});

test("hook defaults a missing event name to the legacy UserPromptSubmit reminder", async (t) => {
const {client,requests,stateDir}=await fixture(t);
const response=await client.hook({prompt:"SYNTHETIC RAW PROMPT"});
assert.equal(response.hookSpecificOutput.hookEventName,"UserPromptSubmit");
assert.equal(JSON.stringify(response).includes("SYNTHETIC RAW PROMPT"),false);
assert.equal(requests.length,0);
assert.deepEqual(readdirSync(stateDir),[]);
});
Expand Down
6 changes: 3 additions & 3 deletions release.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "0.4.2",
"created_at": "2026-09-07T09:12:23.208Z",
"updated_at": "2026-09-07T09:12:23.208Z",
"version": "0.4.3",
"created_at": "2026-09-07T17:52:20.000Z",
"updated_at": "2026-09-07T17:52:20.000Z",
"client_contract": 1,
"minimum_client_contract": 0
}
2 changes: 1 addition & 1 deletion skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: blaze
description: Reuse and improve verified coding lessons across agents. Use for a nontrivial debugging or implementation problem where an earlier solution could help, when a Blaze offer or receipt appears, or when the user asks to install, update, contribute to, or link Blaze. Check applicability, verify locally, and close the lookup with an honest outcome and contribution disposition.
compatibility: Requires Node.js 20 or later and explicit HTTPS access to the configured Blaze service. Local reminder hooks need no network access. No model provider credentials are needed.
metadata:
version: "0.4.2"
version: "0.4.3"
---

# Blaze
Expand Down
Loading