agentsclimarketplace

Data analyse

Skill moonlight-lupin/data-toolkit/skills/data-analyse

Data prep toolkit for finance & ops: extract, tidy, reconcile, analyse, visualise — powered by deterministic engines for consistent and accurate outputs. From Phronesis Applied.

Install
npx -y skills add moonlight-lupin/data-toolkit --skill data-analyse

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Analyse a dataset and deliver the insights and key metrics that matter for it — an insight brief with headline findings, trends, breakdowns, concentration, outliers and ageing, tailored to the type of data (transactions, receivables, pipeline, survey, task list, any table). Use when the user says "analyse this data", "what are the key metrics", "any insights from this spreadsheet", "summarise this export", "what's driving the numbers", "who are the top customers", or hands over a table and asks what it says. Works INTENT-FIRST: asks what question the data should answer, profiles it, proposes a plan → you confirm → computes every metric deterministically (local engine, exact Decimal, currency-aware) → writes a calibrated brief separating observation from interpretation. Metrics computed locally by the engine. NOT data cleaning (data-tidy), NOT matching two datasets (data-reconcile), NOT a dashboard (data-visualise — natural next step); descriptive analysis only, never financial or investment advice.

SKILL.md

13.6 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it

Data Analyse

Take a dataset — a clean(ish) .xlsx/CSV, a pasted table, or the output of another toolkit skill — and deliver an insight brief: the headline findings, the key metrics for that type of data, and honest caveats. The design is intent-first (ask what question the data should answer before computing anything) and compute-then-interpret (every quoted number comes from the deterministic local engine; the narrative interprets, it never generates figures).

Self-sufficient & local engine. All computation runs on your machine via scripts/analyse.py (+ the shared toolkit engine) — no network calls. Note the AI agent driving the skill does send whatever it reads into its context to your AI provider; "never leaves" is not claimed. See ../../PRINCIPLES.md#data-handling--pii-policy.

Workflow

0 — Intent (ask up front)

Before computing anything, ask (a short AskUserQuestion):

  1. What question should this data answer? ("are sales growing?", "where's the risk in receivables?", "which segment matters?") — or is it an open "tell me what you see"?
  2. Who's it for and what decision does it feed? — a partner one-pager reads differently from a working analysis.
  3. Anything known already? — targets, prior-period figures, or a hypothesis to test.

An open-ended "just analyse it" is fine — then the playbook (step 3) drives the metric selection, and the brief says so.

1 — Ingest

Same shared engine as the other skills (../../scripts/):

import sys, pathlib
sys.path.insert(0, str(pathlib.Path("../../scripts").resolve()))
import ingest
header_rows, note = ingest.read_any(path)     # xlsx/csv/pdf/docx/msg; read_paste for pasted tables

Run from the skill directory (skills/data-analyse/). The ../../scripts path resolves to the toolkit-root scripts/ where ingest.py and dataclean.py live. The analysis engine (analyse.py) is in this skill's own scripts/ subdirectory. Multi-tab workbooks: read_any raises SheetSelectionRequired if several tabs hold data — list the sheets and ask, don't guess.

For files with 10k+ rows, use ingest.read_large instead of read_any to avoid OOM. See references/large-file-patterns.md for vectorised operation guidance.

2 — Profile & quality gate

dataclean.profile_table(header, rows) / score_quality(...) — column types, missing %, duplicates. If the data is too messy to analyse honestly (columns that won't parse, heavy duplication, mixed junk), stop and route to data-tidy first — analysing dirty data produces confident-looking nonsense. A little noise is fine: the engine counts every skipped/unparseable cell and the brief must disclose those counts.

Currency gate: analyse.currency_mix(col) — pass the currency-bearing column: the amount column when codes ride inside the amounts (S$100, £1,000), or the separate ISO-code column when the layout is two columns (Amount + Currency of GBP/USD) — the common export shape. If it reports more than one code, never sum the amounts as-is (100 USD ≠ 100 SGD). Split by currency (breakdown(by=<currency col>)) or ask.

3 — Propose the analysis plan (confirm before computing)

analyse.suggest_playbook(header, rows) maps columns to roles (dates, amounts, categories, ids) and suggests analyses. Combine that with the intent and the data-type playbook (references/playbooks.md — transactions, receivables/ageing, pipeline, survey/categorical, task/ops list, general ledger, inventory, spend/AP, time series, cross-domain, generic) into a short plan: "I'll look at: monthly trend of Amount, breakdown by Customer with concentration, outliers, and ageing from Due date as of 12 Jul 2026 — sound right?" Show it; confirm.

Two datasets provided? If the user hands over two files that share a dimension (sales vs competitor prices, actual vs budget), that's the cross-domain playbook — join_on to relate them on the shared key (report coverage), then compare_series to read position and co-movement. It relates, it does not match line-by-line — reconciling two sets to find breaks is data-reconcile. Nail the join key and grain before computing.

4 — Compute (deterministic, engine only)

All metrics come from scripts/analyse.py — exact Decimal, dayfirst dates, reusing the shared parsers:

FunctionWhat it computes
numeric_summary(col)n, missing, skipped, total, mean, median, quartiles, min/max, negatives
outliers_iqr(col)Tukey fences + the outlying values (exact counts)
breakdown(header, rows, by, value=)groups sorted largest-first with shares, top-1/top-3 share, groups-to-80%
period_series(header, rows, date_col, value=, grain=)month/quarter/year totals with gap periods filled as zero, deltas, % change, YoY
ageing(header, rows, date_col, as_of=, value=)0–30/31–60/61–90/90+ buckets (configurable); future & unparsed bucketed visibly
join_on(l_header, l_rows, r_header, r_rows, on=)two-dataset join on a shared key (case/space-folded); returns the joined table + a matched/left-only/right-only coverage report
compare_series(a, b, a_label=, b_label=)relate two ordered series (gap / ratio / % diff per key, Pearson correlation, ±1 lead/lag) — for cross-domain & actual-vs-budget
concentration(values, top_n=4)HHI (0–10000 antitrust scale), top-N share, groups-to-80%, classification (fragmented/moderate/concentrated/highly concentrated) — for revenue/customer concentration
pivot(header, rows, rows_col, cols_col, value=, aggfunc=)2D cross-tab matrix (rows × columns) with sum/count/mean aggregation + row/column grand totals
distribution(values)skewness + excess kurtosis (Fisher-Pearson, Excel-compatible) + classification (symmetric/moderately skewed/highly skewed/heavy-tailed)
trend(series)linear regression slope + R² + direction (rising/falling/weakly/flat) on an ordered (key, value) series — descriptive, not a forecast
percentile(values, q)arbitrary quantile(s) with linear interpolation (Excel PERCENTILE.INC-compatible); single float → {value, n, skipped}, list → {q: value} — p90/p95/p99 for VaR/latency
cohort(header, rows, id_col, date_col, value=, grain=)retention matrix: group by first-active period, track over subsequent periods. Count mode: retention = active/size (0–1). Value mode: matrix = value sums, retention still entity-count-based, value_matrix separate. All rows padded rectangular.
correlation_matrix(header, rows, columns)pairwise Pearson across N numeric columns (symmetric matrix). Row-wise alignment — only rows where BOTH cells parse are paired (junk in one column doesn't shift others). Association, not cause.
rolling(series, window, func=)trailing-window aggregate (mean/sum/median) on an ordered series — smoothing, pairs with period_series. None values in a window are skipped.
gini(values)Gini coefficient (0=equal, 1=concentrated) + classification — inequality of distribution, complements HHI
seasonality(header, rows, date_col, value=, grain=)average by month-of-year (1–12) or quarter (1–4) + seasonal index. Overall average = mean of seasons WITH data (not grand/12).
filter_rows(header, rows, filters)declarative row filter ({"col", "op", "value"/"values"/"lo"+"hi"}) — == != > >= < <= in not_in between not_between contains is_empty not_empty, ANDed. Numbers via parse_number, dates via parse_date, strings case-insensitive; between is inclusive of both ends. A text cell against a numeric threshold is incomparable — dropped and counted, never string-compared. Returns (rows, report) with n_in/n_out/n_dropped and per-filter removed counts
currency_mix(col) / numbers(col)currency codes present / parsed Decimals + skipped count
fmt / pct / render_md(...)house-style formatting + markdown tables for the brief
write_metrics_xlsx(sections, path)optional metrics workbook (one sheet per analysis)

Run computations in a script (not mental arithmetic) so the analysis is reproducible; keep the script in the working folder as the audit trail. The engine ships tested — don't re-run its --self-test or envcheck.py as part of a normal analysis (that's setup overhead the user pays every run); reach for them only when an import fails or the environment is genuinely uncertain.

5 — Write the insight brief

ALWAYS this structure (markdown; British English, dates DD MMM YYYY, currency with code):

# [Dataset] — insight brief                      (as of [date], n = [rows])
## Headline            3–5 findings, most consequential first, each with its number
## Key metrics         the tables from the engine (render_md)
## Notable             outliers, concentration, anomalies — with the specific rows/values
## Caveats & quality   skipped cells, missing %, gap periods, currency notes, what this
                       data CANNOT answer
[footer: draft for review — descriptive analysis, not advice]

Deliver the brief as a .md (plus the optional metrics .xlsx). Keep it to one page of reading unless asked for depth.

6 — Offer the next step

  • Visual one-pager wanted? → hand the computed series/breakdowns to data-visualise (its rows_from_xlsx reads the metrics workbook directly).
  • Numbers look wrong vs another source? → that's data-reconcile, not this skill.

Insight discipline (what makes the brief trustworthy)

  • Every number is computed. If a figure appears in the brief, it came out of the engine or is an arithmetic step shown in the brief. No free-form estimates.
  • Observation ≠ interpretation. "March revenue fell 40% MoM" is an observation; "likely the contract gap" is an interpretation — label it as a possible explanation and say what would confirm it. Never present correlation as cause.
  • Calibrated language. "Verified" vs "likely" vs "couldn't confirm" (PRINCIPLES.md #4). A trend over 3 periods is "early"; over 2 it is not a trend.
  • Disclose the denominators. Shares, averages and trends state n and what was excluded (skipped cells, unparsed dates, filled gap periods).
  • Ratios and multiples are computed too. "20× the typical ticket" is only meaningful with the comparator named — compute it from engine figures and say what the base is (median, mean, next-largest). An eyeballed multiple is a free-form estimate in disguise.
  • Never invent a conversion. No exchange rates, deflators or per-unit factors the user didn't supply — a blended figure built on an assumed rate is an invented number, however clearly footnoted. Report per-currency (per-unit) and, if a combined view is wanted, ask for the rate to use.
  • Descriptive, not advisory. The brief describes what the data shows. It never recommends buying/selling/pricing/provisioning — flag the decision to the qualified owner (drafts, not advice).

Files

  • scripts/analyse.py — the metric engine (see table above); reuses the shared parsers in ../../scripts/dataclean.py; python analyse.py --self-test.
  • references/playbooks.md — per-data-type metric menus: which analyses matter for transactions, receivables, pipeline, survey, ops-list, time-series and generic tables.
  • examples/sample_sales.csv — a synthetic sales export (no real data) to demo against.

Principles

Behavioural charter: ../../PRINCIPLES.md — drafts not advice, never invent, honesty and calibration, plain speech, action boundary.

Data handling

Metrics are computed on your machine — the data, the metrics and the brief stay on your synced or shared file store, and the engine uploads nothing. (The AI agent driving the skill does send whatever it reads into its context to your AI provider.) A brief that names individuals or quotes confidential figures is gated on any egress. Full rule: ../../PRINCIPLES.md#data-handling--pii-policy.

Feedback

Improvement or bug? Use the toolkit's shared format — ../../CONTRIBUTING.md#skill-feedback-format — save as feedback_data-analyse_[date].txt and hand it to the user to file; fix in scope if asked.

Requirements & mode

Portable: Python + openpyxl for .xlsx in/out; PDF/.docx/.msg inputs use the same optional libraries as data-tidy (degrade per-source). No network, no Office, no credentials. If an import fails or the environment is uncertain, pre-screen with python ../../scripts/envcheck.py and see ../../README.md#mode--environment-compatibility — otherwise just start analysing.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.