npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@skillstate/claude

v3.0.1

Published

Claude Code platform adapter for the skillstate runtime.

Readme

@skillstate/claude

Claude Code platform adapter for the @skillstate/core runtime — state injection and patch persistence via hook scripts (2.1.260 hooks contract).

npm version node License: MIT


@skillstate/claude bridges the paper-exact core (@skillstate/core) into Claude Code sessions. It emits self-contained CommonJS hook scripts (run via node script.cjs) that inject the persisted skill state into every turn, re-inject it after compaction, and merge a validated state_patch from Bash tool responses back into the state file.

@non-paper — no adapters exist in arXiv 2608.26263v3. This adapter is an additive integration, not part of the paper.

The honest architecture (Claude Code 2.1.260)

History trimming from hooks is impossible. The compaction-time hook cannot inject context (its only decision is decision: "block" — forbid compaction), and the post-compaction hook has no decision control at all (its systemMessage is discarded). So this adapter implements the state-injection model, not a trim model:

| Event | Matcher | What the script does | | --- | --- | --- | | UserPromptSubmit | — (no matcher support) | Injects Current skill state (JSON): {...} as additionalContext — the model gets the authoritative state at every turn. | | SessionStart | ^compact$ | Re-injects the state right after auto/manual compaction — state SURVIVES compaction even though history was compressed. | | PostToolUse | ^Bash$ | Extracts a fenced ```json state_patch from the tool response (or a raw JSON / object tool_response.state_patch), applies the paper's ⊕ null-deletion merge, and writes { version: 1, state }. stdout is {} or a systemMessage when the patch is invalid. |

Reading and writing the full state is available at any time through the skillstate MCP server (state.get / state.patch — schema-validated) that skillstate init registers in the project's .mcp.json.

Prompts stay O(T) with a fresh state at every turn. True O(1) requires host-side trimming, which Claude Code does not expose.

Installation

npm i @skillstate/core @skillstate/claude
# or wire every detected host at once, project-locally:
skillstate init   # writes .claude/hooks/skillstate/ scripts, merges the project
                  # .claude/settings.json, adds the project .mcp.json entry, and
                  # writes the shared .claude/skills/skillstate/SKILL.md

All Claude glue is PROJECT-LOCAL and committed: the hook scripts live in <project>/.claude/hooks/skillstate/, the hook groups in the project .claude/settings.json (commands anchored at $CLAUDE_PROJECT_DIR), and the MCP entry in the project .mcp.json. Nothing is written into ~/.claude — a fresh clone works for the whole team.

Requires Node.js >= 20. TypeScript types are bundled.

Quick start

import { ClaudeAdapter } from '@skillstate/claude';
import { INTERCODE_CTF_SPEC } from '@skillstate/core/schemas';

const adapter = new ClaudeAdapter();

// Self-contained hook scripts (Node builtins only). Each resolves the
// per-project state from input.cwd at runtime and is INERT when the
// project has no skillstate state (hooks never create state files):
const inject = adapter.generateHookScript('user-prompt-submit');
const survive = adapter.generateHookScript('session-start-compact');
const persist = adapter.generateHookScript('post-tool-use');

// The hooks section for the PROJECT .claude/settings.json (2.1.260 schema:
// { hooks: { Event: [ { matcher?, hooks: [ { type: "command", command, timeout } ] } ] } }):
const hooksJson = adapter.generateHooksConfig('./.skillstate/skillstate.json', {
  scriptDir: '.claude/hooks/skillstate',
  commandFor: (event) => `node "$CLAUDE_PROJECT_DIR/.claude/hooks/skillstate/${event}.cjs" ${event}`,
});

// Merge into a live settings.json — preserves env/permissions/model and
// every foreign hook; byte-identical (no-op) when already wired:
const merged = adapter.mergeHooksConfig(existingSettingsText, {
  scriptDir: '.claude/hooks/skillstate',
  commandFor: (event) => `node "$CLAUDE_PROJECT_DIR/.claude/hooks/skillstate/${event}.cjs" ${event}`,
});

// Uninstall surgery: remove exactly the skillstate groups/handlers from a
// live settings.json (mixed groups keep their foreign handlers):
const { text, changed } = removeSkillstateHookGroups(liveSettingsText);

// Atomic persistence helpers (tmp + fsync + rename):
await adapter.saveHookScript('post-tool-use', '.claude/hooks/skillstate/post-tool-use.cjs');

API / Exports

Root path @skillstate/claude exports:

  • new ClaudeAdapter() — implements PlatformAdapter (name = 'claude'): injectState, extractPatch, extractAction, formatPrompt.
  • generateHookScript(event, statePath?): string — event is 'user-prompt-submit' | 'session-start-compact' | 'post-tool-use'. Accepts a raw path or a { root, name } ref confined by resolveStatePath (.. escapes throw). The path only documents the header — the script resolves the state from the session cwd.
  • generateHooksConfig(statePath?, options?): string — JSON with ONLY the hooks section. Options: scriptDir, command, commandFor (per-event override — the CLI passes a $CLAUDE_PROJECT_DIR-anchored template to make the installed hooks PROJECT-LOCAL), timeoutSeconds (default 30).
  • mergeHooksConfig(existingJson, options?): string — idempotent merge into a live settings.json; preserves every other key.
  • removeSkillstateHookGroups(existingJson): { text, changed } — surgical uninstall (pure groups dropped, mixed groups trimmed, empty events removed).
  • claudeHookScriptPath(scriptDir, event): string.
  • saveHookScript(event, target, statePath?), saveHooksConfig(target, statePath?, options?) — atomic writes. (SKILL.md generation is host-neutral and lives in the CLI: skillstate init writes the shared .claude/skills/skillstate/SKILL.md.)
  • generateAppendPrompt(): string — mode-switch prompt boilerplate.
  • CLAUDE_HOOK_EVENTS, CLAUDE_SESSION_START_MATCHER (^compact$), CLAUDE_POST_TOOL_USE_MATCHER (^Bash$), CLAUDE_HOOK_TIMEOUT_SECONDS.
  • resolveStateForCwd(cwd, home?) — re-export of the core resolveHostStateForCwd (single source of truth for the per-project resolver).

Notes

  • Honest limitation. Claude Code hooks cannot trim history and cannot inject context at compaction time, so prompts are O(T) with fresh state per turn. The injected state is authoritative — history is not.
  • Inert without state. The generated scripts resolve the per-project state path first and emit {} (nothing added to context, nothing written) when the session cwd has no skillstate state — hooks NEVER create state files, so a fresh clone behaves like a vanilla Claude Code install.
  • The generated scripts are self-contained CommonJS. Malformed patches are never persisted — the ⊕ merge either fully applies or the hook reports a systemMessage and leaves the state file untouched.
  • Depends on @skillstate/core for PromptTransformer, atomicWriteFile, resolveStatePath, and the shared resolveHostStateForCwd.

Related

License

MIT © 2026 Vitaly Kuzyaev