0.0
The project is in a healthy, maintained state
A pure function that completes half-written markdown - unclosed emphasis, a link whose URL has not arrived, a code span still open - so a renderer never sees a broken document mid-stream. Idempotent, byte-identical on well-formed input, with no runtime dependencies and no Rails.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

maquina_remend

Repairs the tail of a markdown buffer that is still being streamed.

A model emits markdown a token at a time. Rendered naively, the tail of the buffer is broken for most of the message's life. The model has typed **bol and the reader sees two asterisks; it has typed [the guide](https://exa and the reader sees a link to the wrong host. maquina_remend completes that tail, so the renderer always receives a well-formed document.

MaquinaRemend.call("**unclosed bold")      # => "**unclosed bold**"
MaquinaRemend.call("`code")                # => "`code`"
MaquinaRemend.call("[label](https://exa")  # => "[label](#)"
MaquinaRemend.call("<thinking>\nstill reasoning")
# => "<thinking>\nstill reasoning</thinking>"

It is a pure function. It is idempotent. A document that is already well formed comes back byte for byte. Zero runtime dependencies, and no Rails — it runs in a plain Ruby process with nothing else loaded.

Install

bundle add maquina_remend

or, in a Gemfile:

gem "maquina_remend"

Ruby >= 3.1.

Usage

require "maquina_remend"

MaquinaRemend.call(markdown, **options) # => String

Call it on every frame of the stream, on the whole buffer so far, and render the result. Nothing is remembered between calls.

buffer = +""

stream.each do |chunk|
  buffer << chunk
  render MaquinaRemend.call(buffer)
end

nil and "" come back exactly as they went in. An unrecognised option raises MaquinaRemend::UnknownOption rather than being ignored, so a typo in a host's configuration surfaces at once.

Options

Every repair is individually disableable, and one is off by default.

Option Default Broken input Repaired to
bold: true **unclosed bold **unclosed bold**
italic: true *unclosed / _unclosed *unclosed* / _unclosed_
bold_italic: true ***both ***both***
inline_code: true `code `code`
strikethrough: true ~~struck ~~struck~~
links: true [label [label]()
images: true ![alt ![alt]()
block_math: true $$x = 1 $$x = 1$$
inline_math: false $x = 1 $x = 1$
setext_headings: true Title\n= Title\n=====
comparison_operators: true - a > b - a \> b
html_tags: true text <div cla text
single_tilde: true 20~25°C 20\~25°C
dangling_escape: true media ecuación \ media ecuación and a space
app_tags: five names <thinking>\nstill reasoning <thinking>\nstill reasoning</thinking>
link_mode: :protocol [label](http [label](#)
handlers: [] — your own handlers, run last

Pass false to switch a repair off:

MaquinaRemend.call("**unclosed bold", bold: false)  # => "**unclosed bold"
MaquinaRemend.call("![alt", images: false)          # => "![alt"

inline_math: is off because a bare dollar sign is currency far more often than it is mathematics. Turn it on only if you know your corpus.

app_tags: is a list, not a boolean. It names the tags a model emits to carry application meaning — thinking, answer, tool_call, citation, scratchpad by default — and closes the ones the model has left open. Pass your own names to match the host's tag registry, or false to switch it off:

MaquinaRemend.call("<plan>\nstep one", app_tags: %w[plan])
# => "<plan>\nstep one</plan>"

Every repair, with the input it fires on and the input it refuses to touch, is in docs/repairs.md. The reasoning behind the app_tags: list is under Application tags.

What it will not do

Guards matter more than completions. A false repair corrupts a message that was never broken, and there is no frame later in the stream that undoes it.

MaquinaRemend.call("```\n**not bold")      # => "```\n**not bold"
MaquinaRemend.call("`a * b`")              # => "`a * b`"
MaquinaRemend.call("$$a_1 + b_2$$")        # => "$$a_1 + b_2$$"
MaquinaRemend.call("some_var_name")        # => "some_var_name"
MaquinaRemend.call("costs $5 and $10")     # => "costs $5 and $10"

Nothing is completed inside a fenced code block, inside an inline code span, or inside math, because in those places broken-looking markup is the content. The full list is in docs/repairs.md.

Documentation

  • docs/repairs.md — every repair, one section each, with the input it fires on and the guards that hold it back.
  • docs/handlers.md — writing a handler of your own: the contract, the Context object, ordering, and a worked example.
  • docs/streaming.md — using it in a stream, what idempotence and prefix safety buy a caller, and what the gem deliberately does not do.

API documentation for every class is on rubydoc.info.

Guarantees

Three properties, asserted over a corpus of whole documents at every truncation point rather than over hand-picked inputs:

  1. Idempotence — call(call(x)) == call(x).
  2. No-op on well-formed input — a complete document comes back byte-identical.
  3. Prefix safety — every truncation point of a document is repairable without raising.

A fourth is measured rather than proved: an 8KB buffer is repaired in under a millisecond.

Run them with bundle exec rake test. The prefix-safety property also accepts a local corpus of real transcripts:

MAQUINA_REMEND_CORPUS=~/some/transcripts bundle exec rake test

That corpus is deliberately not committed: a transcript contains whatever the session contained.

maquina

Part of maquina — open source for Ruby and Ruby AI.

License

MIT, © Mario Alberto Chávez. See LICENSE.txt.