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).
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
    Doc
    as main container
    for messages with multiple elements
  • Nest components freely - Sections can contain other Sections, VLists, etc.
  • Use
    Template
    for string interpolation
    with
    {placeholder}
    syntax
  • NEVER use
    .format()
    with STFU elements
    - use
    Template
    instead for proper HTML escaping
  • Section
    provides structure
    with titles and indentation
  • KeyValue
    for labeled data
    with consistent formatting
  • HList
    for horizontal layouts
    ,
    VList
    for vertical lists
  • Title
    for 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 of
    str(doc)
    - preferred method for clarity and explicit format