mant-engine
mant-engine is ManT's document execution layer. It resolves local documents
through mant-loader, which delegates decoding and lowering to mant-codec into
the semantic center in mant-ir. It delegates bounded content queries to
mant-query and composes versioned protocol responses without owning report
rendering, a terminal, or a command-line process. Hosts format those responses
with mant-render.
What this crate provides
- Registered Markdown lookup through the read-only
mant-loader/mant-sourcesboundary. - Integration with
mant-codec's source-positioned Markdown parser, explicit loss diagnostics and optional embedded tldr content. - Source-neutral inline headings: Markdown ATX/Setext and native section headings retain styles and typed links. An extracted first H1 is real document-heading content, not duplicated metadata or a synthetic paragraph.
- Integration with the loader's bounded native input policy: explicit leaf-file symlink support,
root-constrained
.soalias resolution, and delegatedman(7)/mdoc(7)lowering throughmant-codecon every supported platform. - Loader-owned regular-file-only manual-path configuration reads. Unix nonblocking opens and handle checks reject FIFOs without waiting for a writer, while retaining symlinks to regular configuration files and bounded UTF-8 reads.
- Semantic outlines with compact scope summaries, role filters, nested entry paths, authored forms, value domains, and optional section/entry roots.
- Markdown entry authoring with grouped visible names, independent invocation
forms, linked code terms, and explicitly open or exhaustive local choices.
Item-owned
mant:entrycomments can declare exact IDs, disjoint visible-name alias groups, and validated same-document alias relationships without replacing content or inferring equivalence from punctuation. See the authoring field map for declared fields versus index-derived facts. Grouping names supplies shared selectable content, not proof of behavioral equivalence. Semantic facts bind to the original list content without replacing its punctuation, paragraphs, numbering or tightness. - Typed local and cross-document navigation: only logical document and manual links become bounded scope edges; external, email, and page-local targets do not expand a query.
- One strict selector resolver for outline roots and excerpts: explicit local
ContentSelector::PathorContentSelector::Id, without names, aliases, shorthand, fragment activation or document-link following. - Independent bounded explanation evidence: exact names/forms, literal content and validated alias relationships. Multiple owners and no-evidence are normal; ordinary support retains its section and block path without becoming an entry. Consecutive native declaration groups additionally supply complete reading context for empty heads without moving another item's body or inferring aliases. Context is carried in the returned DTO, not recovered by a renderer.
- Excerpt selection and literal or regular-expression search with generated Markdown coordinates.
- Composition with
mant-rendertext, man-style text, and JSON reports andmant-codecdocument Markdown over one normalized IR. Heading Markdown preserves manual targets as explicitman:topic(section)(or unqualifiedman:topic) links; document, external and email targets remain ordinary Markdown links. A local link in any real heading automatically selects addressable output, including its destinations; incompatible semantic comments are omitted even when requested. Otherwisepreserve_anchorsremains opt-in. Root destinations precede the actual document heading, not its body or quick reference. An excerpt preserves heading links but may exclude their target content; it does not follow them. This does not change the historical portable body policy of showing native manual-reference labels. Raw anchor destinations support HTML navigation; they do not make addressable Markdown a lossless semantic-IR reimport format. Use IR JSON for that contract. Multiline level-one/two headings use Setext syntax. At deeper levels portable ATX output folds explicit breaks to spaces while keeping the heading level, visible words and links; IR JSON retains the exact break structure. - Source-aware
mant_render::render_query_text_with/mant_render::render_excerpt_text_withcallbacks over the same plain-text block layout, with composable source markup and validated owner-local name roles rather than rendered-line name matching. - Loader-owned installed-client and private tldr cache discovery. Explicit
subprocess-backed updates belong to the
mantprocess host, not this library.
For already-loaded tldr text, mant-codec::parse_tldr_page and
mant-codec::parse_tldr_command are pure parsing entry points owned by that
crate, not engine re-exports. TldrPageLocation supplies
identity metadata only: it does not trigger a cache read, host/platform lookup,
or URL fetch. TldrParseError reports syntax failure; the separate
TldrCacheError adds read/location context. The updater and its process/filesystem
errors are private to the application's explicit maintenance operation.
Process argument parsing, MCP transport, and interactive presentation remain outside this crate.
The default roff feature preserves native-manual support and explicitly
forwards to mant-loader/roff, which enables mant-codec/roff. Disable default features
for Markdown/tldr-only production use without native parsing or decompression.
Every engine feature remains read-only with respect to tldr data. The old
tldr-update feature and updater exports are removed: maintenance is owned by
the native mant composition root, never by library queries or MCP services.
Execution pipeline
For a host that initializes its document environment lazily,
PreparedQueryRequest::new(&request, policy) and
PreparedScopeQuery::new(&request) validate the complete borrowed request
without reading configuration or documents. Call execute(&resolver) after
obtaining the operation's explicit DocumentResolver snapshot; single-document
requests also expose resolve(&resolver) for full-content consumers. Their
fields are private and their request accessors are immutable, so validation
cannot drift from the executed request or policy. These values are validation
proofs, not cached search matchers. Pure query APIs retain their own checks.
Free execution functions prepare before constructing the system resolver.
Explicit resolver methods follow the same prepared execution path. Catalog
hosts can separately prepare mant_loader::PreparedCatalogQuery and pass it
to discover_prepared; that existing catalog plan retains its compiled matcher.
logical selector / physical input
│
v
DocumentResolver ──> mant-loader ──> mant-codec (Markdown / tldr / roff)
│
v
mant_ir::ResolvedContent
├─> mant-query ─> outline / excerpt / search / explain / references
├─> typed document graph ─> mant-query borrowed scope
├─> mant-codec document Markdown / mant-render body text (host choice)
└─> versioned mant-protocol responses
Lowering preserves ordinary lists as ordinary lists and genuine definitions as
terms plus descriptions. Both can carry mant_ir::EntryFacts; annotation never
replaces their blocks. Markdown binds declarations and coverage to original
item positions before consuming comments, then binds forms to final content.
Native lowering records explicit term forms while styled macro evidence is
still available. Shared validation independently filters invalid forms, names
and relationships without erasing owners or their children. Content selectors
reuse a single immutable location snapshot; semantic names belong to independent
explanation evidence. Compact outline summaries count borrowed facts and validated
form bindings without constructing a full semantic index or copying form text.
Reference inventories independently scan the exact original owner, regardless of
entry display filters. Search composes byte ownership
with rendered text even when table cells flatten for portable Markdown.
Native source interpretation
mant-codec owns native lowering, Markdown parsing, semantic annotation and
portable document encoding. Its native ownership map
documents formatter state, source geometry, target retention and transactional
table recovery. mant-loader prepares inputs; the engine composes queries over
that one implementation through mant-query; it does not reinterpret source
macros, rebuild entry facts, or duplicate selection and evidence algorithms.
Public entry points
| Need | Preferred API |
|---|---|
| Reuse a read-only discovery/loading snapshot | mant_loader::DocumentLoader |
| Reuse an application loading/query snapshot | DocumentResolver |
| Load a borrowed source specification without a query view | mant_loader::DocumentLoader::load, mant_loader::LoadSpec, mant_loader::LoadPolicy |
| Resolve a complete typed request | resolve_query_with_policy |
| Resolve and project its requested view | execute_query |
| Resolve a bounded multi-document scope without querying | mant_loader::DocumentLoader::resolve_scope |
| Resolve and project a scope request | execute_scope_query or DocumentResolver::execute_scope_query |
| Query caller-owned document snapshots without loading | mant_query::QueryScopeView::new, mant_query::search_scope, mant_query::explain_scope |
| Parse in-memory Markdown without query composition | mant_codec::parse_markdown |
| Prepare in-memory Markdown and project a requested view | mant_loader::load_markdown_text, then project_query_view |
| Parse prepared plain roff without loading or decompression | mant_codec::parse_roff_bytes (roff feature) |
| Apply standalone-input policy to prepared plain roff bytes | mant_loader::parse_manual_bytes or mant_loader::load_roff_bytes (roff) |
| Audit production file lowering against its exact native witness | mant_loader::parse_manual_source_with_report (roff) |
| Build a focused result from existing content | mant_query::build_outline_projection, mant_query::select_excerpt, mant_query::search_query |
| Collect bounded independent semantic evidence | mant_query::explain_query, mant_query::validate_explanation_query |
| Produce human or JSON output | mant_render::render_*; document Markdown uses mant_codec::encode |
Basic use
For a complete request, let the engine validate the input and view before it
captures source configuration, loads the explicitly supplied local file through
the loader, and executes the requested projection. This example expects the
caller to provide an existing notes.md; rendering remains a host choice.
use ;
use LoadPolicy;
use ;
use render_outline_text;
let request = QueryRequest ;
let Outline = execute_query? else ;
println!;
# Ok::
The in-memory Markdown path is deterministic and works on every supported platform:
use ;
use ;
use load_markdown_text;
use render_outline_text;
let query = load_markdown_text?;
let result = project_query_view?;
let Outline = result else ;
println!;
# Ok::
Use resolve_query or resolve_query_with_policy when a caller needs the full
document bundle. Use execute_query to validate, resolve, and materialize the
request's view through one engine boundary. Use parse_markdown when the
caller needs the parsed document and tldr preface without query composition;
that function is implemented and exported by mant-codec.
DocumentResolver can be reused when several operations must share one lazy
filesystem snapshot; constructing a new resolver refreshes discovery.
Loading and view validation have distinct error owners. mant_loader::DocumentLoader
accepts a borrowed LoadSpec and LoadPolicy, never a serialized request or query
view; failures are LoadError. The application DocumentResolver validates a
complete request and joins loading with query execution. QueryError::Load and
QueryError::QueryValidation preserve the originating category and error chain
without giving acquisition code access to search or projection behavior.
The same split applies to scopes: ScopeLoadError describes traversal inputs
or acquisition failures, while ScopeQueryError::Execution retains failures
from querying the already-loaded collection. One-shot request functions reject
invalid inputs and views before constructing a system resolver. Explicit
resolver methods reuse their caller-owned snapshot; the validated execution
path does not repeat the application validation merely because a snapshot was
created by a convenience function.
mant_loader::DocumentLoader::resolve_scope owns linked-document traversal and
aggregate content budgets. Engine execute_scope_query joins that acquisition
with breadth-first query results at one application boundary. Process and MCP adapters should pass a ScopeQueryRequest rather
than reimplementing scope traversal.
For already-loaded or caller-produced content, construct QueryScopeView from
the borrowed logical graph and the matching ResolvedContent slice, then use
search_scope or explain_scope. The view checks lengths, exact addresses,
unique source slots, BFS depth/order and graph provenance before execution;
it cannot silently truncate mismatched collections. It borrows the original
content and permits repeated queries without loading, parsing or serialization.
The caller remains responsible for supplying one coherent provenance snapshot,
not merely equal addresses from unrelated revisions. Loading coverage and
frontier records remain accessible through the same borrowed graph; an absent
target is not proof of nonexistence. Query errors are ScopeExecutionError,
separate from source acquisition errors.
LoadedDocumentScope exposes immutable scope() and documents() accessors;
into_parts() transfers both owned components without cloning content. The
engine's complete workflow constructs the validated view from this loading
result and retains global classification, paging and shared copy budgets.
explain_query returns QueryExplanation, not a unique excerpt. Its options
bound returned owners (default 50, maximum 256), a zero-based offset, and copied
forms/facts/previews/body payload (default 1 MiB, maximum 4 MiB). A borrowed
collection plan orders direct entries, explicit relations, entry mentions and
context mentions before global pagination. Within each class, scope preserves
BFS document and original IR order, sharing one budget across selected records.
A bounded priority pool prevents early mentions from excluding later direct
entries, reporting any discarded candidates. Scope has one flat evidence page
and source reports, never duplicate nested bodies. select_explanation uses the defaults;
select_excerpt is the strict navigation API. Check outcome, scope coverage
and truncation separately; semanticsComplete describes semantic validation,
not exhaustive recall. Literal previews retain up to two original matched
blocks, each a maximum 1024 Unicode scalars with exact match ranges and actual
source positions. resolve_explanation_block resolves preview paths in final
IR. Compact rendering shows those windows for mentions instead of unrelated
full owner content. Clipping, omitted previews, and atomic body omission are
distinct. No evidence query performs I/O or executes examples.
mant-render's render_explanation_text_with and render_scope_explanation_text_with expose
the same report as plain text, with terminal-neutral TextPresentation
spans. Their callbacks preserve visible text and boundary whitespace. Exact
matches and ordinary name styling resolve only against returned forms/content;
deserialized responses need no original document or query-side table. The
plain report does not prefix original lines. Complete displayed declaration
owners suppress duplicate Forms per record. Recovered group context is displayed
once with its provider; only truly isolated empty definitions get an empty-body
notice, distinct from copy/support omission. Shared body references map positions
back to each actual member. This does not change the DTO. The
corresponding Markdown renderers quote source lines, escape metadata, and retain
verbatim fenced code. Outline text likewise has one plain/decorated tree through
render_outline_text_with, with complete IDs on hanging metadata lines.
let query = load_markdown_text?;
let evidence = select_explanation?;
assert_eq!;
assert!;
# Ok::
Named resolution treats the full document and command quick reference as two
orthogonal facets. A manual section selects an exact native full document; it
does not by itself disable a compatible section 1 or 8 tldr attachment.
mant_loader::LoadPolicy::ManualOnly excludes that facet, while TldrOnly requests it
without requiring a full document. Dotted names are never split heuristically.
The engine returns mant_ir::ResolvedContent to direct semantic consumers and
creates mant-protocol projections for every structured host or process
boundary. A projection can stay in memory for a TUI callback or be serialized
for CLI JSON and compact MCP presentation. Serializing the IR directly is not a supported substitute
for those versioned DTOs.
Platform behavior
| Platform | Markdown engine | Native man/mdoc engine |
|---|---|---|
| Linux with glibc | Yes | Bundled libmandoc-rs |
| macOS | Yes | Bundled libmandoc-rs |
| Windows | Yes | Bundled libmandoc-rs |
With the default roff feature, every supported target compiles libmandoc-rs. Windows uses its memory-only C
transport while Rust owns file I/O, decompression, paths, and .so redirects.
Within mant-loader, manual_input owns that product input policy and its
ManualError failures. mant-codec accepts prepared plain bytes and a
source label, with includes denied; it never opens that label or a redirect.
Standalone alias syntax is recognized once by a pure codec helper, while only
the indexed loader may resolve it. Stored and decoded bytes each share a
16 MiB budget across the complete chain, which permits at most 16 redirects.
The report-bearing file API lowers the same owned native parse witness rather
than reopening or reparsing the input. Indexed alias metadata is attached by
the loader after parsing, not used to authorize codec IO.
Native root discovery is also loader-owned Rust code: Linux reads man-db mappings or
mandoc man.conf, macOS reads its PATH, active developer selection, and
MANPATH/MANCONFIG configuration, and Windows optionally reads ManT's own
man.conf. The Windows subset supports direct and mandatory roots, bounded
one-level fragments, PATH-conditioned mappings, quoted paths, and single-pass
%NAME% expansion before automatically adding %APPDATA%\ManT\man and the
compatible %USERPROFILE%\.local\share\man fallback. Invalid directives are
omitted from queries and returned by inspect_manual_roots for local doctor
reporting. Windows environment names are matched case-insensitively, and the
fragment bound stops later pattern traversal, all without spawning a host
manual utility.
Native lowering conserves validated zero-width navigation targets as section,
semantic-entry, or inline identities. This includes targets libmandoc moves
onto structural paragraph, display, list, item, and function wrappers; it does
not synthesize visible placeholder text. This policy is implemented once in
mant-codec, not in an engine-specific parser.
Layering
mant-engine returns an owned mant_ir::ResolvedContent for direct semantic
use and owned mant-protocol values at versioned integration boundaries. It does not expose
libmandoc C structures. It owns application request validation and composition;
it is not merely a forwarding facade. Pure query execution belongs
to mant-query. Parser/encoder, loader, query and IR APIs are not re-exported:
callers import the crate that owns each operation and type. The public engine
surface consists of complete-request preparation, resolver workflows,
view dispatch and their application error types. In-memory inputs use the
loader directly before optional engine view dispatch; they do not need a
second engine-owned loading wrapper.
Consumers needing only source-to-IR conversion or portable document Markdown
should depend on mant-codec directly; consumers needing source discovery,
loading, read-only caches or owned scopes should use mant-loader. Consumers
with existing IR that need selection, search, explanation or reference
projections should use mant-query, which does not load files or render reports.
Consumers formatting existing content or protocol values should use
mant-render. The engine's codec and render dependencies exist only for
cross-crate regression tests, profiler examples and doctests; production
decoding is reached exclusively through the loader.
Explicit tldr maintenance belongs to the command host, not this engine or
the loader. Applications that only
need raw roff syntax should use
libmandoc-rs directly. Applications
that need the complete command or reader should install
mant.
Architecture and source-resolution details are documented in the ManT native-engine reference. Compatibility and migration notes are recorded in the crate changelog.
License
Apache-2.0. Native builds also contain the separately attributed vendored mandoc
sources supplied by libmandoc-rs.