# Releases

Every release of aless and what changed in it, newest first, from the repository's changelog.

This page lists the releases of aless, newest first. Each entry says what the release added, changed, and fixed. The archives and installers of every release are on [GitHub](https://github.com/rjrodger/aless/releases). For more information about getting the newest release, see [Install aless](https://aless.tabnas.dev/how-to/install.html).

## [0.8.0](https://github.com/rjrodger/aless/releases/tag/v0.8.0), 2026-11-09

### Added

- A reload marks what it changed. A changed value turns yellow, a new
  value turns green, and a container that lost values counts them in
  red. Rails in the indentation lead from the root down to each change.
  A note under the tree lists the changes, with each value before and
  after.
- aless keeps up to 50 versions of each watched file. `[` and `]` show
  the version before and after the one on screen, `{` and `}` the
  oldest and the newest. A timeline above the status bar shows when
  each version was saved, and marks a save that did not parse.
- `d` and `D` go to the next and the previous change.
- `:set changes`, `:set nochanges`, `:set history=N` and
  `--no-changes`.
- `v` and `:history` list the versions in a history tab, the newest
  first, each with its changes. `Enter` opens a version in a tab of its
  own, which is not watched.
- `:ws FILE` writes the text of the version on screen. In the history
  tab, `:w` and `:ws` write the focused version.
- `--print-json FILE` prints the tree of FILE as JSON on standard
  output, the JSON `:w` writes, and exits. It needs no terminal: it is
  the one thing aless does without one. FILE `-` is standard input. A
  file that can't be read or doesn't parse prints its report on
  standard error, and the exit status is 1.

## [0.7.1](https://github.com/rjrodger/aless/releases/tag/v0.7.1), 2026-11-06

### Fixed

- YAML refuses an alias whose anchor does not come before it in the
  document (tabnas-yaml 0.5.27). The error names the alias and its
  line, for example `undefined alias: *hree`. Before, such an alias read
  as null, so a mistyped name lost its value without a sign. As a key,
  the alias read as its own text, such as `*hree`.

## [0.7.0](https://github.com/rjrodger/aless/releases/tag/v0.7.0), 2026-11-05

### Changed

- The explorer shows dot-files and dot-directories, such as `.github/`
  and `.env`. Before, it hid them unless `--hidden` or `:set hidden`
  asked for them. `:set nohidden` hides them.
- aless shows a number as its source spells it where the spelling is
  JSON's. Numbers such as `1.0`, `-0`, `1e21`, and an integer beyond
  2^53 keep their digits in the tree, in a folded preview, in search,
  and in the JSON that `:w` and the copy commands write. Before, aless
  gave these numbers as the nearest 64-bit float in its shortest form:
  `1`, `0`, and `1e+21`. For a spelling that JSON has no syntax for,
  aless still gives the value the spelling denotes. Two such spellings
  are `0x1F` in JSON5 and `1_000` in TOML. The source view shows the
  spelling.
- `--help` describes aless alone. So do the man page and the line aless
  prints when it cannot start.
- `F1` lists every key, command, and setting. Among them are the
  prompt's editing keys, the keys of the help and of the error report,
  `:tabfirst`, `:tablast`, `:e!`, `:expand`, `:collapse`, and the whole
  of `:set`. `F1` groups the keys, commands, and settings as the
  documentation site's Keys page does. The site's build writes the Keys
  page from the table `F1` shows.
- `--help` and the man page are rewritten in shorter sentences. They say
  that `-n` and `-r` number the rows. Before, `--help` and the man page
  said that `-n` and `-r` show line numbers. They give `--depth N` as
  the first N levels open, because that description matches what the
  option does. They give each format's nesting limit as aless reads that
  format. For example, Markdown's tree stops at 205 levels without an
  error. For ABNF, EBNF, and GBNF, the limit is 127 levels of nested
  groups.
- `--help`, `-h`, `F1`, and the messages aless shows use no em dash. For
  example, `aless 0.7.0:` heads the help. As a second example, the
  message of a failed `:format` or reload ends with
  `(! shows the report)`.
- The documentation site is rewritten. It gains a Formats reference
  page, a how-to guide to saving a document as JSON, and a how-to guide
  to a file that does not parse. aless draws every capture of the viewer
  on the site when the site is built. The build fails when a capture no
  longer matches what aless draws.
- The navigation in the site's header gains a Why page. The page tells
  why aless was written, in Richard Rodger's own words. It shows two
  captures of the viewer.
- The messages aless shows say what went wrong and what to do next. For
  example, an option aless does not know gives
  `--nope is not an option. aless --help lists the options.`
- `--help`, `F1`, and the man page name a key as the key is printed,
  such as `Ctrl+D` and `Shift+Tab`. Before, they wrote `C-d` and
  `S-Tab`.
- The documentation site and the text aless prints are rewritten in
  shorter sentences, each with one claim.
- The site's favicon is the logo's multitool.
- The site links a section by its directory, such as
  `https://aless.tabnas.dev/how-to/`. The site links the home page by its
  domain, `https://aless.tabnas.dev/`. No link names `index.html`.
- On the site, a code box or a table wider than its column no longer
  fades at its right edge.
- On the site, a box of commands has a copy button. In a box that shows
  a command with its output, the button copies the command alone,
  without the `$ ` prompt.

### Removed

- `--hidden`, since the explorer shows dot-files without it.

## [0.6.0](https://github.com/rjrodger/aless/releases/tag/v0.6.0), 2026-11-02

### Removed

- The output options and the interface for scripts and agents: `--json`,
  `--paths`, `--find`, `--where`, `--check`, `--path`, `--at`, `--limit`
  and `--compact`, the JSON error objects and the exit statuses 3 to 6,
  the Agent Skill and `--generate skill`, and the headless module behind
  them. aless is a viewer and nothing else. Without a terminal to draw on
  and read keys from (standard output a pipe or a file, no terminal to
  open, or `TERM=dumb`) it refuses to start, before reading any input,
  with one line on standard error and the exit status 2, where it
  printed the document as JSON; nothing but `-h`, `--help`, `-V` and
  `--generate` writes to standard output. A grammar that does not compile
  or cannot be read is refused the same way. Reading one of these formats
  in a script is `dmog`'s work (below), and `:w FILE` still writes a
  tab's document as JSON. The reference `--help` prints, the man page and
  the completions describe the viewer alone, and the site's tutorial for
  scripts and its guides to extracting values, checking files and giving
  an agent aless are gone.

### Changed

- The command the README points to for reading a document in a script,
  writing it as another format, and running a program over one is `dmog`
  (data mogrify), in [tabnas/dmog](https://github.com/tabnas/dmog): the
  `alchemy` command of tabnas/alchemy-cli, renamed.

## [0.5.0](https://github.com/rjrodger/aless/releases/tag/v0.5.0), 2026-10-24

### Removed

- The streaming exports and the programs: `--render`, `--alchemy`,
  `--alchemy-expr`, `--explain`, `--max-output` and `--key`; the output
  and program panes, with `--panes`, `--stacked`, `C-w`, `:vsplit`,
  `:split`, `:arrange`, `:pane` and `:only`; and the crates behind them,
  tabnas-transduce, tabnas-render and tabnas-alchemy. Writing a document
  as another format, and running an alchemy program over one, is the
  `alchemy` command's work, in
  [tabnas/alchemy-cli](https://github.com/tabnas/alchemy-cli): `alchemy
  translate --from FORMAT --to FORMAT FILE` and `alchemy run PROGRAM
  FILE`. aless reads, shows and prints JSON. `s` still shows a tab's
  text, coloured by its grammar, and `:w FILE` still writes its document
  as JSON.

## [0.4.10](https://github.com/rjrodger/aless/releases/tag/v0.4.10), 2026-10-23

### Changed

- JSON Lines is read through tabnas-jsonl's transducer part, a window at
  a time, where it was read a record at a time. A file or standard input
  of any size still passes through in a window's memory, `--max-size`
  still does not apply to it, and the output is the same. It takes about
  a fifth longer than the record-at-a-time read did. A `--timeout` that
  stops it is reported as one that stops any format's part is, where it
  named the line the record being read started on. When a writer to
  standard input goes quiet and `--timeout` stops the run, the records
  within the window not yet parsed are not written, where every record
  received was.
- CSV and TSV are read through tabnas-csv's transducer part, a window at
  a time, where they were read a record at a time. tabnas-transduce
  0.3.0 runs the part natively. A file or standard input of any size
  still passes through in a window's memory, `--max-size` still does not
  apply to it, and the output is the same. It takes two fifths to a half
  longer than the record-at-a-time read did, at a slightly lower peak of
  memory. A `--timeout` that stops it is reported as one that stops any
  format's part is, where it named the line the record being read
  started on, and the read-ahead past the records written is a 64 KB
  window, where it was a 256 KB chunk.
- A CSV or TSV header that names a column twice is settled as a JSON
  Lines record that repeats a key is. Each record keeps its last cell of
  the name, as `--json` does, and `--render csv` writes that. A stream
  that cannot keep the last, such as `--render json`'s, refuses the
  record before writing anything: a file is read again whole, within
  `--max-size`, and standard input fails with `DUPLICATE_MEMBER`, where
  the record-at-a-time read wrote the last cell.

## [0.4.9](https://github.com/rjrodger/aless/releases/tag/v0.4.9), 2026-10-22

### Changed

- A JSON or JSONC file exported through its format's transducer part is
  read a window at a time. tabnas-parser 0.12.15 parses from a reader,
  tabnas-transduce 0.2.12 streams a part's passes from one, and
  tabnas-json 0.5.19 and tabnas-jsonc 0.5.16 declare `lex.window`. (JSON
  Lines and CSV files are already read a record at a time.) The parse
  holds a window of the file rather than the whole text, so the memory
  such an export needs no longer grows with the file. What is written is what the file read whole writes: its
  byte-order mark skipped, bytes that are not UTF-8 replaced, and a
  stream the part refuses read again whole. Standard input, a pipe, and
  every other format are read as before.

## [0.4.8](https://github.com/rjrodger/aless/releases/tag/v0.4.8), 2026-10-22

### Changed

- Markdown is parsed whole and then streamed, as every format whose
  package ships no transducer is. It was streamed by tabnas-transduce's
  incremental source, which began only once the last line was in, so its
  output and its memory are as they were; aless no longer uses that
  source, which tabnas-transduce is retiring.

### Fixed

- YAML reads a sequence entry's mapping (`- a: ...`) as it reads any
  other (tabnas-yaml 0.5.26). A key the entry repeats is merged, where
  the later value was kept. A key with an empty value before a sibling
  key is null, where the sibling became its value. And an entry with
  more than one space after its dash reads, where it was refused.

## [0.4.7](https://github.com/rjrodger/aless/releases/tag/v0.4.7), 2026-10-21

### Changed

- JSON, YAML and XML stream through `--render` and `--alchemy` by the
  transducers their packages ship (tabnas-json, tabnas-yaml and
  tabnas-xml), which make a document's records of its parse's steps, as
  a grammar from the command line's annotations do. The records are the
  same, and they leave as the parse proceeds, as before.
  - Nothing of the parse is kept behind them, so a long YAML or XML
    document takes much less memory: 40,000 records of YAML in 60 MiB
    rather than 133, and of XML in 74 MiB rather than 355.
  - It takes longer: about a fifth longer for JSON, and four times as
    long for YAML and XML.
  - A YAML alias to a mapping or a sequence is read whole, as a stream
    of several documents is, when nothing has been written yet.
- JSONC, JSON5, jsonic, ZON and PGN stream through their packages'
  transducers too (tabnas-jsonc, tabnas-json5, tabnas-jsonic, tabnas-zon
  and tabnas-chess), so every format whose package ships a transducer is
  read through it. The records are the same, and they leave as the parse
  proceeds, as before.
  - jsonic keeps nothing of the parse behind them now: 40,000 records in
    65 MiB rather than 167.
  - It takes longer: about a tenth to a fifth longer for JSONC and
    JSON5, three and a half times as long for jsonic and ZON, and six
    times as long for PGN.
  - tabnas-chess 0.1.18 ships PGN's transducer, and tabnas-alchemy
    0.2.14 the natives it is written with.
- A document that repeats a member is read whole, when nothing has been
  written yet, unless its format keeps the last of the two, as JSON,
  JSONC and JSON Lines do: jsonic, JSON5 and YAML merge them, which their
  transducers stream one after the other.
- Reading a long document takes less memory (tabnas-parser 0.12.14).
  The engine's lexer kept a byte offset beside each character of the
  text, eight bytes a character, and keeps none now for a text that is
  all ASCII, where a character's place is its offset.

## [0.4.6](https://github.com/rjrodger/aless/releases/tag/v0.4.6), 2026-10-18

### Changed

- An alchemy program run by `--alchemy` no longer slows down as a value
  it builds grows (tabnas-alchemy 0.2.13). `push` and `pop` cost the
  same at any length of vector, and `string-join` adds to a long string
  without copying it.

## [0.4.5](https://github.com/rjrodger/aless/releases/tag/v0.4.5), 2026-10-18

### Changed

- A grammar from the command line with value annotations streams
  through `--render` and `--alchemy` as the JSON family does. aless
  generates a transducer from the annotations (tabnas-abnf 0.4.25), and
  the records leave as the parse makes them.
  - A failure part way leaves every record before it on standard
    output, with `output` partial. Before, nothing was written until the
    whole document had parsed.
  - A grammar whose first rule has no annotation, as in a grammar
    without any, builds the compiler's parse tree at its root, which
    holds the whole document's text before its children, so its
    documents are still parsed whole before anything is written.
- Markdown's loss note gives `whole` (tabnas-markdown 0.7.13): a link can
  name a definition that comes later, so a document's tree is complete
  only at its end. Its records were already written only once its last
  line was read.

## [0.4.4](https://github.com/rjrodger/aless/releases/tag/v0.4.4), 2026-10-14

### Changed

- A PGN database streams through `--render` and `--alchemy` a game at a
  time, as XML's elements do. tabnas-chess 0.1.17 stores a game in the
  database only once it is complete, and tabnas-transduce 0.2.8 lists
  `pgn` among the grammars it streams.
  - The games already written are not kept behind them. The text is
    still read whole, within `--max-size`.
  - A failure in a game leaves every game before it on standard output,
    with `output` partial. Before, nothing was written until the whole
    database had parsed.
  - PGN's loss note no longer has `whole`.

## [0.4.3](https://github.com/rjrodger/aless/releases/tag/v0.4.3), 2026-10-14

### Changed

- A `--render` or `--alchemy` run that fails part way stops at the end of
  a record its renderer marks, held by tabnas-render's writer (0.2.5)
  until the mark rather than found by scanning the bytes written: aless's
  own record scanner is gone, and its writer passes each record on whole
  the moment its end is marked (tabnas/alchemy#29).
  - A value directly inside the root JSON array or object is whole where
    it ends: a bare number no longer waits for the comma after it, so a
    failure after it leaves it on standard output, with `output`
    partial. Below `--path`, the first member of the object taken is a
    record like any other.
  - Another format's render leaves whole records where its package marks
    them (tabnas-jsonl 0.1.17, tabnas-yaml 0.5.24, tabnas-toml 0.5.18,
    tabnas-ini 0.5.20, tabnas-json5 0.5.16, tabnas-zon 0.5.17, tabnas-xml
    0.7.18, tabnas-css 0.5.16, tabnas-chess 0.1.16): a value inside the
    root in YAML, JSON5 and ZON, a root member's line in TOML, a line in
    INI and JSON Lines, a child of the root element in XML, a node of the
    stylesheet in CSS and a game in PGN. A render that marks none
    (Markdown, feeds, expressions, versions, C, `.proto` and the grammar
    notations) writes as it goes, as before.
  - A program's own text is held a record at a time where the program
    marks one: each item `concat-map` writes, and each `:record-end`
    among a `join`'s items (tabnas-alchemy 0.2.7).
  - A record longer than 16 MB is written as it comes; a JSON one is no
    longer cut at the end of one of its own values.

## [0.4.2](https://github.com/rjrodger/aless/releases/tag/v0.4.2), 2026-10-14

### Changed

- `whole`, in `--render`'s loss note and in an error carrying `loss`, is
  given for CSS too (tabnas-css 0.5.15): a stylesheet is read whole
  because the reader builds each rule, at-rule, declaration and comment
  before it adds the node to the list that holds it. Every format whose
  crate reads a document whole now says why.

## [0.4.1](https://github.com/rjrodger/aless/releases/tag/v0.4.1), 2026-10-13

### Changed

- `whole`, in `--render`'s loss note and in an error carrying `loss`, is
  given for nine more of the formats read whole before anything is
  written, where it was given for TOML and INI alone: feeds, `.proto`,
  PGN, expressions, versions, C and the three grammar notations now say
  why in their manifests (tabnas-feed 0.6.18, tabnas-proto 0.6.11,
  tabnas-chess 0.1.15, tabnas-expr 0.5.19, tabnas-semver 0.0.11, tabnas-c
  0.5.15, tabnas-abnf 0.4.24, tabnas-ebnf 0.1.19 and tabnas-gbnf 0.1.20).
  A C file, for one, is read whole because a conditional group is folded
  into one node only once the whole file is parsed.

## [0.4.0](https://github.com/rjrodger/aless/releases/tag/v0.4.0), 2026-10-13

### Added

- C source (`.c`, `.h`, tabnas-c 0.5.14), read as its concrete syntax
  tree, preprocessor directives parsed into it, and written by
  `--render c`. The tree is the
  one tabnas-c realizes from its arena on the parse's thread: each node
  its `kind`, `span`, `children` and `trivia`, each token its `tname`,
  `src` and `span`, and the members a node names its parts by (`operand`,
  `cond`), which repeat subtrees its `children` hold. Like CSS, `.proto`
  and PGN, `--render c` writes only that tree, and refuses another
  document before reading it with the `usage` error that names the
  program route. A C file's tokens are placed where its tree says, not
  by aligning values, and what the reader adds has no position. Its
  reader's limits are `too_deep` errors: tabnas-expr's 127 operations in
  an expression and 1,024 open rules, and tabnas-c's tree of 256 levels,
  with no position where the parse stopped between two tokens. A `.c` or
  `.h` file, read as plain text before, is read as C.
- A C tree is refused as `too_deep`, before it is written out, when it
  would hold more than 256 values a byte of the file written out (at
  least a million, and never more than 33,554,432, so that a long comment
  cannot raise the bound a short chain is held to), or more than 2,048
  bytes of names and strings a byte (at least 8 MB, and never more than
  256 MB, so that a long name in a subtree it repeats is held as well):
  its reader shares the subtrees it repeats, so a chain of subscripts or
  member accesses doubles the tree written out at each level, and 40
  member accesses in one expression would otherwise hold more values
  than a machine can.
- Grammars in ABNF (`.abnf`, tabnas-abnf 0.4.23), EBNF (`.ebnf`,
  tabnas-ebnf 0.1.18) and GBNF (`.gbnf`, tabnas-gbnf 0.1.19), each read
  as the grammar spec its compiler writes, `options` and `rule`s with
  the rules the compiler adds, and written by `--render abnf`, `ebnf` and
  `gbnf`. The three write one
  schema, so a grammar in one notation is written in another; any other
  document is the `usage` error that names the program route, and a spec
  the target notation cannot say (an action, a terminal none of its
  forms matches, in EBNF a counted repetition nested past the 128 levels
  its own reader reads, so ABNF's `*65"a"` and longer) is
  `TARGET_VALUE_UNREPRESENTABLE` before anything is written. A grammar's
  compiler keeps no places, so no node of its spec has a position, and
  the compiler's own limits are `too_deep` errors: groups and options
  nested about 500 levels in ABNF, 130 in EBNF and 128 in GBNF, and
  elements nested 128 levels. The compile runs on the parse's thread, or
  within `--timeout` on a thread of its own, which aless stops waiting
  for when the time is up, and does not start once it is; while a
  compile it stopped waiting for runs on, no other starts, and a later
  grammar in the run is the same `timeout` at once. `aless --check` on a
  grammar file now says whether it compiles; such a file, read as plain
  text before, is read as its spec. `--grammar` reads its grammar as
  before.

### Changed

- tabnas-expr 0.5.18. `--render expr` refuses a tree its reader would
  read back as another, with `TARGET_VALUE_UNREPRESENTABLE` naming the
  object's path where it meets it: a list led by an object whose `src`
  the reader takes for the list's operator, where that is no default
  operator's text, as a C syntax tree's lists are. 0.5.17 wrote such a
  list, and it read back with its leading object reduced to that text.
- tabnas-abnf 0.4.23, from 0.4.20, the compiler behind `--grammar` too.
- tabnas-bnf 0.1.30, the compiler the three notations and `--grammar`
  share. A cycle of rules whose alternatives start with one another,
  which its left-recursion pass multiplied until memory ran out (twenty
  such rules, 0.7 KB), is refused before anything is built, past 512
  alternatives added to one rule, at once and in every route; so is a
  grammar the pass would grow past 131,072 elements, a chain of 5,000
  rules each led by the next among them. A grammar of 10,000 rules
  compiles in under two seconds, where it took ten. What the compiler
  writes and holds is bounded too (3,500,000 units), so a grammar whose
  spec would pass that is refused rather than built.
- tabnas-feed 0.6.17, a version move.
- tabnas-proto 0.6.10. A `.proto` file is read through the crate's own
  descriptor tree (`to_descriptor_value`), so a descriptor's members now
  come in the order the crate's other runtimes give them: the lists every
  descriptor has first, then what a statement places (the syntax, the
  package, a field's `proto3Optional`) in the order of the statements.
  The output can differ from 0.3.0's in member order, and the package,
  held after the lists, is past where positions are aligned, so it has
  none. A number the reader reads as NaN (a digit separator, `1_0`) stays
  NaN: `--json` writes it as null, as before, an entry gives `"NaN"`,
  and `--render yaml` writes `.nan`. The refusals are as they were.
  `--render proto` writes a backtick literal as itself, where 0.6.8
  wrote one holding a line break as an aggregate its own reader refused,
  and refuses a string no spelling of a `.proto` file holds with
  `TARGET_VALUE_UNREPRESENTABLE`, before writing anything.

## [0.3.0](https://github.com/rjrodger/aless/releases/tag/v0.3.0), 2026-10-10

### Added

- Five formats more, read by the crates that carry their translation
  parts: CSS (`.css`, tabnas-css), Protocol Buffers'
  `.proto` files (`.proto`, tabnas-proto, read as their
  FileDescriptorProto in the JSON form protoc writes), PGN chess games
  (`.pgn`, tabnas-chess, named `pgn` as its manifest names it),
  arithmetic expressions (`-k expr`, tabnas-expr, each operation an array
  of its operator and its terms) and semantic versions (`-k semver`,
  tabnas-semver, read without the line break a file holding one ends
  with). A `.css`, `.proto` or `.pgn` file, read as plain text before,
  is read as its format.
- `--render` writes each of them, and Atom feeds through tabnas-feed
  0.6.16's render: `css`, `proto`, `pgn`, `expr`, `semver` and `feed`.
  An expression takes any document as it is and a feed any through its
  embedding. CSS, `.proto` and PGN write only the tree their own
  documents read as, and refuse any other document before reading it,
  as a `usage` error that names the route that can write one, a program
  that makes that tree (`--alchemy FILE --render proto`); a version takes
  only a tree that is a version, and refuses any other with
  `TARGET_VALUE_UNREPRESENTABLE` before writing anything.
- `whole` in `--render`'s loss note and in an error carrying `loss`: why
  a TOML or INI source is read whole before anything is written, in its
  format's own sentence (alchemy 0.2.6, tabnas-toml 0.5.17, tabnas-ini 0.5.19).

### Changed

- `--render` given a format's extension rather than its name
  (`--render rss`, `--render yml`) names the format's render
  (`--render feed`), where it said the format had none.
- `--render` reads JSON Lines, CSV and TSV a record at a time under
  `--path` too, as it does at the root: the path's value is
  taken from the records as they pass, and the rest of the file is read
  the same way to its end, so `--max-size` does not apply below the root
  either. What is written is what reading the file whole writes; a record
  the grammar refuses after the value was written fails the run with
  `output: "partial"`, as a refusal at the root does.
- `--render` and `--alchemy` write an XML document's records as the parse
  proceeds, as they do the JSON family's (tabnas-transduce 0.2.7,
  tabnas-xml 0.7.17), where they waited for the parse to end: a failure
  part way leaves every record before it written, with `output: "partial"`.

### Fixed

- A JSON Lines record that repeats a member (`{"a":1,"a":2}`), which its
  stream holds twice, was refused with `DUPLICATE_MEMBER` at the root
  though nothing had been written. A file is now read again whole, within
  `--max-size`, and its value written, the last of the two as `--json`
  reads it, at the root and below it. Standard input, which cannot be read
  again, keeps the refusal, with `output: "none"`.

## [0.2.0](https://github.com/rjrodger/aless/releases/tag/v0.2.0), 2026-10-10

### Changed

- `--render` composes every conversion through alchemy's `translate`,
  from the parts each format's crate declares: what a
  format cannot hold is written by the convention its manifest declares,
  never refused. A null in TOML is left out; NaN and the infinities are
  `null` in `--render json`, as in `--json`, and their names in CSV; a
  root TOML or INI cannot have is the one member of a table, and one JSON
  Lines, CSV or Markdown cannot have the one element of an array; a
  Markdown document with no table is the empty table; XML writes any
  document as the element tree its embedding declares.
- `--render csv` and every records format take rows of every kind: an
  array row's cells are its positions, a scalar row is one cell named
  `value`, and a row of another kind than the first has a cell where the
  first row's columns find one. A table of no columns is the empty
  document.
- The loss warning names every step that ran in `adapters`; `adapter`
  still names the one between a tree and a table. JSON declares its one
  loss, so `--render json` writes the warning too.

### Added

- `--key NAME`: the member a root is written under when the format's
  document must be a table (`items` by default).

## [0.1.1](https://github.com/rjrodger/aless/releases/tag/v0.1.1), 2026-10-09

The first release with prebuilt binaries. 0.1.0 went to crates.io alone,
published by hand; 0.1.1 is the same program, released the whole way: the
archives for Linux, macOS and Windows with their checksums and attestations,
the installers, the Homebrew tap, and crates.io by trusted publishing. What
aless does is under 0.1.0, below, and at
[aless.tabnas.dev](https://aless.tabnas.dev).

## [0.1.0](https://crates.io/crates/aless/0.1.0), 2026-10-09

The first release.

### Added

- A [jless](https://jless.io)-style terminal viewer for JSON, JSON Lines,
  jsonic, JSONC, JSON5, YAML, TOML, INI, CSV, TSV, XML, ZON, Markdown and
  RSS/Atom feeds, with tabs, panes, a file explorer, regex search, and a
  watch mode that reloads a changed file and keeps your place.
- Custom grammars: any text format described in ABNF (`--grammar`,
  `--grammar-expr`).
- Without a screen, JSON for scripts and agents: `--json`, `--paths`,
  `--find`, `--where` and `--check`, each with source positions.
- `--help`, the whole reference an agent needs to drive aless: every
  option, what each output prints, every error kind with its fields, the
  exit statuses, paths, positions, formats and limits. `-h` is a summary.
- `--generate`: the man page, completions for bash, zsh, fish and
  PowerShell, and the Agent Skill, from the binary itself. Each shell's
  completions load from a file where the shell looks, or from its
  startup file.
- `--render` to CSV, JSON, or any format whose tabnas crate carries a
  render, and `--alchemy` programs over any input.
- Releases: binaries for Linux (x86_64 and aarch64, glibc and static
  musl), macOS (x86_64 and aarch64) and Windows (x86_64 and aarch64), shell
  and PowerShell installers, a Homebrew tap, `cargo install` and
  `cargo binstall`, with checksums, a CycloneDX SBOM and build-provenance
  attestations. Each archive carries the man page and the completions,
  and the Homebrew formula installs them where Homebrew's own formulas
  put theirs.
- A homepage, [aless.tabnas.dev](https://aless.tabnas.dev): tutorials,
  how-to guides, the reference and explanations, with the reference
  written from the binary and every example's output checked against it.

[0.1.1]: https://github.com/rjrodger/aless/releases/tag/v0.1.1
[0.1.0]: https://crates.io/crates/aless/0.1.0
