Guides
Safe Text Formatting
B9 is shipped as a local display feature across kult-node, strict RPC/CLI,
UniFFI, desktop, Android, and iOS. Komms stores and transmits the exact UTF-8
source a person wrote. Formatting is derived only on the receiving endpoint and
is never a second message representation.
Supported source subset
The syntax is deliberately smaller than CommonMark:
| Source | Local presentation |
|---|---|
*emphasis* or _emphasis_ |
Emphasis |
**strong** or __strong__ |
Strong emphasis |
`code` |
Inline monospace code |
| triple-backtick fenced lines | Inert code block; an optional info string is ignored |
> quote |
Quote block |
- item, * item, or + item |
Unordered list item |
1. item |
Ordered list item |
Strong and emphasis may nest within the shared depth bound. List indentation is represented in two-space steps. This is a source-text convenience, not a claim of full CommonMark compatibility: headings, tables, task lists, link parsing, embedded media, and arbitrary block nesting are not supported.
Active content is never interpreted
Raw HTML remains visible text. Markdown links and images remain visible source.
Komms does not turn any URL scheme into a link, fetch remote images, resolve
previews, run scripts, load styles, or hand formatted content to an HTML parser.
Desktop constructs a fixed set of DOM text/block elements and text nodes;
Android constructs SpannableStringBuilder styles; iOS constructs a native
AttributedString. None of those renderers creates href, src, or network
behavior from message content.
Formatting therefore adds no DNS, HTTP, analytics, preview, notification, capability, queue, or transport work. It is not a sanitizer for exporting source into some other rich-text engine; callers must use the bounded display model.
Source, compatibility, and copy
- The authenticated source is unchanged in pairwise, group, note-to-self, and scheduled history. There is no store migration, backup bump, content kind, capability bit, negotiation, or envelope change.
- An older client shows the readable source markers. A newer client derives the
same display model whether the source arrived as legacy text or typed
Text. - Copying formatted history produces a readable plain-text projection. Inline
markers and code fences are removed; quote and list meaning remains as
>,•, indentation, and ordered numbers. - B17 mention spans remain authenticated UTF-8 byte ranges. The formatter
composes them as an inert
highlightstyle with emphasis, strong, or code; it never guesses a mention from free-form@text.
Bounds and failure behavior
One formatting call accepts at most 64 KiB of UTF-8 source, 1,024 blocks, 4,096
display runs, inline nesting depth 4, list depth 4, and 64 sorted,
non-overlapping semantic highlight ranges. Highlights must use exact UTF-8
boundaries. Oversized source or invalid ranges return an error. Excessive supported-syntax
complexity does not partially reinterpret the message: the whole exact source
is returned as one literal paragraph with used_fallback = true.
The shared result contains only:
- exact
sourceand readableplain_text; - block roles (
paragraph,quote, list item, orcode_block); - text runs with inert
emphasis,strong,inline_code, andhighlighttokens; and - the literal-fallback flag.
There are no URLs, resources, callbacks, element attributes, or executable objects in the model.
Front doors
- Rust callers use
kult_node::format_text. - Local RPC uses strict
format_text { source, highlights }; the CLI command iskult format-text TEXT...and prints the stable JSON model. - Kotlin and Swift call
KultNode.formatTextthrough UniFFI; theirSessionwrappers expose the same operation. - Every shipped bubble path—pairwise, group, note-to-self, and scheduled—uses this model. Native selection remains enabled for scalable, plain-text copy.
Qualification
fixtures/b9-text-formatting-parity.json is the cross-surface conformance
corpus. Rust core, RPC, UniFFI, desktop, Kotlin, and Swift tests apply its exact
source, plain-text projection, block roles, fallback state, and highlight
ranges. Additional tests cover malformed UTF-8 offsets, source and complexity
limits, raw HTML, javascript: text, remote-image syntax, bidi controls, exact
source delivery/history, no delivery work, native source inventory, and the
absence of active-content APIs in each formatting renderer.
Manual release qualification should still exercise Dynamic Type/font scaling, TalkBack/VoiceOver, keyboard selection and copy, high contrast, RTL paragraphs, long code blocks, and mixed formatting-plus-mention content on real devices.