Open, create, read, analyze, edit, or validate Excel/spreadsheet files (.xlsx, .xlsm, .csv, .tsv). Use when the user asks to create, build, modify, analyze, read, validate, or format any Excel spreadsheet, financial model, pivot table, or tabular data file. Triggers on 'spreadsheet', 'Excel', '.xlsx', '.csv', 'pivot table', 'financial model', 'formula', or any request to produce tabular data in Excel format.
Published by rebyteai
Runs in the cloud
No local installation
Dependencies pre-installed
Ready to run instantly
Secure VM environment
Isolated per task
Works on any device
Desktop, tablet, or phone
Handle the request directly. Do NOT spawn sub-agents. Always write the output file the user requests.
| Task | Method | Guide |
|---|---|---|
| READ — analyze existing data | xlsx_reader.py + pandas |
references/read-analyze.md |
| CREATE — new xlsx from scratch | openpyxl (Python) | See CREATE section below |
| EDIT — modify existing xlsx | XML unpack→edit→pack | references/edit.md (+ references/format.md if styling needed) |
| FIX — repair broken formulas | XML unpack→fix <f> nodes→pack |
references/fix.md |
| VALIDATE — check formulas | formula_check.py |
references/validate.md |
references/read-analyze.md first)Start with xlsx_reader.py for structure discovery, then pandas for custom analysis. Never modify the source file.
Formatting rule: When the user specifies decimal places (e.g. "2 decimal places"), apply that format to ALL numeric values. Never output 12875 when 12875.00 is required.
Aggregation rule: Always compute sums/means/counts directly from the DataFrame column. Never re-derive column values before aggregation.
Make the user able to use the Excel immediately and gain insights upon opening.
Enrich visuals as much as possible, while ensuring content clarity and not adding cognitive burden. Every visual element should be meaningful and purposeful—serving the content, not decorating it.
Before creating any Excel, think through:
| Feature | User Value | When to Use |
|---|---|---|
| Bar/Column Chart | See comparisons at a glance | Comparing values across categories |
| Line Chart | See trends at a glance | Time series data |
| Pie Chart | See proportions at a glance | Part-to-whole (≤6 categories) |
| Data Bars | Compare magnitude without leaving the cell | Numeric columns needing quick comparison |
| Color Scale | Heatmap effect, patterns pop out | Matrices, ranges, distributions |
| Sparklines | See trend within a single cell | Summary rows with historical context |
| Feature | User Value | When to Use |
|---|---|---|
| Pre-sorting | Most important data comes first | Rankings, Top N, priorities |
| Conditional Highlighting | Key data stands out automatically | Outliers, thresholds, Top/Bottom N |
| Icon Sets | Status visible at a glance | KPI status, categorical states (use sparingly) |
| Bold/Color Emphasis | Visual distinction between primary and secondary | Summary rows, key metrics |
| KEY INSIGHTS Section | Conclusions delivered directly | Analytical reports |
| Feature | User Value | When to Use |
|---|---|---|
| Overview Sheet | Summary on first page, no hunting | All multi-sheet files |
| Pre-calculated Summaries | Results ready, no manual calculation | Data requiring statistics |
| Consistent Number Formats | No format adjustments needed | All numeric data |
| Freeze Panes | Headers visible while scrolling | Tables with >10 rows |
| Sheet Index with Links | Quick navigation, no guessing | Files with >3 sheets |
| Feature | User Value | When to Use |
|---|---|---|
| Filters | Users can explore data themselves | Exploratory analysis needs |
| Hyperlinks | Click to navigate, no manual switching | Cross-sheet references, external sources |
| Print-friendly Layout | Ready to print or export to PDF | Reports for sharing |
| Formulas (not hardcoded) | Change parameters, results update | Models, forecasts, adjustable scenarios |
| Data Validation Dropdowns | Prevent input errors | Templates requiring user input |
| Feature | User Value | When to Use |
|---|---|---|
| Data Source Attribution | Know where data comes from | All external data |
| Generation Date | Know data freshness | Time-sensitive reports |
| Data Time Range | Know what period is covered | Time series data |
| Professional Formatting | Looks reliable | All external-facing files |
| Consistent Precision | No doubts about accuracy | All numeric values |
| Feature | User Value | When to Use |
|---|---|---|
| Comparison Columns (Δ, %) | No manual calculation for comparisons | YoY, MoM, A vs B |
| Rank Column | Position visible directly | Competitive analysis, performance |
| Grouped Summaries | Aggregated results by dimension | Segmented analysis |
| Trend Indicators (↑↓) | Direction clear at a glance | Change direction matters |
| Insight Text | The "so what" is stated explicitly | Analytical reports |
Goal: Logical, easy to navigate, user finds what they need immediately.
| Guideline | Recommendation |
|---|---|
| Sheet count | 3-5 ideal, max 7 |
| First sheet | Always "Overview" with summary and navigation |
| Sheet order | General → Specific (Overview → Data → Analysis) |
| Naming | Clear, concise (e.g., "Revenue Data", not "Sheet1") |
| Element | Position |
|---|---|
| Left margin | Column A empty (width 3) |
| Top margin | Row 1 empty |
| Content start | Cell B2 |
| Section spacing | 1 empty row between sections |
| Table spacing | 2 empty rows between tables |
| Charts | Below all tables (2 rows gap), or right of related table |
Chart placement:
For rows with a single text cell (titles, descriptions, notes, bullet points), text will naturally extend into empty cells to the right. However, text is clipped if right cells contain any content (including spaces).
Decision logic:
| Condition | Action |
|---|---|
| Right cells guaranteed empty | No action needed—text extends naturally |
| Right cells may have content | Merge cells to content width, or wrap text |
| Text exceeds content area width | Wrap text + set row height manually |
Technical note: Fill and border alone do NOT block text overflow—only actual cell content (including space characters) blocks it.
For files with 3+ sheets, include a Sheet Index on Overview:
# Sheet Index with hyperlinks
ws['B5'] = "CONTENTS"
ws['B5'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])
sheets = ["Overview", "Data", "Analysis"]
for i, sheet_name in enumerate(sheets, start=6):
cell = ws.cell(row=i, column=2, value=sheet_name)
cell.hyperlink = f"#'{sheet_name}'!A1"
cell.font = Font(color=THEME['accent'], underline='single')
Goal: Accurate, complete, insightful—user gains knowledge, not just data.
Critical rules:
number_format set — both input values AND formula results0.1074 and 1.0 in one column| Data Type | Format Code | Example |
|---|---|---|
| Integer | #,##0 |
1,234,567 |
| Decimal (1) | #,##0.0 |
1,234.6 |
| Decimal (2) | #,##0.00 |
1,234.56 |
| Percentage | 0.0% |
12.3% |
| Currency | $#,##0.00 |
$1,234.56 |
Common mistake: Setting format only for input cells, forgetting formula cells.
# WRONG: Formula cell without number_format
ws['C10'] = '=C7-C9' # Will display raw precision like 14.123456789
# CORRECT: Always set number_format for formula cells
ws['C10'] = '=C7-C9'
ws['C10'].number_format = '#,##0.0' # Displays as 14.1
# Best practice: Define format by column/data type, apply to ALL cells
for row in range(data_start, data_end + 1):
cell = ws.cell(row=row, column=value_col)
cell.number_format = '#,##0.0' # Applies to both values and formulas
Every data set needs context:
| Element | Location | Example |
|---|---|---|
| Data source | Overview or sheet footer | "Source: Company Annual Report 2024" |
| Time range | Near title or in subtitle | "Data from Jan 2020 - Dec 2024" |
| Generation date | Overview footer | "Generated: 2024-01-15" |
| Definitions | Notes section or separate sheet | "Revenue = Net sales excluding returns" |
For analytical content, don't just present data—tell the user what it means:
ws['B20'] = "KEY INSIGHTS"
ws['B20'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])
insights = [
"• Revenue grew 23% YoY, driven primarily by APAC expansion",
"• Top 3 customers account for 45% of total revenue",
"• Q4 showed strongest performance across all metrics"
]
for i, insight in enumerate(insights, start=21):
ws.cell(row=i, column=2, value=insight)
| Check | Action |
|---|---|
| Missing values | Show as blank or "N/A", never 0 unless actually zero |
| Calculated fields | Include formula or note explaining calculation |
| Abbreviations | Define on first use or in notes |
| Units | Include in header (e.g., "Revenue ($M)") |
Goal: Professional appearance, immediate sense of value, visuals serve content.
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
# Hide gridlines for cleaner look
ws.sheet_view.showGridLines = False
# Left margin
ws.column_dimensions['A'].width = 3
Choose ONE theme per workbook. All visual elements derive from the theme color.
Available Themes (select based on context, or let user specify):
| Theme | Primary | Light | Use Case |
|---|---|---|---|
| Elegant Black | 2D2D2D |
E5E5E5 |
Luxury, fashion, premium reports (recommended default) |
| Corporate Blue | 1F4E79 |
D6E3F0 |
Finance, corporate analysis |
| Forest Green | 2E5A4C |
D4E5DE |
Sustainability, environmental |
| Burgundy | 722F37 |
E8D5D7 |
Luxury brands, wine industry |
| Slate Gray | 4A5568 |
E2E8F0 |
Tech, modern, minimalist |
| Navy | 1E3A5F |
D3DCE6 |
Government, maritime, institutional |
| Charcoal | 36454F |
DDE1E4 |
Professional, executive |
| Deep Purple | 4A235A |
E1D5E7 |
Creative, innovation, premium tech |
| Teal | 1A5F5F |
D3E5E5 |
Healthcare, wellness |
| Warm Brown | 5D4037 |
E6DDD9 |
Natural, organic, artisan |
| Royal Blue | 1A237E |
D3D5E8 |
Academic, institutional |
| Olive | 556B2F |
E0E5D5 |
Military, outdoor |
Theme Configuration:
# === THEME CONFIGURATION ===
THEMES = {
'elegant_black': {
'primary': '2D2D2D',
'light': 'E5E5E5',
'accent': '2D2D2D',
'chart_colors': ['2D2D2D', '4A4A4A', '6B6B6B', '8C8C8C', 'ADADAD', 'CFCFCF'],
},
'corporate_blue': {
'primary': '1F4E79',
'light': 'D6E3F0',
'accent': '1F4E79',
'chart_colors': ['1F4E79', '2E75B6', '5B9BD5', '9DC3E6', 'BDD7EE', 'DEEBF7'],
},
# ... other themes follow same pattern
}
THEME = THEMES['elegant_black'] # Default
SERIF_FONT = 'Source Serif Pro' # or 'Georgia' as fallback
SANS_FONT = 'Source Sans Pro' # or 'Calibri' as fallback
How Theme Colors Apply:
| Element | Color | Background |
|---|---|---|
| Document title | THEME['primary'] |
None |
| Section header | THEME['primary'] |
None or THEME['light'] |
| Table header | White | THEME['primary'] |
| Data cells | Black | None or alternating F9F9F9 |
| Chart elements | THEME['chart_colors'] |
— |
For data meaning (independent of theme):
| Semantic | Color | Use |
|---|---|---|
| Positive | 2E7D32 |
Growth, profit, success |
| Negative | C62828 |
Decline, loss, failure |
| Warning | F57C00 |
Caution, attention |
For row-level emphasis. Use high-lightness tints (85-95% lightness) for subtle distinction.
| Semantic | Hex | Hue | Use |
|---|---|---|---|
| Emphasis | E6F3FF |
209° | Top rated, important data |
| Section | FFF3E0 |
37° | Section dividers |
| Input | FFFDE7 |
55° | Editable cells |
| Special | FFF9C4 |
55° | Base case, benchmarks |
| Success | E8F5E9 |
125° | Passed, completed |
| Warning | FFCCBC |
14° | Needs attention |
Rule: Same semantic = same color. Different semantic = different color.
HIGHLIGHT = {
'emphasis': 'E6F3FF',
'section': 'FFF3E0',
'input': 'FFFDE7',
'special': 'FFF9C4',
'success': 'E8F5E9',
'warning': 'FFCCBC',
}
Use serif + sans-serif pairing. Serif for hierarchy (titles, headers); sans-serif for data (tabular figures).
Font Pairings (in preference order):
| Serif (Titles) | Sans-Serif (Data) | Notes |
|---|---|---|
| Source Serif Pro | Source Sans Pro | Adobe superfamily, recommended |
| IBM Plex Serif | IBM Plex Sans | Modern, corporate |
| Georgia | Calibri | Pre-installed fallback |
Hierarchy:
| Element | Font | Size | Style |
|---|---|---|---|
| Document title | Serif | 18-22 | Bold, Primary color |
| Section header | Serif | 12-14 | Bold, Primary color |
| Table header | Serif | 10-11 | Bold, White |
| Data cells | Sans-Serif | 11 | Regular, Black |
| Notes | Sans-Serif | 9-10 | Italic, 666666 |
# Document title
ws['B2'].font = Font(name=SERIF_FONT, size=18, bold=True, color=THEME['primary'])
# Section header
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])
# Table header
header_font = Font(name=SERIF_FONT, size=10, bold=True, color='FFFFFF')
# Data cells
data_font = Font(name=SANS_FONT, size=11)
# Notes
notes_font = Font(name=SANS_FONT, size=10, italic=True, color='666666')
A Data Block is a group of continuous, non-empty rows that form a visual unit requiring borders. Data Blocks are separated by empty rows.
Identification rules:
Data Block types:
| Type | Structure | Example |
|---|---|---|
| With Header | Header row + data rows | Table with column titles |
| Without Header | Data rows only | Continuation data, sub-tables |
Example recognition:
Row 5: Section Header "INCOME STATEMENT" → No border (not a Data Block)
Row 6: Empty → Separator
Row 7: Header (Item, Year1, Year2...) → Data Block 1 starts
Row 8: Revenue, 47061, 48943...
Row 9: Growth Rate, 4.0%, 3.5%... → Data Block 1 ends
Row 10: Empty → Separator
Row 11: EBITDA, 12121, 12627... → Data Block 2 starts (no header)
Row 12: EBITDA Margin, 25.8%, 25.8%... → Data Block 2 ends
Row 13: Empty → Separator
Row 14: D&A, 1200, 1224... → Data Block 3 starts (no header)
Row 15: EBIT, 10921, 11404...
Row 16: EBIT Margin, 23.2%, 23.3%... → Data Block 3 ends
Result: 3 separate Data Blocks, each with its own outer frame.
Recommended style: Horizontal-only — cleaner, more modern.
Each Data Block must have:
| Border Type | Where |
|---|---|
| Outer frame | All 4 sides of Data Block (top, bottom, left, right) |
| Header bottom | Medium weight, theme primary color (if has header) |
| Internal horizontal | Thin, between all rows |
| Internal vertical | None (omit for cleaner look) |
Critical: Every cell in the Data Block must have its border set. Do not only set header and label cells—data cells need borders too.
# Border definitions
outer_border = Side(style='thin', color='D1D1D1')
header_bottom = Side(style='medium', color=THEME['primary'])
inner_horizontal = Side(style='thin', color='D1D1D1')
no_border = Side(style=None)
def apply_data_block_borders(ws, start_row, end_row, start_col, end_col, has_header=True):
"""
Apply borders to a Data Block.
Every cell must be processed—not just headers and labels.
"""
for row in range(start_row, end_row + 1):
for col in range(start_col, end_col + 1):
cell = ws.cell(row=row, column=col)
# Left/Right: outer frame
left = outer_border if col == start_col else no_border
right = outer_border if col == end_col else no_border
# Top: outer for first row, inner horizontal for others
top = outer_border if row == start_row else inner_horizontal
# Bottom: header_bottom for header, outer for last row, inner for middle
if has_header and row == start_row:
bottom = header_bottom
elif row == end_row:
bottom = outer_border
else:
bottom = inner_horizontal
cell.border = Border(left=left, right=right, top=top, bottom=bottom)
Non-Data-Block elements (titles, section headers, standalone text, notes): No border.
Headers: Center.
Data cells:
| Content | Horizontal |
|---|---|
| Short text (words) | Center |
| Long text (sentences) | Left + indent=1 |
| Numbers | Right |
| Dates, Status | Center |
Vertical: Always center (including wrapped text).
# Left-aligned text with padding
cell.alignment = Alignment(horizontal='left', vertical='center', indent=1)
# Numbers
cell.alignment = Alignment(horizontal='right', vertical='center')
# Wrapped text
cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True, indent=1)
Calculation scope: Only Data Block cells. Exclude standalone text rows, section headers, and notes.
Formula: max(max_content_length_in_data_blocks + padding, minimum)
| Column Type | Padding | Minimum | Notes |
|---|---|---|---|
| Label/Text | +4 | 15 | First column usually |
| Numbers | +6 | 14 | Extra space for formatted numbers (negative signs, commas) |
| Long text | +4 | 20, max 40 | Wrap if exceeds max |
Design constraint: Same column across different Data Blocks should serve similar roles. Column width is determined by the widest content across all Data Blocks in that column.
Standalone text rows: Do NOT include in column width calculation. Let text extend naturally or use wrap/merge.
def calculate_column_width(ws, col, data_block_ranges):
"""
Calculate column width based only on Data Block content.
Standalone text rows are excluded.
data_block_ranges: list of (start_row, end_row) tuples
"""
max_len = 0
is_numeric = True
for start_row, end_row in data_block_ranges:
for row in range(start_row, end_row + 1):
cell = ws.cell(row=row, column=col)
if cell.value:
# Get formatted display length
display_value = str(cell.value)
max_len = max(max_len, len(display_value))
if not isinstance(cell.value, (int, float)):
is_numeric = False
padding = 6 if is_numeric else 4
minimum = 14 if is_numeric else 15
return max(max_len + padding, minimum)
Must set manually—openpyxl does not auto-adjust.
| Row Type | Height |
|---|---|
| Document title | 35 |
| Section header | 25 |
| Table header | 30 |
| Standard data | 18 |
| Wrapped text | lines × 15 + 10 |
ws.row_dimensions[2].height = 35 # Title
ws.row_dimensions[5].height = 25 # Section header
ws.row_dimensions[7].height = 30 # Table header
ws.row_dimensions[8].height = 18 # Data row
| Element | Merge? | Span |
|---|---|---|
| Document/Sheet title | Yes | Width of content below |
| Section header | Yes | Width of related table |
| Multi-level header (parent) | Yes | Span child columns |
| Long text row | Yes | Width of content area |
When to merge: Merge when text would otherwise be clipped at the column boundary. If text fits within a single column, merging is optional.
Common cases requiring merge:
Section header with background — merge width must match table width:
# Section header spans same width as table below
last_col = 8 # Must match table's last column
ws.merge_cells(f'B6:{get_column_letter(last_col)}6')
ws['B6'] = "KEY METRICS"
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])
ws['B6'].fill = PatternFill(start_color=THEME['light'], end_color=THEME['light'], fill_type='solid')
ws['B6'].alignment = Alignment(horizontal='left', vertical='center')
Data Bars:
from openpyxl.formatting.rule import DataBarRule
rule = DataBarRule(start_type='min', end_type='max', color=THEME['primary'])
ws.conditional_formatting.add('C5:C50', rule)
Color Scale:
from openpyxl.formatting.rule import ColorScaleRule
rule = ColorScaleRule(
start_type='min', start_color='FFFFFF',
end_type='max', end_color=THEME['primary']
)
ws.conditional_formatting.add('D5:D50', rule)
Charts:
from openpyxl.chart import BarChart, Reference
chart = BarChart()
chart.title = "Revenue by Region"
data = Reference(ws, min_col=3, min_row=4, max_row=10)
cats = Reference(ws, min_col=2, min_row=5, max_row=10)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)
# Apply theme colors to chart series
for i, series in enumerate(chart.series):
series.graphicalProperties.solidFill = THEME['chart_colors'][i % len(THEME['chart_colors'])]
ws.add_chart(chart, "F5")
Goal: Usable, flexible, user can explore and work with the data.
For tables with >10 rows:
ws.freeze_panes = 'B5' # Freeze below header row
For tables with >20 rows:
ws.auto_filter.ref = f"B4:{get_column_letter(last_col)}{last_row}"
# Internal link
cell.hyperlink = "#'Data'!A1"
cell.font = Font(color=THEME['accent'], underline='single')
# External link
cell.hyperlink = "https://example.com"
cell.font = Font(color=THEME['accent'], underline='single')
Pre-sort by most meaningful dimension:
df = df.sort_values('revenue', ascending=False)
references/edit.md first)CRITICAL — EDIT INTEGRITY RULES:
Workbook() for edit tasks. Always load the original file.xlsx_reader.py or pandas and confirm the original sheet names and a sample of original data are present.Never use openpyxl round-trip on existing files (corrupts VBA, pivots, sparklines). Instead: unpack → use helper scripts → repack.
Helper scripts:
python3 SKILL_DIR/scripts/xlsx_unpack.py in.xlsx /tmp/xlsx_work/ # unpack for XML editing
python3 SKILL_DIR/scripts/xlsx_pack.py /tmp/xlsx_work/ out.xlsx # repack after editing
python3 SKILL_DIR/scripts/xlsx_shift_rows.py /tmp/xlsx_work/ insert 5 1 # shift rows
python3 SKILL_DIR/scripts/xlsx_add_column.py /tmp/xlsx_work/ --col G ... # add column
python3 SKILL_DIR/scripts/xlsx_insert_row.py /tmp/xlsx_work/ --at 6 ... # insert row
references/fix.md first)This is an EDIT task. Unpack → fix broken <f> nodes → pack. Preserve all original sheets and data.
references/validate.md first)Run formula_check.py for static validation.
python3 SKILL_DIR/scripts/formula_check.py file.xlsx --json # formula validation
python3 SKILL_DIR/scripts/formula_check.py file.xlsx --report # standardized report
python3 SKILL_DIR/scripts/xlsx_reader.py input.xlsx # structure discovery
python3 SKILL_DIR/scripts/formula_check.py file.xlsx --json # formula validation
python3 SKILL_DIR/scripts/xlsx_unpack.py in.xlsx /tmp/work/ # unpack for XML editing
python3 SKILL_DIR/scripts/xlsx_pack.py /tmp/work/ out.xlsx # repack after editing
python3 SKILL_DIR/scripts/xlsx_shift_rows.py /tmp/work/ insert 5 1 # shift rows for insertion
python3 SKILL_DIR/scripts/xlsx_add_column.py /tmp/work/ --col G ... # add column with formulas
python3 SKILL_DIR/scripts/xlsx_insert_row.py /tmp/work/ --at 6 ... # insert row with data
Everyone else asks you to install skills locally. On Rebyte, just click Run. Works from any device — even your phone. No CLI, no terminal, no configuration.
Claude Code
Gemini CLI
Codex
Cursor, Windsurf, Amp
Process, create, convert, and analyze documents — PDFs, Word docs, spreadsheets, and more. Use when user wants to extract data from PDFs, create Word documents, merge or split PDFs, convert between formats, analyze spreadsheet data, or process uploaded files. Triggers include "extract from PDF", "create Word document", "merge PDFs", "convert document", "analyze spreadsheet", "OCR this scan", "extract tables", "create template", "process invoice".
Use this skill whenever the user wants to do anything with PDF files. This includes creating professional PDF documents (reports, articles, white papers) with themed styling and CJK support, reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file, asks to produce one, wants a "professionally formatted" document, or says "转PDF" or "生成报告", use this skill.
Generate, edit, and read PowerPoint (.pptx) files. Create from scratch with PptxGenJS, edit existing PPTX via XML workflows, or extract text with markitdown. Triggers: PPT, PPTX, PowerPoint.
Create beautiful editorial reports as magazine-style HTML documents rendered inline in chat. Pretext-powered hero typography with text wrapping around decorations, multi-column body, pull quotes, stat callouts, and figures. Uses the widget aesthetic system. Triggers include "create a report", "write a report", "format as a report", "magazine layout", "editorial report", "formatted analysis", "beautiful document", "publish-quality report", "research report", "analysis brief".
rebyte.ai — The only platform where you can run AI agent skills directly in the cloud
No downloads. No configuration. Just sign in and start using AI skills immediately.
Use this skill in Agent Computer — your shared cloud desktop with all skills pre-installed. Join Moltbook to connect with other teams.