[BUG] Plugin manifest experimental.syntaxHighlighting.hljsLanguages validates but never registers a grammar

Status Open
Reported on v2.1.270
Maintainer reply None cached
Activity 1 comment · opened Sep 13, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

A plugin manifest can declare experimental.syntaxHighlighting.hljsLanguages to register a custom highlight.js grammar. claude plugin validate accepts it with no warning — but at runtime nothing happens at all: the grammar is never fetched, no language is registered, and no error is raised anywhere.

The 2.1.270 bundle clearly contains the machinery:

  • the manifest schema — an array (max 16) of { id, remote, integrity }, where id matches ^[a-z][a-z0-9_-]*$, remote matches npm:<pkg>[@ver] or github:<owner>/<repo>@<ref>#<path>.js, and integrity is an SRI hash; the object is .strict();
  • a registry — addPluginLanguage, registerResolvedPluginLanguage, clearPluginLanguages, isReservedLanguageId, isPluginLanguageId;
  • a telemetry event plugin_hljs_languages with a resolve_failed outcome;
  • the error string `plugin hljs grammar '${id}' failed to resolve at registration: ${reason}`;
  • extension resolution that already consults plugin languages: the file extension is lowercased, checked against the built-in maps, then against isPluginLanguageId(ext).

So the feature appears to be shipped on the schema and registry side, but nothing connects the manifest to the registry at session start.

What Should Happen?

Either the declared language registers and .gd diffs / ```gd fences get highlighted, or a diagnostic is shown explaining why it was refused. Silently accepting a manifest and doing nothing gives the plugin author no way to tell the difference between "not supported yet" and "my manifest is wrong".

Error Messages/Logs

# A full session started with --debug-file. The plugin loads:

[DEBUG] Loaded 4 installed plugins from ~/.claude/plugins/installed_plugins.json
[DEBUG] Found 1 enabled plugins with scopes: gdscript-highlight@gdscript-local(user)
[DEBUG] Loading plugin gdscript-highlight from source: "./gdscript-highlight"
[DEBUG] Total plugin workflows loaded: 0
[DEBUG] Total plugin commands loaded: 0
[DEBUG] Total plugin agents loaded: 0
[DEBUG] Total plugin skills loaded: 0
[DEBUG] Registered 0 hooks from 1 plugins
[DEBUG] Loaded plugins - Enabled: 1, Disabled: 3, Commands: 0, Agents: 0, Errors: 0

# grep over the whole 300-line debug log:
#   hljs               0
#   grammar            0
#   syntaxHighlighting 0
#   experimental       0
#
# and no [ERROR] line about a grammar — while unrelated [ERROR] lines from the
# same run (a failing MCP server, a lock acquisition) do land in the same file.

Steps to Reproduce

  1. Create a plugin with this manifest:
{
  "name": "gdscript-highlight",
  "version": "0.1.0",
  "description": "GDScript syntax highlighting",
  "author": { "name": "..." },
  "experimental": {
    "syntaxHighlighting": {
      "hljsLanguages": [
        {
          "id": "gd",
          "remote": "github:Repiteo/highlightjs-gdscript@cc1d048b6c3127c1badf233daf411f8fe9914b0b#src/languages/gdscript.js",
          "integrity": "sha256-5eI3NzW6c7bciH+BpEEMuV4ooUj58R8N1BlwTIjBZvc="
        }
      ]
    }
  }
}
  1. claude plugin validate <path>✔ Validation passed, no warning.
  2. Start a session, open a .gd diff or render a ```gd fenced block → no highlighting.
  3. Check every plausible cache — ~/.claude, ~/Library/Caches, ~/.cache, ~/.local/share/claude, /tmp, $TMPDIR → the grammar was never downloaded.

Tried both plugin load paths, with identical results:

  • a skills-directory plugin (gdscript-highlight@skills-dir, discovered in place);
  • a plugin installed from a local marketplace via claude plugin install, copied into ~/.claude/plugins/cache/gdscript-local/gdscript-highlight/0.1.0/ (verified the experimental block survives the copy).

Tried both remote forms in a single manifest — one entry github:, one npm:@exercism/highlightjs-gdscript@0.0.1. Neither is fetched, so this is not a URL-parsing problem in one of the two forms.

The remote itself is fine: the URL returns HTTP 200, the file's sha256 matches the declared integrity, and it is a plain export default function (hljs) { … } module — the shape e.default ?? e expects.

gd and gdscript are not reserved ids: the string gdscript does not occur anywhere in the 2.1.270 bundle.

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

N/A

Claude Code Version

2.1.270

Platform

Claude subscription

Operating System

macOS

Terminal/Shell

iTerm2 / zsh

Additional Information

The field is undocumented: the public plugins reference describes experimental as exactly themes, monitors, evals, and neither the repository CHANGELOG nor the docs changelog mentions syntaxHighlighting or hljsLanguages. If the mechanism is simply not wired up yet, that is a perfectly good answer — but the validator accepting the block makes it look supported.

Two questions that would help plugin authors either way:

  1. Is experimental.syntaxHighlighting.hljsLanguages expected to work in 2.1.270, or is the loader side not connected yet / behind a rollout flag?
  2. If a plugin is not the intended route for adding a language, could GDScript be added to the bundled highlight.js languages? .gd has no entry in the extension-to-language table at all, which is the root of #48181 — open since April.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗