Files
AgentCompany/builtin-skills/document-process/minimax-xlsx/references/read-analyze.md
T
ZacharyZhang-NY e74dafcd36 Silence render-disposed spam, unbreak bundled skills, drop board wake
Three independently ugly bugs that all fed the same log flood:

* Electron's `WebFrameMain.send` writes every "Render frame was disposed"
  to stderr via `console.error`. When the worker fans a second
  agent-event past a reloading renderer, we produced thousands of
  identical lines and stalled the main loop on stderr I/O. Added a
  `mainFrame.detached` guard so the send is short-circuited before
  Electron's own catch block fires, and installed a targeted filter in
  `suppress-warnings.ts` (now actually imported from the entry point)
  so the specific `console.error("Error sending from webFrameMain:"…)`
  noise never reaches the terminal. Any other payload still surfaces.

* `dispatchAgentMessage` accepted the human-reader sentinel as a wake
  target when an agent replied to `__board__` — `wakeAgentIfPossible`
  then called `db.getAgent("__board__")`, threw, and the dispatcher
  kept repeating on every send. Strip `HUMAN_SENDER_ID` at
  `resolveMessageWakeTargets`, and keep a defense-in-depth guard in the
  heartbeat so a stray caller (future automation fan-out) cannot
  reintroduce the crash.

* Pi's skills loader rejects any SKILL.md whose frontmatter `name`
  diverges from its parent directory. The four bundled `my-writing-style`
  copies declared `name: writing-style-skill`, so every install emitted
  a warning and dropped the skill. They also lived as orphan gitlinks
  (mode 160000 without .gitmodules), and the global `*.md` gitignore
  hid every other SKILL.md from version control. Fixed the frontmatter
  to match the dir, converted the dangling submodules to plain trees,
  and allowlisted `builtin-skills/**/*.md` so a fresh clone carries the
  catalogue instead of silently losing it.
2026-04-20 08:13:48 -04:00

4.2 KiB

Data Reading & Analysis Guide

Reference for the READ path. Use xlsx_reader.py for structure discovery and data quality auditing, then pandas for custom analysis. Never modify the source file.


When to Use This Path

The user asks to read, analyze, view, summarize, extract, or answer questions about an Excel/CSV file's contents, without requiring file modification. If modification is needed, hand off to edit.md.


Workflow

Step 1 — Structure Discovery

Run xlsx_reader.py first. It handles format detection, encoding fallback, structure exploration, and data quality audit:

python3 SKILL_DIR/scripts/xlsx_reader.py input.xlsx                 # full report
python3 SKILL_DIR/scripts/xlsx_reader.py input.xlsx --sheet Sales   # single sheet
python3 SKILL_DIR/scripts/xlsx_reader.py input.xlsx --quality       # quality audit only
python3 SKILL_DIR/scripts/xlsx_reader.py input.xlsx --json          # machine-readable

Supported formats: .xlsx, .xlsm, .csv, .tsv. The script tries multiple encodings for CSV (utf-8-sig, gbk, utf-8, latin-1).

Step 2 — Custom Analysis with pandas

Load data and perform the analysis the user requests:

import pandas as pd
df = pd.read_excel("input.xlsx", sheet_name=None)  # dict of all sheets
# For CSV: pd.read_csv("input.csv")

Header handling (when the default header=0 doesn't work):

Situation Code
Header on row 3 pd.read_excel(path, header=2)
Multi-level merged header pd.read_excel(path, header=[0, 1])
No header pd.read_excel(path, header=None)

Analysis quick reference:

Scenario Pattern
Descriptive stats df.describe() or df['Col'].agg(['sum', 'mean', 'min', 'max'])
Group aggregation df.groupby('Region')['Revenue'].agg(Total='sum', Avg='mean')
Top N df.groupby('Region')['Revenue'].sum().sort_values(ascending=False).head(5)
Pivot table df.pivot_table(values='Revenue', index='Region', columns='Quarter', aggfunc='sum', margins=True)
Time series df.set_index(pd.to_datetime(df['Date'])).resample('ME')['Revenue'].sum()
Cross-sheet merge pd.merge(sales, customers, on='CustomerID', how='left', validate='m:1')
Stack sheets pd.concat([df.assign(Source=name) for name, df in sheets.items()], ignore_index=True)
Large files (>50MB) pd.read_excel(path, usecols=['Date', 'Revenue']) or pd.read_csv(path, chunksize=10000)

Step 3 — Output

If the user specifies an output file path, write results to it (highest priority). Format the report as:

## Analysis Report: {filename}
### File Overview     — format, sheets, row counts
### Data Quality      — nulls, duplicates, mixed types (or "no issues")
### Key Findings      — direct answer to the user's question
### Additional Notes  — formula NaN, encoding issues, caveats

Numeric display: monetary 1,234,567.89, percentage 12.3%, multiples 8.5x, counts as integers.


Common Pitfalls

Pitfall Cause Fix
Formula cells read as NaN <v> cache empty in freshly generated files Inform user; suggest opening in Excel and re-saving; or use libreoffice_recalc.py
CSV encoding errors Chinese Windows exports use GBK xlsx_reader.py auto-tries multiple encodings; manually specify if all fail
Mixed types in column Column has both numbers and text (e.g., "N/A") pd.to_numeric(df['Col'], errors='coerce') — report unconvertible rows
Year shows as 2,024 Thousands separator format applied to year df['Year'].astype(int).astype(str)
Multi-level headers Two-row header merged pd.read_excel(path, header=[0, 1]), then flatten with ' - '.join()
Row number mismatch pandas 0-indexed vs Excel 1-indexed excel_row = pandas_index + 2 (+1 for 1-index, +1 for header)

Critical: Never open with data_only=True then save() — this permanently destroys all formulas.


Prohibitions

  • Never modify the source file (no save(), no XML edits)
  • Never report formula NaN as "data is zero" — explain it's a formula cache issue
  • Never report pandas indices as Excel row numbers
  • Never make speculative conclusions unsupported by the data