NAPL

File formats

The complete reference for .napl prompts, the .mapl reply, the emoji aliases, and the .napl/ state directory.

This page is the exhaustive reference for every file NAPL reads and writes: the .napl prompt you author, the .mapl reply the toolchain generates, the emoji spellings of both, and the .napl/ directory that holds the derived state. For the narrative behind these, see Writing prompts that hold and Drift, moves & reconcile.

The .napl prompt

A prompt is YAML frontmatter (machine-facing metadata) followed by markdown prose (the contract handed to the coding agent). Edit the example below and the validator runs as you type. Break the YAML or misspell a field and the squiggle appears.

Loading example…

Frontmatter fields

FieldTypeRequiredDescription
modulestringyesThe module's identity: a name, which may be path-like (auth/session). Not a file path.
depsstring[]noDependency module names. Surfaced to the agent as Declared dependencies: … and enforced at gen.
targetsstring[]noTarget languages to generate for, e.g. typescript, react, rust.
testsTest[]nogiven/expect cases as data. They gate every generation.
cratestringnoRust target only: modules sharing a crate value share one member crate with a toolchain-owned manifest.

Each tests entry is { name, given, expect }, all data. Behavior that can't be expressed as a given/expect pair belongs in the prose contract, not the frontmatter.

deps declares the where of a dependency; the imperative to use it rather than reimplement it lives in the prose (see load-bearing sentences).

The .mapl reply

napl gen writes a .mapl file per module: the machine layer's answer, regenerated on every compile. Its top level is { module, target, entries }; each entry records the prompt lines it refers to and one of four kinds.

greeting.mapl
- promptLines: [12, 14]
  kind: assumption
  message: Return type left unspecified
  reasoning: >
    The prose does not name the return type. Chose a plain string.

Entry fields

FieldTypeDescription
promptLinesLineRangeThe 1-based body line(s) the entry refers to (scalar n or [a,b]).
kindsee belowOne of ambiguity, assumption, no-op, note.
messagestringRequired, non-empty: the one-line summary.
reasoningstringOptional prose reasoning (defaults empty).
suggestionstring | nullOptional suggested rewording, chiefly for ambiguity.

Kinds and severities

The kind maps to an editor diagnostic severity: this is how ambiguity becomes a first-class compile diagnostic:

KindSeverityMeaning
ambiguityerrorYour words were unclear. Red squiggle on the exact words, usually with a rewording.
assumptionwarningA decision your prose left open; the model chose one.
no-opwarningThe prompt changed but the code didn't: the entry must say why, or the gen fails.
noteinformationHover-visible reasoning about why the code is shaped this way.

Emoji aliases

Each side of the dialogue has a canonical extension and emoji aliases. Both spellings in a pair are byte-identical to every tool (discovery, LSP, grammar, the VS Code extension):

SideCanonicalAliasVoice
Human.napl.🧑what you write
Machine.mapl.🤖its margin notes

The human alias is a single code point on purpose. ZWJ sequences (a base emoji joined to another with a zero-width joiner) are rejected so filenames stay filesystem-safe and round-trip cleanly across tools and shells. Override the human alias in lock.json:

.napl/lock.json
{
  "model": "claude-sonnet-5",
  "promptAliases": [".🧑"]
}

Each override entry starts with ., carries a single code point after the dot, and may not contain a ZWJ. The mirror rule: napl gen writes .mapl for a .napl prompt and .🤖 for an emoji-spelled one. It mirrors your choice. Reading accepts both spellings on both sides.

The .napl/ directory

Committed by design: the durable record of every gen, and what lets napl status verify the prompt/code connection in CI without regenerating.

PathContents
src/<target>/Generated code, per target. Locked 0444 after tests pass.
map.jsonPer-module attribution of generated files and locked content hashes.
lock.jsonPinned model id, backend, agent preset, alias overrides.
ir/<module>.yamlDerived contracts: signatures, types, tests. Best-effort.
attribution/<module>.yamlPrompt-line to code-line span mappings. A hard gate at gen.
mapl/<module>.maplThe machine layer's reply.
journal.jsonlAppend-only gen history: prompt diff and per-file patch per gen.

Build artifacts (node_modules, dist, lockfiles, *.tsbuildinfo, Rust target/) are excluded from attribution and never locked.

Next: the CLI reference for every command that reads and writes these files.

On this page