pi-eda 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/agents/critical-auditor.md +23 -0
- package/agents/job-runner.md +34 -0
- package/agents/naive-reader.md +31 -0
- package/agents/script-checker.md +27 -0
- package/eda.mplstyle.example +28 -0
- package/extensions/show.ts +114 -0
- package/package.json +27 -0
- package/skills/exploring-data/SKILL.md +70 -0
- package/skills/exploring-data/checking-and-running-scripts.md +97 -0
- package/skills/exploring-data/directory-structure.md +44 -0
- package/skills/exploring-data/plotting.md +74 -0
- package/skills/exploring-data/pre-code-checkpoints.md +63 -0
- package/skills/exploring-data/workflow.md +66 -0
- package/skills/finishing-exploratory-data-analysis/SKILL.md +70 -0
- package/skills/finishing-exploratory-data-analysis/verification-dispatch.md +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# pi-eda
|
|
2
|
+
|
|
3
|
+
Pi skills and subagents for interactive exploratory data analysis.
|
|
4
|
+
|
|
5
|
+
- `skills/exploring-data`: iterative analysis & plotting
|
|
6
|
+
- `skills/finishing-exploratory-data-analysis`: locking in analysis into a wiki-style report
|
|
7
|
+
- `show` extension: renders a figure to the user in the TUI without spending tokens on it
|
|
8
|
+
|
|
9
|
+
## Requires
|
|
10
|
+
|
|
11
|
+
The [`pi-subagents`](https://www.npmjs.com/package/pi-subagents) package, for
|
|
12
|
+
custom-agent support and the `/skill:pi-subagents` dispatch pattern the skills
|
|
13
|
+
reference.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi install git:github.com/shivam-v-verma/pi-eda
|
|
19
|
+
pi install npm:pi-eda
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Matplotlib style
|
|
23
|
+
|
|
24
|
+
`skill:exploring-data` respects a matplotlib template `eda.mplstyle`,
|
|
25
|
+
usually located at `~/.config/matplotlib/stylelib/eda.mplstyle`.
|
|
26
|
+
|
|
27
|
+
A minimal example file `eda.mplstyle.example` is given here.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: critical-auditor
|
|
3
|
+
description: Confirms an EDA report/script's claims match the agreed intent, not just clarity
|
|
4
|
+
tools: read, grep, find
|
|
5
|
+
defaultContext: fork
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Confirm the report's claims and the script's implementation actually
|
|
9
|
+
match what was agreed -- correct semantic intent, not just clarity. If
|
|
10
|
+
you have no conversation context (fork wasn't available), expect a
|
|
11
|
+
written recap of the framing/decisions instead -- context-free, you're
|
|
12
|
+
a naive reader and thus not able to do your job properly.
|
|
13
|
+
|
|
14
|
+
- Inputs: the report, figure(s), numbered script(s), and any associated
|
|
15
|
+
summary data. You need all of the work product to evaluate correctness.
|
|
16
|
+
- Check whether the report/script match what was agreed; flag drift
|
|
17
|
+
between intent and implementation.
|
|
18
|
+
- Distrust rule: don't trust matching/ordering/canonicalization logic
|
|
19
|
+
verified only on one easy example -- check it was tested on nontrivial
|
|
20
|
+
cases that could actually fail.
|
|
21
|
+
- Findings have no tiers: everything you report is drift between intent
|
|
22
|
+
and implementation. Never silently resolve it yourself -- report it
|
|
23
|
+
verbatim for the calling agent to surface.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: job-runner
|
|
3
|
+
description: Launches and monitors a heavy/long-running analysis script in the background
|
|
4
|
+
tools: bash, read
|
|
5
|
+
inheritProjectContext: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You own execution and monitoring of a full-scale run that's already been
|
|
9
|
+
checked and cleared to launch. You do not review or edit the script --
|
|
10
|
+
that already happened before you were dispatched.
|
|
11
|
+
|
|
12
|
+
## What to do
|
|
13
|
+
|
|
14
|
+
- Confirm inputs before launching:
|
|
15
|
+
- The estimated runtime and peak memory from the smoke test (should be
|
|
16
|
+
in the task you were given -- if missing, ask the dispatching agent
|
|
17
|
+
for it rather than guessing).
|
|
18
|
+
- Whether `systemd-run` is available on this machine.
|
|
19
|
+
- Launch the script as a background process (following the project's run
|
|
20
|
+
convention, e.g. `uv run`).
|
|
21
|
+
- Cap it with a memory limit so a runaway process gets killed by the OS
|
|
22
|
+
instead of taking down the machine, sized off the estimate with
|
|
23
|
+
headroom (e.g. 2x the estimated peak):
|
|
24
|
+
- `systemd-run --scope -p MemoryMax=<budget> --user -- uv run <script>`
|
|
25
|
+
if available.
|
|
26
|
+
- Otherwise, say so explicitly and fall back to periodic `ps`/`smem`
|
|
27
|
+
checks with a manual kill.
|
|
28
|
+
- Monitor progress and memory use periodically rather than blocking on it
|
|
29
|
+
synchronously -- this is in addition to the hard cap above, not a
|
|
30
|
+
replacement for it, since you want to know about a job trending toward
|
|
31
|
+
the ceiling before it gets killed.
|
|
32
|
+
- Report back once it completes: success/failure, runtime, and where the
|
|
33
|
+
output landed. On failure, include the actual error, not just "it
|
|
34
|
+
failed."
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: naive-reader
|
|
3
|
+
description: Confirms an EDA report reads as a clear, complete, standalone artifact
|
|
4
|
+
tools: read
|
|
5
|
+
defaultContext: fresh
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Confirm the report (with `index.md`) reads as a clear, comprehensive,
|
|
9
|
+
standalone artifact -- no missing context, no unexplained gaps. Read it
|
|
10
|
+
cold, as if returning in 6 months having forgotten everything.
|
|
11
|
+
|
|
12
|
+
- Inputs: report file, figure(s), summary CSV(s), and `index.md` for
|
|
13
|
+
project context. You may open the script only to resolve a specific
|
|
14
|
+
confusion, never to run it.
|
|
15
|
+
- Comprehension only -- you never judge whether a choice was right, only
|
|
16
|
+
whether it's explained.
|
|
17
|
+
- Confirm every figure file passed to you is actually embedded in the
|
|
18
|
+
report -- an unreferenced figure is material-tier, since there isn't an
|
|
19
|
+
interpretation for it.
|
|
20
|
+
|
|
21
|
+
## Severity rubric
|
|
22
|
+
|
|
23
|
+
| Tier | Definition |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| cosmetic | wording/labeling nit, doesn't change interpretation |
|
|
26
|
+
| confusing | correct and complete, but too dense/jargon-heavy to parse easily |
|
|
27
|
+
| clarifying | you can't tell why/what/how from the report alone. If you had to open the script to answer your own question, that's automatic clarifying-tier |
|
|
28
|
+
| material | your conclusion contradicts what the report claims, or the claim isn't backed by anything shown |
|
|
29
|
+
|
|
30
|
+
Report every finding with its tier. Do not silently decide a fix for
|
|
31
|
+
anything -- that's the calling agent's call, not yours.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: script-checker
|
|
3
|
+
description: Checks a script against stated intent/framing before a heavy scale-up run
|
|
4
|
+
tools: read, grep, find
|
|
5
|
+
inheritProjectContext: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You check a script against the user's stated intent/framing before an
|
|
9
|
+
expensive full-scale run. You review; you do not edit the script or run
|
|
10
|
+
it.
|
|
11
|
+
|
|
12
|
+
## What to check
|
|
13
|
+
|
|
14
|
+
- Does each transform (groupby, join, pivot, filter, etc.) actually do
|
|
15
|
+
what the stated intent/framing says it should.
|
|
16
|
+
- Any matching/ordering/canonicalization logic verified only on an
|
|
17
|
+
easy/symmetric case -- that's a red flag, not a pass. Ask whether it
|
|
18
|
+
was tested against a case that could actually fail.
|
|
19
|
+
- Anything that would silently produce a plausible-but-wrong result
|
|
20
|
+
(wrong join key, off-by-one window, unintended dtype coercion).
|
|
21
|
+
|
|
22
|
+
## Output
|
|
23
|
+
|
|
24
|
+
- If everything checks out, say so plainly -- don't invent issues.
|
|
25
|
+
- If something's off, name the exact line/transform and what's wrong
|
|
26
|
+
with it, specific enough that the calling agent can fix it without
|
|
27
|
+
guessing.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Shared matplotlib style for /skill:exploring-data.
|
|
2
|
+
# This is a template shown for example; include in default matplotlib
|
|
3
|
+
# style sheet dir (see README.md).
|
|
4
|
+
# See plotting.md for the conventions this backs and what still needs a
|
|
5
|
+
# per-script judgment call (aspect ratio, bin count, title text, etc).
|
|
6
|
+
#
|
|
7
|
+
# Full rcParams menu:
|
|
8
|
+
# https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/mpl-data/matplotlibrc
|
|
9
|
+
|
|
10
|
+
figure.dpi: 150
|
|
11
|
+
savefig.dpi: 150
|
|
12
|
+
savefig.format: png
|
|
13
|
+
savefig.bbox: tight
|
|
14
|
+
figure.autolayout: True
|
|
15
|
+
|
|
16
|
+
axes.grid: False
|
|
17
|
+
# CSS named colors: https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
|
|
18
|
+
axes.prop_cycle: cycler('color', ['lightsteelblue', 'darksalmon', 'darkseagreen', 'plum', 'burlywood', 'rosybrown'])
|
|
19
|
+
|
|
20
|
+
font.size: 10
|
|
21
|
+
axes.titlesize: 10
|
|
22
|
+
axes.labelsize: 10
|
|
23
|
+
legend.fontsize: 10
|
|
24
|
+
xtick.labelsize: 10
|
|
25
|
+
ytick.labelsize: 10
|
|
26
|
+
legend.frameon: False
|
|
27
|
+
|
|
28
|
+
image.cmap: Blues
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Show Extension - Render an image to the user without spending LLM tokens on it.
|
|
3
|
+
*
|
|
4
|
+
* `show` reads an image file and renders it in the TUI via the built-in
|
|
5
|
+
* `Image` component. The LLM only ever sees a short confirmation string in
|
|
6
|
+
* `content` (what gets sent back to the model) - the image bytes live in
|
|
7
|
+
* `details`, which is TUI-only and never enters LLM context. If the model
|
|
8
|
+
* later needs to actually look at the image, it uses the normal `read` tool.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFile, stat } from "node:fs/promises";
|
|
12
|
+
import { extname, resolve } from "node:path";
|
|
13
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import { Image, Text } from "@earendil-works/pi-tui";
|
|
15
|
+
import { Type } from "typebox";
|
|
16
|
+
|
|
17
|
+
const MEDIA_TYPES: Record<string, string> = {
|
|
18
|
+
".png": "image/png",
|
|
19
|
+
".jpg": "image/jpeg",
|
|
20
|
+
".jpeg": "image/jpeg",
|
|
21
|
+
".gif": "image/gif",
|
|
22
|
+
".webp": "image/webp",
|
|
23
|
+
".bmp": "image/bmp",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
interface ShowDetails {
|
|
27
|
+
path: string;
|
|
28
|
+
base64: string;
|
|
29
|
+
mediaType: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default function (pi: ExtensionAPI) {
|
|
33
|
+
pi.registerTool({
|
|
34
|
+
name: "show",
|
|
35
|
+
label: "Show",
|
|
36
|
+
description:
|
|
37
|
+
"Display an image to the user in the terminal without loading its pixels into your own context. " +
|
|
38
|
+
"Use read on the same path afterward if you need to analyze the image yourself.",
|
|
39
|
+
promptSnippet:
|
|
40
|
+
"Show an image to the user in the terminal (does not add the image to your context)",
|
|
41
|
+
promptGuidelines: [
|
|
42
|
+
"Use show to display an image the user asked to see; use read instead when you need to look at the image yourself.",
|
|
43
|
+
],
|
|
44
|
+
parameters: Type.Object({
|
|
45
|
+
path: Type.String({
|
|
46
|
+
description: "Path to the image file (png, jpg, gif, webp, bmp)",
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
51
|
+
const rawPath = params.path.startsWith("@")
|
|
52
|
+
? params.path.slice(1)
|
|
53
|
+
: params.path;
|
|
54
|
+
const absolutePath = resolve(ctx.cwd, rawPath);
|
|
55
|
+
|
|
56
|
+
const mediaType = MEDIA_TYPES[extname(absolutePath).toLowerCase()];
|
|
57
|
+
if (!mediaType) {
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{ type: "text", text: `Not a supported image type: ${params.path}` },
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const fileStat = await stat(absolutePath).catch(() => null);
|
|
67
|
+
if (!fileStat?.isFile()) {
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: `File not found: ${params.path}` }],
|
|
70
|
+
isError: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (ctx.mode !== "tui") {
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: `Cannot render images outside interactive TUI mode (${ctx.mode}).`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
isError: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const base64 = (await readFile(absolutePath)).toString("base64");
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
content: [{ type: "text", text: `Displayed ${params.path} to the user.` }],
|
|
90
|
+
details: { path: params.path, base64, mediaType } as ShowDetails,
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
renderCall(args, theme, _context) {
|
|
95
|
+
return new Text(
|
|
96
|
+
theme.fg("toolTitle", theme.bold("show ")) + theme.fg("muted", args.path),
|
|
97
|
+
0,
|
|
98
|
+
0,
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
renderResult(result, _options, theme, _context) {
|
|
103
|
+
const details = result.details as ShowDetails | undefined;
|
|
104
|
+
if (!details) {
|
|
105
|
+
const text = result.content[0];
|
|
106
|
+
return new Text(text?.type === "text" ? text.text : "", 0, 0);
|
|
107
|
+
}
|
|
108
|
+
return new Image(details.base64, details.mediaType, theme, {
|
|
109
|
+
maxWidthCells: 80,
|
|
110
|
+
maxHeightCells: 24,
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-eda",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pi tooling for interactive exploratory data analysis.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Shivam V Verma",
|
|
7
|
+
"keywords": ["pi-package", "pi", "eda", "exploratory-data-analysis"],
|
|
8
|
+
"files": [
|
|
9
|
+
"README.md",
|
|
10
|
+
"agents",
|
|
11
|
+
"eda.mplstyle.example",
|
|
12
|
+
"extensions",
|
|
13
|
+
"skills"
|
|
14
|
+
],
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
17
|
+
"@earendil-works/pi-tui": "*",
|
|
18
|
+
"typebox": "*"
|
|
19
|
+
},
|
|
20
|
+
"pi": {
|
|
21
|
+
"extensions": ["./extensions"],
|
|
22
|
+
"skills": ["./skills"],
|
|
23
|
+
"subagents": {
|
|
24
|
+
"agents": ["./agents"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exploring-data
|
|
3
|
+
description: Use when exploring a dataset, generating plots, or iterating on data analysis scripts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Related skills:** Dispatch the `script-checker` with `/skill:pi-subagents`. Once a figure/analysis seems meaningful, use `/skill:finishing-exploratory-data-analysis` before writing it up or committing.
|
|
7
|
+
|
|
8
|
+
# Exploring Data
|
|
9
|
+
|
|
10
|
+
**Scope, small to large:**
|
|
11
|
+
|
|
12
|
+
- *plot*: a chart type/category (e.g. histogram, scatter)
|
|
13
|
+
- *figure*: one rendered image
|
|
14
|
+
- *question*: one concept to test through one or more figures
|
|
15
|
+
- *analysis*: one `.md` *report* file + its paired scripts/figs folder
|
|
16
|
+
- *project*: the whole `eda/` directory, created across many
|
|
17
|
+
`/skill:exploring-data` sessions
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
**Core principle:** Your job is to help the user surface hypotheses,
|
|
22
|
+
and suggest or build the plots that interrogate them. What a confirmed pattern
|
|
23
|
+
*means*, the story it tells, is the user's call: hand back a clear summary of
|
|
24
|
+
what the figure shows, not a conclusion dressed as a finding.
|
|
25
|
+
|
|
26
|
+
See `workflow.md` for stages of this skill. In all stages, confirm framing
|
|
27
|
+
with the user. Never run a batch of steps by yourself; always interleave
|
|
28
|
+
by checking for the user's insight/thoughts.
|
|
29
|
+
|
|
30
|
+
A good hypothesis is usually a simple, clean one -- reachable through better
|
|
31
|
+
framing of the question, not through aggressively slicing the dataset more ways
|
|
32
|
+
looking for a signal.
|
|
33
|
+
|
|
34
|
+
## Directory Structure
|
|
35
|
+
|
|
36
|
+
Default to `eda/` at the project root (ask if a different name/location is
|
|
37
|
+
wanted). See `directory-structure.md` for the full layout convention
|
|
38
|
+
(scripts/figs tree, numbering rules, shared-code placement).
|
|
39
|
+
|
|
40
|
+
## Core Data Practices
|
|
41
|
+
|
|
42
|
+
Always, whether running a numbered script or an ad hoc check (e.g.
|
|
43
|
+
`python -c "..."`):
|
|
44
|
+
|
|
45
|
+
- Check input file size(s) and be aware of runtime/memory.
|
|
46
|
+
- Set a timeout via the `timeout` param (seconds) in pi's `bash` tool
|
|
47
|
+
on any check or smoke test. If it times out, reduce sample size and
|
|
48
|
+
extrapolate rather than waiting for a highly accurate estimate.
|
|
49
|
+
- Don't delete scripts or attempts yourself unless the user explicitly
|
|
50
|
+
asks to. If a script is paused or abandoned, leave a module/function
|
|
51
|
+
docstring giving its status and where it was left off.
|
|
52
|
+
- If processing is heavy, decide with the user whether to run on the
|
|
53
|
+
full dataset or a representative subset for this pass.
|
|
54
|
+
|
|
55
|
+
## Common Mistakes
|
|
56
|
+
|
|
57
|
+
The most cross-cutting/devastating failures. Each reference file above has
|
|
58
|
+
its own narrower table.
|
|
59
|
+
|
|
60
|
+
| Mistake | Fix |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| Running the full dataset before a smoke test | See `checking-and-running-scripts.md` -- always sample/time on a subset first |
|
|
63
|
+
| Auto-advancing to the next question without a framing check | See `pre-code-checkpoints.md` -- confirm framing before each new question, not once for the whole analysis |
|
|
64
|
+
| Picking the report/subfolder name yourself instead of asking | Ask before creating it -- one name, shared by the file and its folder |
|
|
65
|
+
| Launching a heavy scale-up run while the `script-checker` is still pending | See `checking-and-running-scripts.md` -- wait for it, or the expensive run finishes before a material issue could surface |
|
|
66
|
+
| Deleting/pruning a failed or paused script | Leave it in place with a status docstring unless the user explicitly asks to remove it |
|
|
67
|
+
| Treating an approval-sounding signal ("looks great", "keep going", "I trust your judgment") as done | Ask whether to move to `/skill:finishing-exploratory-data-analysis` -- don't auto-advance and don't stay silent |
|
|
68
|
+
| Chasing a pattern that only appears after trying many slices/cuts of the data | Multiple-comparisons risk -- go back to framing, not more cuts |
|
|
69
|
+
| Stating a small or non-random-sample result as a general fact | State it as a property of the sample examined ("true in this subset") until checked for generalization |
|
|
70
|
+
| Writing to `index.md` or the report before `/skill:finishing-exploratory-data-analysis` | Both are created/updated together at lock-in checkpoint -- confirm scope/framing conversationally during exploration instead |
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Checking and Running Scripts
|
|
2
|
+
|
|
3
|
+
Building confidence in a script for `/skill:exploring-data`, then deciding
|
|
4
|
+
how to run it. See `workflow.md` for where this fits in the full loop
|
|
5
|
+
(the light/heavy fork is inlined there, each branch with its own check
|
|
6
|
+
step and loop-back on findings).
|
|
7
|
+
|
|
8
|
+
## Sanity Checking a Script
|
|
9
|
+
|
|
10
|
+
- After each nontrivial transform (groupby, join, pivot, filter, etc.), do
|
|
11
|
+
a quick check (`.head()`, row counts, spot-check a few values) that the
|
|
12
|
+
output matches what the transform should have done -- not just once at
|
|
13
|
+
the end of the script.
|
|
14
|
+
- Pick a case that could actually fail, not the first one at hand --
|
|
15
|
+
especially for canonicalization/ordering/matching logic, where an easy
|
|
16
|
+
case can pass while hiding a real bug.
|
|
17
|
+
|
|
18
|
+
## Smoke Testing a Script
|
|
19
|
+
|
|
20
|
+
- Run on a sampled/head subset (fixed seed) and time it before running at
|
|
21
|
+
full scale.
|
|
22
|
+
- After it runs, glance at the actual output values, not just "it
|
|
23
|
+
completed in time." A fast clean run on garbage output is not a
|
|
24
|
+
passing smoke test.
|
|
25
|
+
- Exception: a cached-read-and-plot script -- one that purely reads an
|
|
26
|
+
already-validated cached table and plots it, with zero computation (no
|
|
27
|
+
groupby, join, pivot, or filter). State that justification explicitly
|
|
28
|
+
instead of skipping silently.
|
|
29
|
+
|
|
30
|
+
## Judging Heavy vs. Light Scale-up
|
|
31
|
+
|
|
32
|
+
Goal: increase iteration speed without being reckless. Either extreme
|
|
33
|
+
wastes the user's time -- blocking every quick diff on a check likely to
|
|
34
|
+
pass, or committing to a large/expensive run that turns out wrong.
|
|
35
|
+
|
|
36
|
+
- Judge from the smoke-test timing/size ratio whether the full-scale run
|
|
37
|
+
will be heavy (long-running or memory-heavy relative to the sample --
|
|
38
|
+
e.g. 1% took a second but full scale extrapolates to minutes).
|
|
39
|
+
- Rough thresholds based on estimated time: light if under ~1 minute,
|
|
40
|
+
heavy if over ~5 minutes. In between is a judgment call.
|
|
41
|
+
- State that judgment explicitly: "sample took Xs, full run estimated ~Y,
|
|
42
|
+
treating as heavy."
|
|
43
|
+
|
|
44
|
+
## Light Scale-up
|
|
45
|
+
|
|
46
|
+
- No `script-checker` dispatch -- reread the script yourself before
|
|
47
|
+
running: does it match the user's stated intent/framing, does each
|
|
48
|
+
nontrivial transform do what it should.
|
|
49
|
+
- If the reread surfaces an issue, fix it and reread again before
|
|
50
|
+
running -- don't run first and raise the concern after.
|
|
51
|
+
- This is a deliberately lower bar than the heavy path: a light-path
|
|
52
|
+
mistake is cheap to catch downstream too, since the run finishes fast
|
|
53
|
+
and you're looking at the output right away. The real second-set-of-
|
|
54
|
+
eyes gate for the analysis still happens at
|
|
55
|
+
`/skill:finishing-exploratory-data-analysis`'s lock-in checkpoint --
|
|
56
|
+
this reread isn't the last line of defense, it's a cheap intermediate
|
|
57
|
+
one.
|
|
58
|
+
|
|
59
|
+
## Heavy Scale-up
|
|
60
|
+
|
|
61
|
+
- Dispatch the `script-checker` before launching:
|
|
62
|
+
`subagent({agent:"script-checker", task:"<script path + stated intent/framing>"})`.
|
|
63
|
+
- Do not launch until it has returned and come back clean.
|
|
64
|
+
- If it's still running, wait for it (or say explicitly you're waiting)
|
|
65
|
+
-- don't launch anyway planning to fold in feedback once it lands.
|
|
66
|
+
- Launching "in parallel while the `script-checker` runs in the
|
|
67
|
+
background" still counts as launching without it -- the expensive run
|
|
68
|
+
finishes and gets shown to the user before a material issue could
|
|
69
|
+
surface.
|
|
70
|
+
- A `script-checker` pass only checks the script -- it never substitutes
|
|
71
|
+
for the lock-in checkpoint in
|
|
72
|
+
`/skill:finishing-exploratory-data-analysis` once a figure/question is
|
|
73
|
+
ready to show the user.
|
|
74
|
+
- Two or more edits since the last `script-checker` dispatch count as one
|
|
75
|
+
nontrivial change on their own -- dispatch again at that point, don't
|
|
76
|
+
wait for it to feel big enough.
|
|
77
|
+
|
|
78
|
+
### Dispatching the `job-runner`
|
|
79
|
+
|
|
80
|
+
- Once clear to launch:
|
|
81
|
+
`subagent({agent:"job-runner", task:"<script path + output location + estimated runtime + estimated peak memory>"})`.
|
|
82
|
+
This frees the main session to keep iterating while it runs. Pass the
|
|
83
|
+
runtime/memory estimate from your smoke test (see "Judging Heavy vs.
|
|
84
|
+
Light Scale-up" above) rather than making it re-derive them blind.
|
|
85
|
+
|
|
86
|
+
## Common Mistakes
|
|
87
|
+
|
|
88
|
+
| Mistake | Fix |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| Running the full dataset (or an ad hoc exploratory probe) before a smoke test | Always sample/time on a subset first -- applies to one-off probes too, not just numbered scripts |
|
|
91
|
+
| Silently skipping the smoke test on a "just read cache and plot" script | Only skip for zero-computation cached-read-and-plot, and state that justification explicitly |
|
|
92
|
+
| Trusting a sanity check that only ran on an easy/symmetric case | Pick a case that could actually have failed, especially for matching/ordering/canonicalization logic |
|
|
93
|
+
| Checking that a smoke test ran fast/clean without looking at what it produced | Glance at the actual output values -- a clean run on garbage isn't a pass |
|
|
94
|
+
| Running a light-path script without rereading it first because it's "just quick" | Reread against the stated intent/framing before running -- speed doesn't waive the check, it just changes who does it |
|
|
95
|
+
| Launching a heavy scale-up "while the `script-checker` runs in the background" instead of waiting for it | Confirm the `script-checker` came back clean before launching -- don't launch and plan to fold feedback in later |
|
|
96
|
+
| Letting 2+ small edits pile up on a heavy-path script since the last `script-checker` dispatch because none felt big enough alone | Dispatch again once 2+ edits have landed |
|
|
97
|
+
| Treating a mid-work `script-checker` pass as covering the finishing skill's lock-in checkpoint | Different gate, different artifact -- a pending or completed `script-checker` pass never substitutes for it |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Directory Structure
|
|
2
|
+
|
|
3
|
+
Layout convention for `/skill:exploring-data`.
|
|
4
|
+
|
|
5
|
+
Default to `eda/` at the project root (ask if a different name/location is
|
|
6
|
+
wanted).
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
eda/
|
|
10
|
+
index.md # landing pad for readers -- what's been done,
|
|
11
|
+
# links to each report below
|
|
12
|
+
customer_churn.md # a report -- lives directly under eda/
|
|
13
|
+
customer_churn/ # paired folder, same stem as the report file
|
|
14
|
+
scripts/
|
|
15
|
+
common_data.py # unnumbered: shared code, not an analysis step
|
|
16
|
+
01_description.py
|
|
17
|
+
02_description.py
|
|
18
|
+
figs/
|
|
19
|
+
01_description.png
|
|
20
|
+
01_description_b.png # one script can produce many figures
|
|
21
|
+
02_description.png
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `index.md` is a skimmable document for first-time readers, briefly
|
|
25
|
+
describing what analyses have been done, with links to the reports.
|
|
26
|
+
- A report (`<name>.md`) is the analysis's confirmed write-up -- its
|
|
27
|
+
questions, each with approach/results/figures, and a conclusion.
|
|
28
|
+
- The report file and its folder must share the exact same stem -- that's
|
|
29
|
+
the only thing that pairs them, no manifest or frontmatter needed.
|
|
30
|
+
- `index.md` and the report are only created/updated during
|
|
31
|
+
`/skill:finishing-exploratory-data-analysis`, and not during exploration.
|
|
32
|
+
- No strict 1:1 between scripts, figures, and a report's *Questions* -- number for
|
|
33
|
+
correlation, don't enforce it.
|
|
34
|
+
- Numbered scripts (`NN_description.py`) can't import each other.
|
|
35
|
+
- Shared code (data loading, plotting helpers, constants) goes in an
|
|
36
|
+
unnumbered `common_<topic>.py` and gets imported from there instead --
|
|
37
|
+
never import one numbered script from another.
|
|
38
|
+
|
|
39
|
+
## Common Mistakes
|
|
40
|
+
|
|
41
|
+
| Mistake | Fix |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Naming the report file and its folder with different stems | They must match exactly -- that's the only thing that pairs them |
|
|
44
|
+
| Importing one numbered script from another | Shared code goes in `common_<topic>.py` instead |
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Plotting Preferences
|
|
2
|
+
|
|
3
|
+
Style conventions and the figure-production process for
|
|
4
|
+
`/skill:exploring-data`. Defaults below apply to every plot
|
|
5
|
+
type; subsections add rules for a specific type. If a plot type has no
|
|
6
|
+
subsection yet, follow Defaults and ask if unsure -- don't invent a
|
|
7
|
+
per-type rule that hasn't been stated.
|
|
8
|
+
|
|
9
|
+
## Process
|
|
10
|
+
|
|
11
|
+
- Generate figures with matplotlib, saved as PNG, following the conventions
|
|
12
|
+
below.
|
|
13
|
+
- Apply the user's `eda.mplstyle` at the top of the script
|
|
14
|
+
(`plt.style.use("eda")`) and respect user defaults.
|
|
15
|
+
- Visually inspect every figure with the `read` tool before treating it as a
|
|
16
|
+
result -- never make hypotheses from a figure you haven't looked at.
|
|
17
|
+
- `read` is for your own inspection. When you're ready to show the figure to
|
|
18
|
+
the user (the "Summarize the answer" handoff), use `show` to display it.
|
|
19
|
+
This will render the PNG to the user without spending your tokens
|
|
20
|
+
rereading it.
|
|
21
|
+
- Check specifically for: overlapping/clipped labels, indistinguishable
|
|
22
|
+
traces/series, and rendering artifacts (banding, gaps) that don't reflect
|
|
23
|
+
real structure in the data.
|
|
24
|
+
- Save a table alongside the figure if it's built from a compact aggregate
|
|
25
|
+
(roughly <=20 distinct values) rather than a full-row plot -- cheap at that
|
|
26
|
+
size, and it avoids guessing what the report will cite.
|
|
27
|
+
|
|
28
|
+
## Defaults
|
|
29
|
+
|
|
30
|
+
If the user has not set up `eda.mplstyle` or has not offered opinions
|
|
31
|
+
on plot style, use these defaults:
|
|
32
|
+
|
|
33
|
+
- Colors: `eda.mplstyle` (see the repo-root `eda.mplstyle.example`) defaults to
|
|
34
|
+
`lightsteelblue` for one color and `Blues`
|
|
35
|
+
for a colormap -- pick something else only if needed to convey a point, e.g.
|
|
36
|
+
categorical comparison.
|
|
37
|
+
- Gridlines: none. Spines / ticks: matplotlib defaults -- don't add or strip
|
|
38
|
+
either.
|
|
39
|
+
- Titles: Be brief -- words must earn their space. Detailed descriptions belong
|
|
40
|
+
in report prose, not the title.
|
|
41
|
+
- Axis labels and legends: always present, be terse.
|
|
42
|
+
- Sample size: prefer density/percentage over raw counts unless there's a
|
|
43
|
+
specific reason to show counts.
|
|
44
|
+
|
|
45
|
+
## Bar-shaped Plots (Bar Charts, Histograms)
|
|
46
|
+
|
|
47
|
+
- Aspect ratio: 8:3 (wide).
|
|
48
|
+
- Shaded (filled) bars, not an unfilled outline/step line.
|
|
49
|
+
- **Histograms only**:
|
|
50
|
+
- For continuous variables or integer variables with >= 30 bins,
|
|
51
|
+
suggest KDE smoothing with filled plots. Never start with smoothing;
|
|
52
|
+
instead, show an initial histogram without smoothing and suggest it.
|
|
53
|
+
- For integer variables/PMF plots that are graphed without smoothing,
|
|
54
|
+
ensure the number of bins aligns with the x range. Graph with shaded
|
|
55
|
+
bars only.
|
|
56
|
+
|
|
57
|
+
## Square-aspect Plots (Scatter Plots, 2D Histograms)
|
|
58
|
+
|
|
59
|
+
- Aspect ratio: 1:1 (square).
|
|
60
|
+
- **2D Histograms only** -- include a colorbar sized to the height of
|
|
61
|
+
the histogram for visual clarity.
|
|
62
|
+
|
|
63
|
+
## Common Mistakes
|
|
64
|
+
|
|
65
|
+
| Mistake | Fix |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| Describing what a figure shows without having looked at the PNG | Always `read` the figure before writing anything about what it shows |
|
|
68
|
+
| Summarizing a figure in prose only, without the user seeing it | `show` the PNG to the user as part of the handoff, then summarize |
|
|
69
|
+
| Building a plot from a compact aggregate (<=20 values) with no saved table | Save the underlying table alongside the figure -- cheap at that size |
|
|
70
|
+
| Inventing a per-type styling rule for a plot type with no subsection yet | Follow Defaults and ask -- don't guess a convention that hasn't been stated |
|
|
71
|
+
| Adding a KDE overlay to a discrete-variable histogram | KDE implies continuous density -- shaded bars only, even at cleanup time |
|
|
72
|
+
| Histogram bars show banding or an every-other-bar artifact | Try a different bin width/count, or overlay a KDE to check if the shape is real or a binning artifact |
|
|
73
|
+
| Comparing multiple histograms on one axes with different bin edges per series | Use identical bin edges across all series being compared |
|
|
74
|
+
| A scatter plot has so many overlapping points it's an unreadable blob | Switch to `hist2d`/hexbin (density) or drop alpha significantly, instead of a plain scatter |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Pre-Code Checkpoints
|
|
2
|
+
|
|
3
|
+
What to do for `/skill:exploring-data` before you write any
|
|
4
|
+
code for the next question.
|
|
5
|
+
|
|
6
|
+
## Scope the analysis (once per analysis, before Peek at the data)
|
|
7
|
+
|
|
8
|
+
- Before opening the data, check in one or two sentences what is broadly in
|
|
9
|
+
scope for this analysis and get the user's confirmation. This is a "what
|
|
10
|
+
are we even doing here", separate from and prior to the per-question framing
|
|
11
|
+
below.
|
|
12
|
+
- Ask the user for a report name for this analysis -- it names both the
|
|
13
|
+
report file and its paired folder (see `directory-structure.md`).
|
|
14
|
+
Don't pick one yourself.
|
|
15
|
+
- Keep it broad on purpose -- treat it as provisional, not a lock. Expect
|
|
16
|
+
it to narrow or shift as the data reveals what's actually there, well
|
|
17
|
+
before you reach conclusions -- confirm the new framing with the user
|
|
18
|
+
when it does, same as any other question (see below). `index.md` and
|
|
19
|
+
the report are written together during
|
|
20
|
+
`/skill:finishing-exploratory-data-analysis`, not during exploration.
|
|
21
|
+
|
|
22
|
+
## Peek at the data (once per new dataset, before Propose/ask a question)
|
|
23
|
+
|
|
24
|
+
- Load the dataset (lazily), check schema/dtypes.
|
|
25
|
+
- Get null counts and basic summary stats (mean/median, min/max, std).
|
|
26
|
+
- Get a feel for the actual data: `.head()`, a strided sample, or a random
|
|
27
|
+
sample (fixed seed).
|
|
28
|
+
- Read a few raw rows by eye. They catch what schema/dtype checks and basic
|
|
29
|
+
stats above miss: a "numeric" column that's really a formatted string,
|
|
30
|
+
an ID convention, units, or what a free-text field actually holds.
|
|
31
|
+
- Even raw rows and basic stats can miss duplicate rows.
|
|
32
|
+
- Beyond that, think about what else is cheap to calculate and might
|
|
33
|
+
reveal something missed above -- e.g. sentinel/placeholder values (`-1`,
|
|
34
|
+
`0`, `"unknown"`), class imbalance, or a grain mismatch after a join.
|
|
35
|
+
|
|
36
|
+
## Propose/ask a question (once per question, every time)
|
|
37
|
+
|
|
38
|
+
- Confirm the framing for *this* question/figure with the user before
|
|
39
|
+
writing a script for it.
|
|
40
|
+
- State the new framing in a sentence before scripting it, even if a broad
|
|
41
|
+
go-ahead was already given for the analysis as a whole.
|
|
42
|
+
- This applies to every question, including one you decide to add on your
|
|
43
|
+
own after an earlier go-ahead. Approval for one question is not
|
|
44
|
+
approval for the next one the user hasn't seen proposed yet.
|
|
45
|
+
- **A blanket "keep going" / "I trust your judgment" is not per-question
|
|
46
|
+
approval.** It authorizes you to keep working on framing, not to skip
|
|
47
|
+
asking about the next question's framing. Treat it the same as
|
|
48
|
+
silence: propose the next question's framing in one sentence, then
|
|
49
|
+
build it.
|
|
50
|
+
- Do not build multiple questions in one pass and hand over a "finished
|
|
51
|
+
report" -- stop after each one and surface what it shows before
|
|
52
|
+
moving to the next.
|
|
53
|
+
|
|
54
|
+
## Common Mistakes
|
|
55
|
+
|
|
56
|
+
| Mistake | Fix |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| Opening the data before agreeing on a broad scope | State the analysis's scope/question area in a sentence and confirm before Peek at the data |
|
|
59
|
+
| Picking the report/subfolder name yourself instead of asking | Ask before creating it -- one name, shared by the file and its folder |
|
|
60
|
+
| Treating EDA as a pipeline and auto-advancing through questions without a framing check | Confirm framing per question, not once for the whole analysis |
|
|
61
|
+
| Adding a follow-up figure/question under an earlier blanket go-ahead without confirming its framing | State the new framing in a sentence before scripting it |
|
|
62
|
+
| Building the next two questions back-to-back and presenting a "complete report" because the user said "keep going" / "I trust your judgment" | That phrase covers continued work, not skipped per-question confirmation -- stop after each one |
|
|
63
|
+
| Skipping the raw-row eyeball and stopping at summary stats | Read a few actual rows -- aggregates hide format/unit/encoding surprises |
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Workflow
|
|
2
|
+
|
|
3
|
+
Loop/flow-control for `/skill:exploring-data`.
|
|
4
|
+
|
|
5
|
+
The user drives this loop: they propose or pick the next thing to plot or
|
|
6
|
+
check, you build it and return what it shows. They then interpret it
|
|
7
|
+
and pick next steps or ask additional questions.
|
|
8
|
+
|
|
9
|
+
This is a looped pipeline, exiting only when the user decides to
|
|
10
|
+
lock-in an analysis.
|
|
11
|
+
|
|
12
|
+
```dot
|
|
13
|
+
digraph EDA_WORKFLOW {
|
|
14
|
+
"Start analysis" [shape=doublecircle];
|
|
15
|
+
"Scope the analysis" [shape=box, style=filled, fillcolor=lightblue];
|
|
16
|
+
"Peek at the data" [shape=box, style=filled, fillcolor=lightyellow];
|
|
17
|
+
"Propose/ask a question" [shape=box, style=filled, fillcolor=lightblue];
|
|
18
|
+
"Build script/plot" [shape=box];
|
|
19
|
+
"light or heavy?" [shape=diamond];
|
|
20
|
+
"Reread script" [shape=box];
|
|
21
|
+
"Dispatch script-checker (blocking)" [shape=box];
|
|
22
|
+
"run now, this session" [shape=box];
|
|
23
|
+
"Dispatch job-runner" [shape=box];
|
|
24
|
+
"Summarize the answer" [shape=box, style=filled, fillcolor=lightyellow];
|
|
25
|
+
"Continue analysis or lock in?" [shape=diamond, style=filled, fillcolor=lightblue];
|
|
26
|
+
"/skill:finishing-exploratory-data-analysis" [shape=doublecircle];
|
|
27
|
+
|
|
28
|
+
"Start analysis" -> "Scope the analysis";
|
|
29
|
+
"Scope the analysis" -> "Peek at the data";
|
|
30
|
+
"Peek at the data" -> "Propose/ask a question";
|
|
31
|
+
"Propose/ask a question" -> "Build script/plot";
|
|
32
|
+
"Build script/plot" -> "light or heavy?";
|
|
33
|
+
"light or heavy?" -> "Reread script" [label="light"];
|
|
34
|
+
"Reread script" -> "Build script/plot" [label="issues found"];
|
|
35
|
+
"Reread script" -> "run now, this session" [label="looks right"];
|
|
36
|
+
"light or heavy?" -> "Dispatch script-checker (blocking)" [label="heavy"];
|
|
37
|
+
"Dispatch script-checker (blocking)" -> "Build script/plot" [label="issues found"];
|
|
38
|
+
"Dispatch script-checker (blocking)" -> "Dispatch job-runner" [label="clean"];
|
|
39
|
+
"run now, this session" -> "Summarize the answer";
|
|
40
|
+
"Dispatch job-runner" -> "Summarize the answer";
|
|
41
|
+
"Summarize the answer" -> "Continue analysis or lock in?";
|
|
42
|
+
"Continue analysis or lock in?" -> "Propose/ask a question" [label="next question"];
|
|
43
|
+
"Continue analysis or lock in?" -> "/skill:finishing-exploratory-data-analysis" [label="finish analysis"];
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
(blue = User turn, yellow = Agent -> User handoff, white = Agent-only)
|
|
48
|
+
|
|
49
|
+
| Stage | Turn | What it looks like | See |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| Scope the analysis | User | State the broad scope/question area for this analysis and confirm it, once per analysis, before touching data | `pre-code-checkpoints.md` (Scope the analysis) |
|
|
52
|
+
| Peek at the data | Agent -> User | Schema/dtypes, `.head()`, a sample, eyeball raw rows, hand back for a look | `pre-code-checkpoints.md` (Peek at the data) |
|
|
53
|
+
| Propose/ask a question | User (agent may suggest) | Confirm framing for the next question, then the user picks what to plot or check | `pre-code-checkpoints.md` (Propose/ask a question) |
|
|
54
|
+
| Build script/plot | Agent | Write the script/plot, smoke test on a subset before scaling | `checking-and-running-scripts.md`, `plotting.md` |
|
|
55
|
+
| light or heavy? | Agent | Judge from the smoke-test timing/size ratio | `checking-and-running-scripts.md` |
|
|
56
|
+
| Reread script | Agent | Light: reread the script yourself before running -- no `script-checker` dispatch, loop back to the script on issues you find | `checking-and-running-scripts.md` |
|
|
57
|
+
| Dispatch script-checker (blocking) / Dispatch job-runner | Agent | Heavy: dispatch the `script-checker` and wait; loop back to the script on findings; don't launch the `job-runner` until it's clean | `checking-and-running-scripts.md` |
|
|
58
|
+
| Summarize the answer | Agent -> User | Interpret the figure/stats as a summary, not a conclusion -- the user decides what it means and what's next | `SKILL.md` Core principle |
|
|
59
|
+
| Lock-in checkpoint | User | Figure/analysis seems meaningful, ready to write up or commit | `/skill:finishing-exploratory-data-analysis` |
|
|
60
|
+
|
|
61
|
+
## Common Mistakes
|
|
62
|
+
|
|
63
|
+
| Mistake | Fix |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| Treating any issue in scripts (via self-reread or `script-checker`) as a note to fold in later instead of a loop back to the script | Go to "Build script/plot" and fix it -- see the graph's "issues found" edges |
|
|
66
|
+
| Launching a heavy scale-up while the `script-checker` is still pending or has open findings | See `checking-and-running-scripts.md`'s Common Mistakes |
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: finishing-exploratory-data-analysis
|
|
3
|
+
description: Use when a figure or EDA analysis seems meaningful and ready to summarize, write into a report, or commit
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Related skills:** Use `/skill:exploring-data` for the exploration/plotting phase this follows. Use `/skill:verification-before-completion` before treating any figure as a finished result. Use `/skill:pi-subagents` (`runs.all`, `context: "fresh"`/`"fork"`) for the two dispatches in `verification-dispatch.md`.
|
|
7
|
+
|
|
8
|
+
# Finishing Exploratory Data Analysis
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Locking in a figure/analysis is a sequential, one-at-a-time gate, not a
|
|
13
|
+
batch step at the end of a session.
|
|
14
|
+
|
|
15
|
+
**Core principle:** never write to the report or commit from your own
|
|
16
|
+
read of a figure -- confirm the story with the user first, every time. A
|
|
17
|
+
broader go-ahead, or the user saying "ship it" about the figure itself,
|
|
18
|
+
confirms the figure's story -- not this unrun verification step.
|
|
19
|
+
|
|
20
|
+
Once the report is written or updated, don't skip straight to offering to
|
|
21
|
+
commit -- run the verification dispatch (step 4) first. A completed code
|
|
22
|
+
review doesn't count (see Common Mistakes).
|
|
23
|
+
|
|
24
|
+
## Lock-in Checkpoint (do this once a figure/analysis seems meaningful)
|
|
25
|
+
|
|
26
|
+
1. **Walk through the figures with the user.** `show` each figure and
|
|
27
|
+
re-examine it together to confirm the narrative -- no written artifact
|
|
28
|
+
yet.
|
|
29
|
+
2. **Summarize and wait.** Give the user a ~4 sentence written summary
|
|
30
|
+
of the agreed narrative. Wait for confirmation before proceeding.
|
|
31
|
+
3. **Write the report and `index.md`.** Once confirmed, add or update
|
|
32
|
+
the `index.md` and report (`<report_name>.md`, sibling to its paired
|
|
33
|
+
`<report_name>/` scripts/figs folder). Create them here if necessary.
|
|
34
|
+
- Writing style: clear sentences. No run-ons, reduce em/en-dash
|
|
35
|
+
(`--`/`—`) as a sentence joiner. Split into two sentences or use a
|
|
36
|
+
comma/colon instead.
|
|
37
|
+
- `index.md` contents -- a brief description (no figures) containing:
|
|
38
|
+
- *Link to report*
|
|
39
|
+
- *Brief summary*
|
|
40
|
+
- *Scope of analysis*
|
|
41
|
+
- *Dataset description*
|
|
42
|
+
- *Open questions*, if any
|
|
43
|
+
- Report contents -- at minimum:
|
|
44
|
+
- *Scope of analysis*
|
|
45
|
+
- *Data source(s) used*
|
|
46
|
+
- *Questions*, grouped when closely related:
|
|
47
|
+
- *Approach* in prose, with key equations if nontrivial
|
|
48
|
+
- *Results*, with the embedded figure(s)
|
|
49
|
+
- *Conclusion*
|
|
50
|
+
4. **Reread, then dispatch verification.** See `verification-dispatch.md`
|
|
51
|
+
for the reread pass, the `naive-reader`/`critical-auditor` dispatch, and
|
|
52
|
+
the severity rubric for findings.
|
|
53
|
+
5. **Integrate findings and modify the report.** Apply silent fixes per
|
|
54
|
+
the rubric; surface material-tier and `critical-auditor` findings
|
|
55
|
+
verbatim, flagged unresolved if not yet addressed. If the fix is
|
|
56
|
+
substantive, ask the user whether to rerun verification.
|
|
57
|
+
6. **Ask before committing.** Explicitly ask if the user is ready to
|
|
58
|
+
commit -- don't commit on your own judgment.
|
|
59
|
+
|
|
60
|
+
## Common Mistakes
|
|
61
|
+
|
|
62
|
+
| Mistake | Fix |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| Writing to the report from your own interpretation of a figure | Confirm with a ~4 sentence summary first |
|
|
65
|
+
| Putting figures/results into `index.md` | Keep it a skimmable summary of what's been done -- figures and results belong in the report files |
|
|
66
|
+
| Dispatching verification before the report is written | Verification checks the written report against the figures/script -- write first (step 3), then dispatch (step 4) |
|
|
67
|
+
| Stating a correlation as if it were causal | Hedge appropriately in report prose; correlation is not causation |
|
|
68
|
+
| Silently patching a material-tier or `critical-auditor` finding before telling the user | Always surface these verbatim in the summary, even unresolved -- only cosmetic/confusing/non-fabricated-clarifying fixes get silently applied |
|
|
69
|
+
| Treating a completed script/code review as satisfying this checkpoint's dispatch | Different gate, different artifact -- a code review checks the script, this checkpoint checks the written report. See `verification-dispatch.md` |
|
|
70
|
+
| Saying an analysis is "done and reviewed" once code review passes, before the lock-in checkpoint has run | Say so explicitly ("script validated; report still needs the lock-in checkpoint") rather than a blanket "done" that could be read as covering sign-off too |
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Verification Dispatch
|
|
2
|
+
|
|
3
|
+
The critical checkpoint in `/skill:finishing-exploratory-data-analysis`:
|
|
4
|
+
reread the report/script, then dispatch subagents to check it, before
|
|
5
|
+
you offer to commit. Together the two dispatches establish trust in
|
|
6
|
+
the report: that it's clear and complete as a standalone artifact
|
|
7
|
+
(`naive-reader`), and that it was produced with the correct semantic
|
|
8
|
+
intent (`critical-auditor`). See each agent's own definition in this
|
|
9
|
+
package's `agents/` directory (`naive-reader.md`, `critical-auditor.md`)
|
|
10
|
+
for what they check and how they're configured (context, tools).
|
|
11
|
+
|
|
12
|
+
1. **Reread first.** Reread the report/script yourself for leftover
|
|
13
|
+
editing artifacts (draft asides, TODO notes, contradictions) before
|
|
14
|
+
dispatching -- don't hand reviewers an unread draft.
|
|
15
|
+
2. **Dispatch both in parallel** (`runs.all`), every lock-in, not just
|
|
16
|
+
risky ones:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
runs.all([
|
|
20
|
+
{key:"naive", agent:"naive-reader", task:"<report, figures, index.md>"},
|
|
21
|
+
{key:"audit", agent:"critical-auditor", task:"<report, figures, numbered scripts>"},
|
|
22
|
+
])
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If fork context isn't available for `critical-auditor`, hand it a
|
|
26
|
+
written recap of this session's framing/decisions in the task instead
|
|
27
|
+
-- context-free it's just a second `naive-reader`.
|
|
28
|
+
|
|
29
|
+
## Handling `naive-reader` findings by tier
|
|
30
|
+
|
|
31
|
+
| Tier | Handling |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| cosmetic | fix silently, one-line changelog note |
|
|
34
|
+
| confusing | fix silently (simplify/rewrite), one-line changelog note |
|
|
35
|
+
| clarifying | fix silently if you actually know the answer. If closing the gap means guessing or inventing a reason, don't fabricate it -- tell the user honestly instead |
|
|
36
|
+
| material | always surface, never silently patched -- this is a correctness signal wearing a comprehension-test disguise |
|
|
37
|
+
|
|
38
|
+
## Handling `critical-auditor` findings
|
|
39
|
+
|
|
40
|
+
Findings have no tiers: everything it reports is drift between intent
|
|
41
|
+
and implementation, never silently resolved -- goes into the
|
|
42
|
+
user-facing summary verbatim.
|
|
43
|
+
|
|
44
|
+
## Common Mistakes
|
|
45
|
+
|
|
46
|
+
| Mistake | Fix |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| Skipping the `naive-reader`/`critical-auditor` dispatch because it "seems fine" | Every lock-in, no exceptions -- this is the final check before commit, and "seems fine" is exactly the curse-of-knowledge blind spot it exists to catch |
|
|
49
|
+
| Inventing a plausible-sounding rationale to resolve a clarifying-tier gap you don't actually know the answer to | Surface it as an open question instead -- never fabricate reasoning to make a flag disappear |
|
|
50
|
+
| Letting the `critical-auditor` run with no conversation context because fork wasn't available | Hand it an explicit written recap of the framing/decisions instead -- context-free, it's just a second `naive-reader` and can't catch intent drift |
|
|
51
|
+
| Treating a completed script/code review as satisfying this dispatch | Different gate, different artifact -- a code review checks the script; this dispatch checks the written report |
|