Repository navigation
Description
Summary
iwes already completes links (trigger [, configured under [completion]).
This asks for the same treatment for frontmatter: complete field names and enum
values from the Document Schema that .iwe/config.toml already binds to the
document's path.
Motivation
In a workspace with path-bound schemas:
[schemas.article]
match = "data/stories/*".iwe/schemas/article.yaml already declares the vocabulary:
stage:
enum: [pitch, assigned, research, draft, review, published, shelved]
description: where the story sits in the pipeline
format:
enum: [nyhed, analyse, kommentar, interview, reportage, feature, faktatjek, andet]While editing data/stories/2026-08-31-example.md, none of that is available at
the cursor. You type stage: from memory and find out at
iwe schema validate — or at commit time — whether the value was in the enum.
The schema is bound, loaded, and knows the answer; it just isn't reachable while
writing.
Why this can't be solved editor-side
The obvious workaround is yaml-language-server with the schema mapped to the
file. It doesn't apply: LSP servers attach per buffer filetype, and frontmatter
lives inside a markdown buffer, so a YAML server never attaches. Treesitter
injection highlights the region but does not route it to another server.
That leaves the markdown server as the only one in position to answer. For a
schema-carrying workspace, iwes is the only candidate.
Why it should fit the architecture
From the discussion in #374, Document Schema validation is deliberately local —
every schema node validates the node it matched, with no shared state and no
second pass.
Frontmatter completion has the same property. The completion at a cursor is
derived from the schema node matched at that frontmatter path, for the schema
already bound by path glob. No symbol table, no cross-document resolution, no
accumulated state — the same locality that makes validation composable. It also
strengthens an existing path ([completion]) rather than opening a new one.
Possible scope, smallest first
- Key completion — at a frontmatter path, offer the
propertiesof the
matched schema node, withrequiredfields ranked first. - Enum value completion — after
field:, offer that field'senum. - Hover — surface the schema's
descriptionfor the field under the
cursor.
Tier 2 alone would carry most of the value; a mistyped enum is the common error
and the one validation reports last.
Notes
Happy to test against a real workspace — this comes from daily use of a
schema-heavy one (a newsroom graph with article, beat, source, task,
plan and hub types, all path-bound).
Nothing here asks for new state in the server: the schemas and the parsed
frontmatter are already in the process.
Activity
kiil commentedon Aug 31, 2026
Correcting myself: the "this can't be solved editor-side" section above is
wrong.
yaml-language-servercan be pointed at markdown, and frontmattercompletion does work. I tested it after filing this.
What works, in Neovim:
Verified against a real workspace: key completion offers the schema's unset
properties, value completion offersstage's enum (pitch, assigned, research, draft, review, published, shelved), and an invalid value reportsValue is not accepted. Valid values: ...on the frontmatter line.So this issue is no longer "there is no way". It's "the way costs five moving
parts, and four of them exist only because the server on the other side isn't
IWE."
The Document Schema has to be split.
.iwe/schemas/*.yamlis not JSONSchema — the frontmatter node sits under a
frontmatter:key besidesections:. Using it with yamlls means generating standalone JSON Schema filesfrom that one node and regenerating them whenever a schema changes. That is a
second source of truth that drifts silently.
Path bindings get maintained twice.
[schemas.article] match = "data/stories/*"in.iwe/config.toml, and the same glob again in the editorconfig. Nothing keeps them in sync.
The prose becomes YAML. yamlls parses the whole file as a YAML stream, so
the body produces junk:
*italics*is read as an alias(
Unexpected alias at node end), and the rest collapses into oneUnexpected scalar token in YAML streamspanning the document. Usable onlywith a diagnostic filter that drops everything below the closing
---.Formatting is a live hazard. yamlls advertises
documentFormattingon themarkdown buffer. With format-on-save enabled — the default in several
distributions — a YAML formatter is one keystroke from rewriting a prose
document. It has to be turned off deliberately, and nothing warns you.
Only frontmatter is covered.
sections:and block structure get nothing,so
iwe schema validatestays the authority regardless.Every editor redoes it. The above is ~110 lines of Neovim Lua, including
the fence-aware diagnostic filter and workspace-root resolution for the schema
paths. None of it transfers to another editor.
iweshas the schemas, the path bindings and the parsed frontmatter already,and it knows where the frontmatter ends — so none of these five costs exist on
that side. That is the argument for tier 2 (enum value completion) more than
the original "no alternative" framing was.
Happy to share the full Neovim config if it's useful as a reference for what
the native version would replace.