shib·bo·leth — a small utterance that reveals what one is.
A Neovim plugin that inserts and updates schema-pointer directives in configuration files, so any editor or LSP that reads them can validate the file against the right schema. Resolves candidate schemas by matching the buffer's path against a curated set of pairings.
This is meant to complement, not replace, your existing LSP / language-server setup. Instead of relying on per-machine editor config to bind a file to a schema, it writes a directive that rides in version-control within the file itself, so every collaborator's editor picks up the same schema without having a similar setup as yours.
Supports JSON, YAML, and TOML out of the box.
Bonus feature: Write a Vim filetype modeline so a file's intended filetype rides in version control — useful for extension-less scripts and ambiguous files.
| Filetype | Directive | Example |
|---|---|---|
| JSON | top-level $schema property |
"$schema": "https://json.schemastore.org/package.json" |
| YAML | # yaml-language-server: $schema=... modeline |
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json |
| YAML (alt) | # $schema: ... (IntelliJ-compatible) |
# $schema: https://json.schemastore.org/github-workflow.json |
| TOML | Taplo #:schema directive |
#:schema https://json.schemastore.org/pyproject.json |
| any | Vim filetype modeline | # vim: set ft=ruby: |
With lazy.nvim:
{
'bezhermoso/shibboleth.nvim',
event = 'VeryLazy',
opts = {},
}Requirements:
- Neovim 0.10+
- Tree-sitter
jsonparser (for the JSON handler) curl(only if you use the SchemaStore loader)
Run :checkhealth shibboleth to verify.
" Schema directive (the primary operation)
:Shibboleth " open schema picker for current buffer
:Shibboleth <url> " set schema URL directly (no picker)
:Shibboleth remove " remove existing directive
" Filetype modeline (the bonus feature)
:Shibboleth modeline " write `# vim: set ft=<bo.filetype>:` modeline
:Shibboleth modeline <ft> " write modeline with explicit filetype
:Shibboleth modeline remove " remove modeline
" SchemaStore catalog
:Shibboleth schemastore " load catalog (uses cache after first fetch)
:Shibboleth schemastore refresh " force refetch from network:Shibboleth resolves candidates by matching the buffer's path against a
curated set of file globs (e.g. package.json → npm schema,
**/.github/workflows/*.yml → GitHub Actions schema,
**/.claude/settings.json → Claude Code settings).
:Shibboleth modeline uses the buffer's existing filetype (vim.bo.filetype).
If neither the buffer's filetype nor an explicit <ft> argument is available,
it prompts for one via vim.ui.input.
Note
For extension-less scripts where you want the filetype detected from a
shebang, install something like
shebang.nvim or rely on
Neovim's built-in filetype detection (vim.filetype). Then run
:Shibboleth modeline to persist that filetype hint into the file.
require('shibboleth').setup({
yaml = {
style = 'modeline', -- 'modeline' (default) or 'intellij'
},
fallback_commentstring = '# %s',
-- Add custom schemas
schemas = {
['my-thing'] = {
name = 'My Thing config',
url = 'https://example.com/my-thing.schema.json',
ft = { 'yaml' },
},
},
-- Add custom glob patterns. `schema` references a key from the schemas table above.
patterns = {
{ pattern = '*.mything.{yml,yaml}', schema = 'my-thing' },
},
})For the long tail of schemas (1,200+ entries from json.schemastore.org), opt in via either the command or the Lua API.
:Shibboleth schemastore " load (uses local cache after first fetch)
:Shibboleth schemastore refresh " force refresh from the networkrequire('shibboleth.registry.schemastore').load()
require('shibboleth.registry.schemastore').load({ force = true })This fetches the catalog of schemas and merges them into your registry.
The catalog is cached at stdpath('cache')/shibboleth/catalog.json;
subsequent loads use the cache unless refresh (or force = true) is passed.
make test # run the plenary test suite
make test-watch # re-run on every save (requires entr)
make lint # luacheck if installedThese tools are complementary, not competing.
- yaml-companion.nvim
picks a YAML schema and tells the LSP about it via
workspace/didChangeConfiguration. The choice lives in your Neovim session and is YAML-only. - SchemaStore.nvim supplies catalog data to your LSP server config.
- shibboleth.nvim writes a persistent directive into the file itself, across JSON / YAML / TOML, so the schema choice is portable, version- controlled, and visible to any editor with the right LSP — not just your Neovim.
You can use all three.