anthropics / anthropics/claude-code

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

Open
#93,944 1 comment 0 reactions 0 assignees View on GitHub
area:plugins bug platform:macos
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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:[@ver]` or `github:/@#.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

```shell
# 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:

```json
{
"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="
}
]
}
}
}
```

2. `claude plugin validate ` → `✔ Validation passed`, no warning.
3. Start a session, open a `.gd` diff or render a ```gd fenced block → no highlighting.
4. 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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.