S
SessionStart (startup|resume|clear|compact)
HookFires on
SessionStartmatchingstartup|resume|clear|compactOnce, as a session begins — before you type anything.
Where this sits in a session
- Session start→
- Prompt submitted→
- Prompt expansion→
- Before tool use→
- After tool use→
- Notification→
- Before compaction→
- Subagent finished→
- Turn finished→
- Session end
Observes only — Emits messages or context. It never returns a permission decision.
What it runs
Executed automatically when the event fires — no prompt, no confirmation.
command
node "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-seen-skills.mjs"command
node "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-profiler.mjs"command
node "${CLAUDE_PLUGIN_ROOT}/hooks/inject-claude-md.mjs"Install it yourself
Paste into .claude/settings.json to run this hook without installing the whole plugin. Adjust the paths to point at your own copy of the scripts.
settings.json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start-seen-skills.mjs\""
},
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start-profiler.mjs\""
},
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/inject-claude-md.mjs\""
}
],
"matcher": "startup|resume|clear|compact"
}
]
}
}Source (3 files)
Read this before installing — it runs on your machine with your permissions.
#!/usr/bin/env node
// hooks/src/session-start-seen-skills.mts
import { readFileSync } from "fs";
import { resolve } from "path";
import { fileURLToPath } from "url";
import {
formatOutput
} from "./compat.mjs";
import {
removeAllSessionDedupArtifacts
} from "./hook-env.mjs";
import { createLogger } from "./logger.mjs";
var CONTEXT_CLEARING_EVENTS = /* @__PURE__ */ new Set(["clear", "compact"]);
function parseSessionStartSeenSkillsInput(raw) {
try {
if (!raw.trim()) return null;
return JSON.parse(raw);
} catch {
return null;
}
}
function detectSessionStartSeenSkillsPlatform(input, _env = process.env) {
if (input && ("conversation_id" in input || "cursor_version" in input)) {
return "cursor";
}
return "claude-code";
}
function formatSessionStartSeenSkillsCursorOutput() {
return JSON.stringify(formatOutput("cursor", {
env: {
VERCEL_PLUGIN_SEEN_SKILLS: ""
}
}));
}
function resetDedupStateForSession(sessionId) {
return removeAllSessionDedupArtifacts(sessionId);
}
function main() {
const log = createLogger();
const input = parseSessionStartSeenSkillsInput(readFileSync(0, "utf8"));
const platform = detectSessionStartSeenSkillsPlatform(input);
if (platform === "cursor") {
process.stdout.write(formatSessionStartSeenSkillsCursorOutput());
return;
}
const hookEvent = input?.hook_event_name ?? "";
const sessionId = input?.session_id ?? "";
const resetTriggered = CONTEXT_CLEARING_EVENTS.has(hookEvent) && !!sessionId;
let removedFiles = 0;
let removedDirs = 0;
if (resetTriggered) {
const result = resetDedupStateForSession(sessionId);
removedFiles = result.removedFiles;
removedDirs = result.removedDirs;
}
log.debug("session-start-seen-skills:decision", {
event: hookEvent || "unknown",
sessionId: sessionId || "none",
resetTriggered,
removedFiles,
removedDirs
});
}
var SESSION_START_SEEN_SKILLS_ENTRYPOINT = fileURLToPath(import.meta.url);
var isSessionStartSeenSkillsEntrypoint = process.argv[1] ? resolve(process.argv[1]) === SESSION_START_SEEN_SKILLS_ENTRYPOINT : false;
if (isSessionStartSeenSkillsEntrypoint) {
main();
}
export {
detectSessionStartSeenSkillsPlatform,
formatSessionStartSeenSkillsCursorOutput,
parseSessionStartSeenSkillsInput,
resetDedupStateForSession
};
Shipped by 1 plugin
Installing any of these installs this hook.
Reviews
Log in to leave a review.
No reviews yet — be the first.
Explore related
Other things in this space — across every part of the ecosystem, not just hooks.