Where a Claude Code plugin keeps Sume state: CLAUDE_PLUGIN_DATA

A plugin's data directory survives updates, while its root changes. Where to put a Sume call log or cache, and when uninstalling deletes it.

3 min readSume
All posts

Write plugin state, such as a log of Sume calls, to ${CLAUDE_PLUGIN_DATA}, not to the plugin root. The plugin manifest reference says the data directory is ~/.claude/plugins/data/<id>/, is created on first reference, and is kept across plugin updates. ${CLAUDE_PLUGIN_ROOT} changes when the plugin updates, so anything written there can vanish.

By default Claude Code deletes the data directory when you uninstall the plugin from the last place it is installed, unless you use --keep-data.

Root versus data

The reference defines three path variables.

Plugin path variables (read 2026-10-08)
VariableResolves toUse for a Sume plugin
CLAUDE_PLUGIN_ROOTThe installed version of the pluginHook scripts and bundled files; do not write state here
CLAUDE_PLUGIN_DATA~/.claude/plugins/data/<id>/A call log, a cache of catalog lookups, saved job notes
CLAUDE_PROJECT_DIRThe project rootProject-local config the team commits

A hook that records Sume calls

Hook commands receive CLAUDE_PLUGIN_DATA in their environment. This script appends the tool name and idempotency key of each call. Register it as a PreToolUse command hook in the plugin's hooks/hooks.json with a matcher for the Sume prefix.

import json
import os
import sys


def main() -> None:
    data = json.load(sys.stdin)
    folder = os.environ.get("CLAUDE_PLUGIN_DATA")
    if not folder:
        return
    os.makedirs(folder, exist_ok=True)
    args = data.get("tool_input") or {}
    row = {"tool": data.get("tool_name"), "key": args.get("idempotency_key")}
    with open(os.path.join(folder, "sume-calls.jsonl"), "a") as out:
        out.write(json.dumps(row) + "\n")


main()

Why the idempotency key is worth keeping

Sume's docs describe idempotency_key as a stable key for transport and dedup on write and paid tools. If a session dies after you submit, the log tells you which key you used, so you can resend the same call with the same key rather than starting a second paid job. Treat that as a habit, not a guarantee: read Sume's docs for how a repeated key behaves before you rely on it for billing.

  • Do not log the API key or any bearer token.
  • Use --keep-data when you uninstall if the log matters.
  • Do not store state in the plugin root; an update replaces it.

Naming and cleaning up

The <id> in the path is the plugin identifier with every character other than a letter, digit, underscore or hyphen replaced by a hyphen, so a plugin named sume-media lands in a folder you can guess. Keep file names inside it stable and add a version field to any file format you write, because a plugin update keeps the folder but may change what the new hooks expect.

Rotate the log. A line per call is tiny, but a month of automated renders adds up, and a log that grows without limit is the sort of thing nobody notices until a disk fills.

A short test

Install the plugin, trigger one hook, and look for sume-calls.jsonl in the data folder. Update the plugin to a new version and confirm the file is still there. Uninstall without --keep-data, and confirm it is gone. Three checks, five minutes, and you will know exactly how the log behaves.

What Sume does not do

Sume does not read the local log, and the file is not a source of truth for spend. The source of truth for jobs is jobs_list on the Sume side, and a local file can fall behind it.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume