Using STFU Formatting Tools
Last updated: October 9, 2026
Using STFU Formatting Tools
STFU (Sophie Text Formatting Utility) is used to build structured, formatted messages for Telegram. It handles HTML/Markdown conversion and provides reusable components.
Important: Never Use .format()
CRITICAL: Never use Python's
.format()
method when formatting user input with STFU elements.Loading...
Why? When you pass STFU elements (like
Bold()
, Code()
) to .format()
, their string representation includes HTML tags that get embedded literally. Template
properly escapes HTML when converting, preventing XSS issues and malformed output.Basic Concept
All STFU components implement the
Element
base class and provide:- to_html()- Convert to HTML format
- to_md()- Convert to Markdown format
Important: Always use
doc.to_html()
instead of str(doc)
when sending messages. This is the preferred, non-legacy approach.Loading...
Use
reply_or_answer
for a command response that must still arrive after its command
message has been deleted. Group /start
uses this helper to retry without a reply,
while keeping its Help button and link-preview settings.Loading...
Doc - Container for Elements
The main container that holds multiple elements.
Loading...
Outputs:
Loading...
Title - Headings
Creates title/headings for sections.
Loading...
Parameters:
- item- Title text
- bold- Make bold (HTML mode, default:True)
- level- Heading level 1-6 (Markdown mode, default:1)
- prefix/postfix- Custom delimiters (HTML mode, default:[/])
Section - Grouped Content
Groups related content with optional title and indentation.
Loading...
Parameters:
- *items- Content items to include
- title- Section title (default:'')
- title_bold- Bold the title (default:False)
- title_underline- Underline the title (default:True)
- indent- Indentation level (default:1)
- indent_text- Indentation text (default:' ')
- title_postfix- Text after title (default:':')
KeyValue - Key-Value Pairs
Displays labeled values with formatting.
Loading...
Parameters:
- title- Label for the key
- value- The value to display
- suffix- Text between title and value (default:': ')
- title_bold- Bold the title (default:True)
HList - Horizontal List
Displays items horizontally with optional prefix/divider.
Loading...
Parameters:
- *args- Items to display
- prefix- Text before each item (default:'')
- divider- Text between items (default:' ')
VList - Vertical List
Displays items vertically with bullets and indentation.
Loading...
Parameters:
- *items- List items
- indent- Indentation level (default:0)
- prefix- Bullet/bullet text (default:'- ')
Template - String Templates
Replaces placeholders in a string with values. This is the preferred way to format strings with STFU elements.
Loading...
Important: Always use
Template()
instead of .format()
when your template includes STFU elements. Template
properly handles HTML escaping.Parameters:
- item- Template string with{placeholder}markers
- **kwargs- Placeholder replacements (values can be strings or STFU elements)
Special Components
InvisibleSymbol
An invisible character for spacing/hiding content.
Loading...
Spacer
A space character (useful for forcing spacing in lists).
Loading...
PreformattedHTML
Pass through HTML without escaping (use when you have valid HTML).
Loading...
EscapedStr
Automatically escapes HTML when converting. (Used internally, usually not needed directly).
UserLink
Creates a clickable user link.
Loading...
Basic Formatting Elements
These wrap text in Telegram's basic formatting.
Loading...
Combining Components
STFU elements can be nested and combined.
Loading...
Real-World Examples
Command Status Response
Loading...
AI Mode Selection
Rich elements such as
RichTable
only render as tables when the message is sent with
send_rich_message
; to_html()
degrades them to plain text, which is what the fallback relies on.Loading...
AI reply paragraphs
STFU's AI Markdown renderer emits real
<p>
tags for Rich HTML. When Sophie adds
an AI marker, it unwraps only the leading paragraph of the first body item to keep
that marker inline. Later paragraphs and paragraphs inside other blocks keep their
wrappers. With the header disabled, the body keeps all paragraph wrappers.
Streaming drafts use the same rule with their progress marker. Regular Telegram
HTML (to_html()
) keeps newline separators instead of adding unsupported <p>
tags.
Legacy AI paths using ai_markdown_to_html()
still produce regular Telegram HTML;
this wrapper rule does not convert their newline-only content into Rich paragraphs.AI-generated tables
Sophie limits AI Markdown tables to 15 columns and 50 rows (including the header).
When a table has more than 8 columns, STFU displays each data row as a separate
key/value table, with its first value as the caption and the column headings as keys.
Only the first 15 columns and first 50 rows are rendered. These chat-scoped numeric
feature flags control the limits and conversion threshold:
ai_chatbot_table_max_columns
, ai_chatbot_table_max_rows
, and
ai_chatbot_table_card_threshold
. Set the threshold to -1
to keep wide tables
in their normal layout; the row and column limits still apply.Statistics Display
Loading...
Nested Sections
Loading...
Key Takeaways
- Use Docas main container for messages with multiple elements
- Nest components freely - Sections can contain other Sections, VLists, etc.
- Use Templatefor string interpolation with{placeholder}syntax
- NEVER use .format()with STFU elements - useTemplateinstead for proper HTML escaping
- Sectionprovides structure with titles and indentation
- KeyValuefor labeled data with consistent formatting
- HListfor horizontal layouts,VListfor vertical lists
- Titlefor headings - supports both HTML and Markdown modes
- All components auto-escape HTML (except PreformattedHTML)
- Combine with formatting - Bold, Code, Italic work inside all components
- Use doc.to_html()instead ofstr(doc)- preferred method for clarity and explicit format