Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Usage

nessemble is driven from the command line. This page documents its options and subcommands.

Usage: nessemble [OPTIONS] [infile.asm]
       nessemble <COMMAND>

Commands:
  init       initialize new project
  scripts    install scripts
  reference  get reference info about assembly terms
  lsp        run the language server (stdio)
  format     format assembly source
  lint       lint assembly source
  coverage   report runtime coverage from a CDL capture
  help       Print this message or the help of the given subcommand(s)

Arguments:
  [infile.asm]  assembly source to assemble (stdin if omitted)

Options:
  -o, --output <outfile.rom>  output file
  -f, --format <NES|RAW>      output format
  -e, --empty <hex>           empty byte value
  -u, --undocumented          use undocumented opcodes
  -l, --list <listfile.txt>   generate list of labels and constants
      --mlist                 include labels created by macros in the list file
  -p, --pseudo <pseudo.txt>   use custom pseudo-instruction functions
      --root <dir>            project root for `@/`-relative paths
      --max-operations <n>    cap each pseudo-op script's Rhai operation count
      --time-scripts          report per-directive script call count and wall time
  -c, --check                 check syntax only
  -v, --version               display program version
  -L, --license               display program license
  -h, --help                  Print help

The help text above is generated by clap; run nessemble --help (or nessemble <command> --help) for the current output.

The lsp command starts the built-in Language Server for use with LSP-capable editors. The format command reformats assembly source (§ format) and the lint command reports style problems without rewriting it (§ lint). The coverage command reports coverage from an emulator CDL capture, the -p Rhai scripts, or both (§ coverage).

Options

-o, --output <outfile.rom>

Sets the filename where output is written. An outfile of - (or omitting the flag) writes to stdout.

nessemble infile.asm --output outfile.rom

-f, --format

Specifies the output format:

  • NES — an iNES ROM, complete with a 16-byte header.
  • RAW — raw assembled 6502 code.

The format is RAW by default, but if iNES header directives (.inesprg, .ineschr, …) are present, it becomes NES unless overridden.

-e, --empty <hex>

Sets the fill value for empty/unwritten ROM bytes. Defaults to FF.

nessemble infile.asm --empty 00

-u, --undocumented

Allows the use of undocumented ("illegal") opcodes.

-l, --list <listfile.txt>

Writes a list of labels and constants to the given file.

Labels defined inside a macro body are omitted by default, so the list is not cluttered with the per-invocation labels a macro emits each time it is called (for example a loop target uniquified with \@). Pass --mlist to include them.

--mlist

Includes labels created by macro expansion in the --list output. Has no effect unless --list is also given.

nessemble infile.asm --list listing.txt --mlist

Constants defined in macros always appear in the list; --mlist affects only the [labels] section. See Macros for more on macro-defined labels.

-p, --pseudo <pseudo.txt>

Points to a mapping file that enables custom pseudo-instructions. See Extending.

--root <dir>

Sets the project root that @/-prefixed filename arguments resolve against, overriding the usual walk-up for the nearest .nessemblerc, .nessemblerc.json, or .nessembleignore.

nessemble src/main.asm --root .

dir must exist; a missing or non-directory path is rejected before assembly starts.

--no-cache

Neither reads nor writes the custom pseudo-instruction cache: every directive's script runs. Reach for this when a build looks stale, or to confirm that a suspected caching problem is one.

--max-operations <n>

Overrides the runaway-script guard on every pseudo-op script, in place of the built-in default of 10,000,000 Rhai operations. 0 means unlimited.

nessemble src/main.asm --pseudo pseudo.txt --max-operations 50000000

--time-scripts

Prints a per-directive report to stderr after assembly: how many times each .foo-style directive was called, how many of those were cache hits versus real script runs, and the total wall time spent in it — busiest directive first. See Runaway-script guard and timing.

-c, --check

Checks the input for syntax errors only; produces no output.

-v, --version / -L, --license / -h, --help

Print the version, license, or usage message respectively.

Commands

init [<arg> ...]

Scaffolds a new project, prompting for any values not supplied as arguments:

nessemble init [filename] [prg] [chr] [mapper] [mirroring]
  • filename — file to create.
  • prg / chr — number of PRG / CHR banks.
  • mapper / mirroring — iNES mapper and mirroring.

scripts

Installs the bundled custom-pseudo-instruction scripts into ~/.nessemble/scripts. See Extending.

cache info | cache clear

Inspects or empties the custom pseudo-instruction cache in ~/.nessemble/cache.

nessemble cache info     # where the cache is, how many entries, how many bytes
nessemble cache clear    # delete every entry

Clearing is always safe: an entry is a saved result, never the only copy of anything, so the next build recomputes what it needs.

reference [<category>] [<term>]

Prints reference information from locally bundled data. With no arguments it lists the categories (instructions, directives, script); with a category it lists its entries; with a term it prints the details (e.g. reference instructions LDA).

The script category is the host API a custom pseudo-op script can call, grouped by domain:

nessemble reference script              # every function, method, and property
nessemble reference script nes_shade    # signature, summary, and a docs link

A name catalogued more than once prints each meaning — read_blob is both a method on an open file handle and a one-call function — and an entry that needs a build feature says so, since the WebAssembly build has neither filesystem access nor random numbers.

format [<opt> ...] <path> ...

Reformats nessemble assembly source in an opinionated, Prettier-style way: consistent indentation and comma spacing, .db/.dw/.color data consolidated a fixed number of values per line, a blank line after each RTS/RTI, collapsed runs of blank lines, and a normalized final newline. Formatting is cosmetic only — the assembled ROM is never changed.

nessemble format path/to/file.asm       # print formatted source to stdout
nessemble format --write path/to/dir    # rewrite files in place
nessemble format --check path/to/dir    # CI gate: exit non-zero if unformatted
  • A single file with no flags prints the formatted result to stdout, leaving the file untouched.
  • -w, --write rewrites each changed file in place and prints its path.
  • -c, --check writes nothing; it lists files that are not already formatted and exits non-zero — the gate for CI.
  • A directory is walked recursively (for the configured extensions, .asm by default) and requires --write or --check.
  • --config <file> uses <file> as the .nessemblerc; --no-config ignores any .nessemblerc and uses built-in defaults.

The editor Language Server's "format document" action runs this same formatter, so editors and the CLI produce identical output.

lint [<opt> ...] <path> ...

Reports style problems in nessemble assembly. Where format is Prettier, lint is ESLint: it only reports and never rewrites source.

nessemble lint path/to/file.asm       # report problems for one file
nessemble lint path/to/dir            # walk a tree and report problems
src/prg/07.asm
     42:1   warning  code block `sound_engine` has no nearby comment  require-block-comment
    103:1   warning  unknown comment directive `@nessemble-formt`  unknown-comment-directive

✖ 2 problems (0 errors, 2 warnings)

The rules:

RuleFlags
require-block-commentA block-opening label with no comment nearby — a named label whose preceding non-comment line is blank or the top of the file. Internal branch targets and anonymous labels are never flagged.
unknown-comment-directiveA comment directive naming no known directive (@nessemble-formt), or a known one with wrong arguments (@nessemble-format stride=x).
deprecated-comment-directiveA directive written with a deprecated alias — today, @fmt for @nessemble-format.
ineffective-comment-directiveA well-formed directive that cannot apply where it is written: in a trailing comment, a -next-line with no following line, a stride hint with no data run after it, or an unbalanced ignore-region bound. (An unclosed region is not flagged — that is the documented whole-file opt-out.)
invalid-routine-signatureA routine annotation that binds to no label (code intervenes, or the file ends), or names the same slot twice.
undeclared-clobberA routine that writes a register its @nessemble-clobbers omits — the annotation and the code disagree. Only routines that declared a clobber list are checked.
overdeclared-clobberA routine that declares a clobber its body cannot produce. Fires only when the body holds no unknowns (no macro invocation, unannotated call, indirect jump, or data run).
require-routine-docA called routine with no annotations at all. Off by default — switch it on per project once you are using the convention.
  • Each finding prints as LINE:COL severity message rule-id, grouped by file, with a problem-count footer; a clean run prints ✓ No problems.
  • Exit code: any error-severity finding fails the run (exit non-zero); warn findings do not, unless --max-warnings <n> is exceeded. This is the CI gate.
  • A directory is walked recursively (for the configured extensions, .asm by default), skipping .nessembleignore paths.
  • --quiet reports errors only (suppresses warnings).
  • --config <file> uses <file> as the .nessemblerc; --no-config ignores any .nessemblerc and uses built-in defaults.

Every rule defaults to warn except require-routine-doc, which defaults to off. Rules, their severities, the comment window, and the label-name ignore list are configured under the lint key of .nessemblerc. The editor Language Server surfaces the same findings inline as you type, including quick fixes for the deprecated directive spelling and for a register missing from a clobber list.

Suppressing a finding

Two directives silence findings at the site, for when a rule is wrong about a particular routine:

; @nessemble-lint-ignore-next-line [rule[, rule...]]
; @nessemble-lint-ignore start|end [rule[, rule...]]

Bare, they suppress every rule. With a comma-separated list of rule ids, only those. An unknown rule name is reported as unknown-comment-directive, so a typo cannot silently silence nothing.

These exist because the clobber analysis has two known blind spots, both of which force an author to choose between a false annotation and a false finding. Suppressing at the site is the third, better option:

Fall-through entry points. A routine's body is read as its own block plus the JSR/JMP targets it names; a routine that falls through into the next one is not followed. So assign_chr_bank below really does clobber A, X, Y — via the routine it falls into — but its own block writes no register, and overdeclared-clobber fires:

; @nessemble-lint-ignore-next-line overdeclared-clobber
; @nessemble-clobbers A, X, Y, [chr_bank_arg]
assign_chr_bank:
    STA <chr_bank_arg
                            ; falls through ↓
; @nessemble-clobbers A, X, Y
find_or_evict_chr_slot:
    ...

Save/restore pairs. A PHAPLA around a routine's body preserves A, but the restore is not modeled, so undeclared-clobber asks you to declare A clobbered — inverting what the tag means:

; @nessemble-lint-ignore-next-line undeclared-clobber
; @nessemble-clobbers X, Y, [draw_tmp]
ppu_set_xy_addr:
    PHA
    ...
    PLA
    RTS

In both cases the annotation stays truthful — it is what a caller needs to know — and exactly one bogus finding is suppressed.

The rules are the coverage directives' rules, because it is the same mechanism:

  • -next-line targets the next significant line, skipping blank and comment lines. That is what lets it sit above a whole @nessemble-param block and still land on the label, which is where the routine rules report.
  • start opens a region and end closes it; an unclosed region runs to end of file (the whole-file opt-out), regions do not nest, and a region never crosses into an .included file.
  • A directive in a trailing comment is inert, and reported.
  • Matching is by the line a finding is reported at. Most rules report at the label — including undeclared-clobber, overdeclared-clobber, and require-block-comment — so -next-line above the label reaches them. invalid-routine-signature and the comment-directive rules report at the annotation line instead, so use the region form to suppress those.
  • A suppressed finding is gone, not downgraded: it does not print, does not count toward --max-warnings, and does not affect the exit code, even when the rule's configured severity is error. Severity is your choice in .nessemblerc, so it is not a reason to withhold the escape hatch.
  • Suppression applies to lint findings only. It never silences a parse or assembly error.

coverage <infile.asm> --cdl <file.cdl> ...

Reports runtime execution coverage of an assembled ROM against a CDL (Code/Data Logger) capture an emulator wrote after running the ROM, line coverage for the -p Rhai scripts a build runs, or both. It never writes a ROM.

nessemble coverage main.asm --cdl capture.cdl                 # coverage.json + coverage.lcov
nessemble coverage main.asm --cdl capture.cdl --format lcov --out cov.lcov
nessemble coverage main.asm --cdl a.cdl --cdl b.cdl --emulator mesen
nessemble coverage main.asm -p pseudo.txt --scripts           # scripts only, no CDL, no emulator

At least one of --cdl or --scripts is required.

With --cdl, the source assembles with a byte-exact source map and each PRG-emitting line is classified as code (executed), data (read), mixed (both), or unaccessed (present but never touched). Only the PRG section is classified; lines that emit only CHR data are omitted.

  • --cdl <file> — the CDL to read; repeatable (multiple files are merged by bitwise OR). Required unless --scripts is given.

  • --emulator <fceux|mesen> — the CDL format, default fceux. FCEUX and Mesen flat masks are the same size but bit-incompatible, so there is no auto-detect; state the emulator that produced the file. (BizHawk's container format is not yet supported.)

  • --format <json|lcov|all> — report format, default all. JSON carries the full four-way class per line, plus a "kind" of "rom" or "script" per file; LCOV is line hit/not-hit for coverage tools and has no kind.

  • --out <path> — output file for a single format, or a directory for all (coverage.json + coverage.lcov); defaults to the current directory.

  • -p, --pseudo <pseudo.txt> — custom pseudo-op mapping, as in assemble mode.

  • --root <dir>project root for @/-relative paths, as in assemble mode.

  • --max-operations <n> — caps each pseudo-op script's Rhai operation count, as in assemble mode.

  • --scripts — also report line coverage for the -p Rhai scripts, so you can see which parts of a custom pseudo-op never ran during assembly. Each project script appears as its own file (each line executed or not); bundled ~/.nessemble scripts are excluded. Available when the binary is built with the coverage feature (on by default).

    Given without --cdl, this reports scripts alone: the source assembles without forcing NES mode or a source map, no CDL is read, and no --emulator is consulted — the shape a CI job without an emulator playthrough can produce. Every script the -p mapping names is included, even one whose directive the build never reaches (reported at 0%, not omitted); a script mapped under two directive names appears once. A run that instruments no script at all — no -p mapping given, or the mapping named nothing readable — prints a warning saying why instead of a silent, unscripted report.

  • --no-ignore — report every line, disabling the @nessemble-coverage-ignore… directives.

Source can exclude lines it does not want measured with the coverage ignore directives; excluded lines leave both the numerator and the denominator, and the run reports how many were dropped:

coverage: 812/900 lines (90.2%) — 14 lines, 1 file ignored

When both --cdl and --scripts contribute files, the single percentage above can move for reasons that have nothing to do with the ROM, so the summary also splits the two:

coverage: 812/900 lines (90.2%) — rom 780/840, scripts 32/60

The CDL must be the same size as this ROM's PRG+CHR (it carries no ROM identity of its own); a size mismatch is a hard error. Equal sizes still do not guarantee the CDL came from this exact build, so capture it from the ROM this source assembles to.

Comment directives

Some nessemble tools take instructions from the source itself, written as comment directives: a comment whose first token names the tool and what to do.

; @nessemble-<name> [args]   [; trailing prose]
DirectiveApplies toTool
@nessemble-format stride=N[,N,...]the next data run (skipping blank, comment, and label lines)format
@nessemble-coverage-ignore-next-linethe next significant linecoverage
@nessemble-coverage-ignore start | endevery line between the twocoverage
@nessemble-param <slot> [description]the routine below — a register it readslint, editor
@nessemble-returns <slot> [description]the routine below — a slot it defineslint, editor
@nessemble-clobbers <slot>[, ...] | nonethe routine below — what it destroyslint, editor
@nessemble-lint-ignore-next-line [rule[, ...]]findings on the next significant linelint
@nessemble-lint-ignore start | end [rule[, ...]]findings on every line between the twolint
@fmt stride=N[,N,...]deprecated alias of @nessemble-formatformat

The rules are the same for every directive:

The routine annotations are described in Documenting routines; the rules below apply to every directive.

  • It must be on its own line — a directive in a trailing comment (LDA #$00 ; @nessemble-…) does nothing, and is reported.
  • The @… token must come first in the comment, after the ; (or ;;, ;;;) and any spaces. A directive mentioned mid-sentence is prose.
  • Names are exact and lower-case; anything after the arguments and a second ; is free-text prose.
  • A directive applies to what follows it, and blank lines, comment lines, and label or constant definitions in between are skipped — so a directive can sit above the label that names its subject, and an explanation can follow the directive.
  • An unrecognized @nessemble-… name, or a known one with wrong arguments, is reported by lint and in the editor rather than silently ignored — that is what the namespace buys you. Ordinary @-comments (; @todo, ; @param) are never touched.

Excluding lines from coverage

Two directives keep lines out of a coverage report. Excluded lines leave both sides of the ratio — they are not counted as covered, and not counted at all — so the percentage reflects only the lines you meant to measure.

@nessemble-coverage-ignore-next-line excludes the next significant line; blank and comment lines in between are skipped, so an explanation can follow the directive:

; @nessemble-coverage-ignore-next-line
; only reachable from a mapper IRQ we can't trigger in CI
    JMP nmi_stub

@nessemble-coverage-ignore startend excludes a whole region:

; @nessemble-coverage-ignore start
mapper3_init:
    LDA #$00
    STA mapper_reg
; @nessemble-coverage-ignore end
  • An unclosed region runs to the end of the file — put a lone ; @nessemble-coverage-ignore start in the header to opt a whole file out. A file with nothing left to report is dropped from the report entirely (no SF: record) and counted as an ignored file.
  • Regions are per file: one does not extend into an .included file, and each included file carries its own directives.
  • Regions do not nest. A start inside an open region, or an end with no start, does nothing and is reported by lint.
  • Rhai scripts (under --scripts) honor both directives, written as // comments.
  • nessemble coverage --no-ignore reports every line regardless — useful in CI, or to see what the directives are hiding. The stdout summary always names how much was excluded, and the JSON report carries ignored / ignoredFiles counts.

Documenting routines

The 6502 has no calling convention: every routine invents its own, and the only record of it is usually a comment, if that. Three directives write that convention down where the tools can read it — which registers a routine takes, what it hands back, and what it destroys:

; Draw one metasprite from `metasprite_table` into the OAM shadow buffer.
;
; @nessemble-param   A  metasprite index into `metasprite_table`
; @nessemble-param   X  screen x, in pixels
; @nessemble-param   Y  screen y, in pixels
; @nessemble-returns C  set when the sprite was clipped off-screen
; @nessemble-clobbers A, X, Y, [oam_cursor]
draw_metasprite:
    ...
    RTS

Hovering any use of draw_metasprite — including the operand of a JSR, in this file or another open one — shows that table, so "does this call eat my Y?" is answered without leaving the call site.

Slots. A slot is a place a value lives across a call. The vocabulary is closed, so a typo is reported rather than silently accepted:

SlotMeaning
A, X, Ythe registers
Sthe stack pointer
Pthe whole status register
C, Z, N, V, D, Ione flag — @nessemble-returns C is how a 6502 routine returns a boolean
[symbol]a named memory location, e.g. [oam_cursor]
$NN, $NNNN, $NN-$NNan address or inclusive range, e.g. $10-$1F
none(clobbers only) preserves everything

Slot names are case-insensitive (a and A both work) and always render upper-case. Memory needs its brackets or its $: that is what lets @nessemble-clobbers AX be reported as a bad slot instead of quietly becoming a symbol named AX.

What the tags mean.

  • @nessemble-param and @nessemble-returns take one slot each, followed by a free-text description (a ; in it is part of the description). Repeat the tag for each slot.
  • @nessemble-clobbers takes a list, and means anything not listed is preserved. A returned slot is clobbered by definition and need not be repeated.
  • @nessemble-clobbers none claims the routine preserves everything. That is different from writing no @nessemble-clobbers at all, which claims nothing.
  • Annotations bind to the first label below them; blank lines and prose comments in between are skipped, so a summary can sit above the tags. A line of code in between binds them to nothing, and is reported.

The declaration is checked. nessemble lint compares each declared clobber list against what the routine actually writes:

src/prg/sprite.asm
     42:1   warning  routine `draw_metasprite` writes Y but does not declare it clobbered  undeclared-clobber
  • Only A, X, Y, and S are verified. Flags are documentation — nearly every instruction disturbs N/Z, so checking them would flag everything. Memory slots are documentation too.
  • Only routines that declared a clobber list are checked, so a project adopts this one routine at a time.
  • A routine's body runs from its label to the next block-opening label. A call to another annotated routine contributes that routine's declared clobbers; a call to an unannotated one, a macro invocation, an indirect jump, or a data run inside the body makes the body "not fully understood", which silences overdeclared-clobber but never undeclared-clobber.
  • A routine that falls through into the next one is under-reported rather than over-reported: the analysis prefers a missed warning to a wrong one. Where that costs a wrong finding — a fall-through entry point, or a PHA/PLA pair the analysis does not model — suppress it at the site with @nessemble-lint-ignore… and keep the annotation truthful.
  • The stack pointer counts as clobbered only for TXS. Pushes and pulls move S, but routines balance them.

.nessemblerc

Formatting is configurable, Prettier-style, via an optional .nessemblerc (or .nessemblerc.json) file discovered by walking up from the file or directory being formatted. It is JSON; every key is optional and takes the default shown below, so a project with no .nessemblerc still gets fully-formatted output. Unknown keys are rejected (to catch typos early).

{
  "extensions": [".asm"],
  "indentStyle": "space",
  "indentWidth": 4,
  "commaSpacing": true,
  "finalNewline": true,
  "indentDirectives": false,
  "alignContinuations": true,
  "dataPerLine": 8,
  "respectStrideHints": true,
  "blankLineAfterReturn": true,
  "maxConsecutiveBlankLines": 2,
  "mnemonicCase": "preserve",
  "hexDigitCase": "preserve",
  "overrides": []
}
KeyDefaultMeaning
extensions[".asm"]File extensions formatted during a directory walk.
indentStyle"space"Instruction indent: "space" or "tab".
indentWidth4Spaces per indent level (space style only).
commaSpacingtrue", " between values; false for tight commas.
finalNewlinetrueEnsure the file ends in exactly one newline.
indentDirectivesfalseIndent directive lines (.db, .dw, .include, …) to block depth like instructions. false pins them to column 0 (house style); true suits codebases that indent data under labels. Labels and constants stay at column 0 either way.
alignContinuationstrueAlign the continuation lines of a multi-line statement (operands wrapped onto the next line by a trailing comma) under the opening line's first argument. false indents them to the block indent (indentWidth). See below.
dataPerLine8Values per consolidated .db/.dw/.color line; 0 disables consolidation.
respectStrideHintstrueHonor ; @fmt stride=N[,N,...] comments (see below).
blankLineAfterReturntrueInsert one blank line after every RTS/RTI.
maxConsecutiveBlankLines2Collapse longer runs of blank lines down to this.
mnemonicCase"preserve"Case the instruction mnemonic: "preserve", "lower", or "upper".
hexDigitCase"preserve"Case hex-digit letters ($ab vs $AB): "preserve", "lower", or "upper".
overrides[]Per-glob option overrides (see below).

Directive names (.db, .DB) are never re-cased — nessemble is case-sensitive about them.

Stride hints

To override dataPerLine for one data block, place a ; @nessemble-format stride=N comment directive before it. Multiple strides cycle in order and the last one repeats:

; @nessemble-format stride=2
    .db $01, $02
    .db $03, $04

The hint binds to the next data run, skipping blank lines, comment lines, and label or constant definitions on the way — the run's own label and an explanatory comment are both transparent:

; @nessemble-format stride=3
; one row of the tile per line
palette_rows:
    .db $01, $02, $03
    .db $04, $05, $06

If the first thing that is not one of those is anything but a .db/.dw/ .color line, the hint applies to nothing and lint reports it as ineffective-comment-directive. format and lint resolve the target the same way, so a hint the formatter honors is exactly a hint the linter calls effective.

Deprecated spelling. The original ; @fmt stride=N still works and always will — it is an alias, not a removal. It is reported by the deprecated-comment-directive rule, and the editor offers a one-click rename. To migrate a tree in bulk:

grep -rl '@fmt' --include='*.asm' . | xargs sed -i 's/@fmt/@nessemble-format/g'

Continuation alignment

When a statement's operand list wraps onto further lines (a trailing comma continues it onto the next physical line), alignContinuations (on by default) lines up each continuation under the opening line's first argument:

    .metasprite $FA, $02, $00, $FA,
                $FA, $03, $00, $02,
                $02, $0D, $00, $FA

With alignContinuations: false, continuation lines fall to the block indent instead:

    .metasprite $FA, $02, $00, $FA,
    $FA, $03, $00, $02,
    $02, $0D, $00, $FA

The alignment is computed from the opening line's actual indent, so it stays correct together with indentDirectives. Under indentStyle: "tab" the continuation reuses the opening line's leading tab and then pads to the first-argument column with spaces. Only leading whitespace changes, so the assembled output is unaffected.

Overrides

overrides is an ordered list of { "files": <glob>, "options": { … } } entries; for each formatted file, later matching entries layer their options on top of the base config. Globs support *, **, and ?.

{
  "dataPerLine": 8,
  "overrides": [
    { "files": "src/data/**/*.asm", "options": { "dataPerLine": 16 } }
  ]
}

.nessembleignore

A .nessembleignore file (gitignore-style globs, one per line) excludes matching paths from directory walks. It is discovered the same way as .nessemblerc.

lint

The lint subcommand is configured under a lint key in the same .nessemblerc. With no config the linter is on with its defaults (every rule at "warn" except require-routine-doc, which is "off"; a comment window of 3; and no ignores), so nessemble lint is useful out of the box.

{
  "lint": {
    "rules": {
      "require-block-comment": ["warn", { "window": 3 }],
      "unknown-comment-directive": "error",
      "deprecated-comment-directive": "off",
      "require-routine-doc": "warn"
    },
    "ignore": ["^loc_[0-9A-Fa-f]", "^data_[0-9A-Fa-f]"]
  }
}
KeyDefaultMeaning
rules{}Per-rule severity. Each value is "off", "warn", or "error", or a [severity, { …options }] pair. Unknown rule names are rejected.
ignore[]Regexes matched against a label's name; a match exempts it from every rule. Anchors (^) are yours to add.

Severity. A rule at "off" is not run. An "error" finding fails the run (non-zero exit); a "warn" finding does not, unless the CLI's --max-warnings is exceeded. In the editor, findings appear at a gentle severity (Information for error, Hint for warn) with the nessemble-lint source, distinct from the assembler's own errors and warnings.

Rule options. require-block-comment takes a window (default 3): a block label is clean if any line within ±window lines carries a comment. The directive and routine-signature rules take no options.

Ignore patterns. List the name shapes that should never be flagged — most often machine-generated disassembly labels (loc_8000:, data_c123:). No patterns ship by default, so a fresh project flags every undocumented block until you opt specific shapes out. (Ignore patterns match label names, so they do not affect the comment-directive rules; silence those with a severity of "off". They do apply to the routine rules, which are keyed by the routine's label name.)

Per-glob overrides may carry a lint block too, so a data-heavy directory can loosen or disable a rule for its files:

{
  "overrides": [
    { "files": "src/data/**/*.asm",
      "options": { "lint": { "rules": { "require-block-comment": "off" } } } }
  ]
}