Varun Kulkarni
All projects

Sigil

Semantic document format for LLM-native context

  • AI Research
  • Language Design
  • Open Source

Where it started

Sigil came out of a problem I kept hitting while building multi-stage document-processing pipelines: context degraded every time information moved between models. A warning became indistinguishable from a suggestion. A procedural step looked like a fact. The words survived, but their meaning did not.

We were passing a lot of Markdown around because it was convenient and every model already understood it. But Markdown mostly describes presentation. A human can infer that bold text is important or that a paragraph beneath a heading is rationale; a parser only sees decorated text. Once that text is split for retrieval or handed to another model, those relationships become even easier to lose.

The idea

My core bet was simple: in machine-primary documents, meaning should be part of the syntax. Sigil gives every block an explicit type from a small, fixed vocabulary. A ! warn is always a warning, a * fact is always an asserted truth, and a ^ context block always explains its parent.

Markdown — meaning inferred
Always wait for networkidle before
inspecting the DOM.

This matters because JavaScript may
still be loading.
Sigil — meaning declared
! warn: always wait for networkidle
  before inspecting the DOM
  ^ context: JavaScript may still be
    loading
The words are almost identical. The difference is that a parser no longer has to guess which sentence is the warning and which one explains it.

I don’t see Sigil as a replacement for Markdown. Markdown is still better when the reader is primarily a person. Sigil is for the awkward layer between models, agents, retrieval systems, and people—the places where content needs to stay readable but also carry enough structure to be dependable.

Designing the format

I wanted the language to remain easy to inspect in a text editor, so I resisted turning it into verbose JSON or XML. The markers are compact, nesting is controlled by indentation, and there are no closing tags. The format looks lightweight, but the choices underneath it are intentionally restrictive.

Closed vocabulary
Models get a finite set of valid concepts instead of inventing new labels.
Two-space indentation
Scope stays obvious to a person and deterministic to a parser.
Context as a child block
A rule and its rationale remain connected when a document is chunked.
Strict and lenient modes
Authored files can be exact; generated files can still be recovered.

The closed vocabulary matters most. Open-ended labels feel flexible, but they drift quickly when models generate them. A fixed set gives the parser predictable input and gives a model a bounded decision: is this a fact, warning, step, example, uncertainty, or something else the specification already understands?

Building the implementation

I treated the specification as the product and the TypeScript package as its reference implementation. That changed the order in which I built things:

  1. Define the document header, block vocabulary, nesting rules, annotations, and typed references in the specification.
  2. Encode the grammar with Peggy, then produce a typed AST rather than a loose object tree.
  3. Add validation, serialization, and Markdown conversion around the parser.
  4. Write conformance fixtures so another implementation can prove it reads the same valid and invalid documents.
LLM outputA model writes a .sgl document
Parse + validateThe CLI checks syntax and meaning
Typed ASTFacts, warnings, and steps stay distinct
Next systemA retriever or agent uses the structure
Sigil acts as the interchange layer between generated text and the systems that need to reason about it.

The parser has two modes because generated text is never perfectly clean. Strict mode stops on a specification violation and is useful for authoring or CI. Lenient mode returns the best document it can plus line-level warnings. In an agent pipeline, recovering most of a generated document is often more useful than rejecting all of it.

A Sigil document

This is a shortened skill file. The header can be queried before loading the body, the trigger and skip rules are explicit, and the reason for the warning stays attached to it.

%% skill
name: webapp-testing
version: 1.0.0

@ trigger: user asks to test a web application
@ skip: user is testing a CLI tool

# Setup
  ! warn: wait for networkidle before inspecting the DOM
    ^ context: JavaScript may still be loading

  $ step: start the development server
  $ step: navigate to the application
  $ step: run assertions

The npm package exposes the parser, validator, serializer, converters, and a small CLI. It can turn a .sgl file into JSON, validate it against the spec, round-trip it back to Sigil, or convert it to and from Markdown.

Where it fits

  • Agent skills: triggers, exclusions, steps, and constraints have explicit types.
  • RAG pipelines: retrieved chunks retain whether they are facts, warnings, examples, or uncertain claims.
  • Agent memory: facts can carry confidence, provenance, and temporal annotations.
  • LLM-to-LLM handoffs: downstream models receive structured meaning without giving up human readability.

Current status

Sigil is open source and still deliberately early. The language specification is an active 0.1.0 draft, and the sigil-lang reference package is currently at 0.3.2. I’m keeping the vocabulary conservative while real usage exposes weak spots; I would rather make a small semantic system dependable than grow it before the core ideas hold up.

The next direction I’m interested in is querying: asking a document for every high-confidence fact, every critical warning, or every step activated by a particular trigger. At that point, the document stops being a flat text file and starts behaving like a compact knowledge layer.