SuperAPI AI Directory

ds

Data & analytics

View repository

Updated 10-15 21:37

About this skill

ds — a data project, run through work with a computed data-quality gate

What this skill carries — grep references/ for any subject the names below miss: !d=${CLAUDE_SKILL_DIR}; command -v skill-toc >/dev/null 2>&1 && exec skill-toc "$d"; s=$HOME/.claude/skills/plugin-utils/bin/skill-toc; [ -x "$s" ] && exec "$s" "$d"; echo "(skill-toc unavailable: references and scripts are NOT listed here — install the plugin-utils plugin, or start a new session so its bin/ reaches PATH)"

DS constraints in force — every rule scoped to this workflow, discovered from the corpus so a new one needs no edit here; read the ones your task touches: !c=${CLAUDE_PLUGIN_ROOT}/scripts/load-constraints; [ -x "$c" ] && exec "$c" ds; echo "(constraint index unavailable: NO DS rule is listed here — the four named below are not the whole set)"

The lifecycle is work. Read it and follow it. This file is a delta: it supplies the domain — the CLARIFY axes, the plan grammar, the lens, the mechanical checks, the refs, the authority text. It ships no workflow.js and restates none of work's mechanics.

What makes a run ds rather than plain work is one thing: every declared data output is verified by a computed runner, not by the agent that produced it. scripts/ds-dq.py reads the approved plan's ## Data Outputs table and opens each artifact itself; work's JS reads its exit code.

Write surface

Main chat clarifies, plans and dispatches. It does not do the analysis, and it never writes a .py, .ipynb, .R, .sas, .sql or .qmd file — not by Write/Edit, and not by Bash (python3 -c, pixi run python, inline pandas/numpy). Analysis runs in a dispatched agent. work's dispatch is already structural and its judges are pinned to Explore, so this line is a rule on you, not a hook; reach for the workflow first rather than after a refusal.

Phase 1 — CLARIFY

work's Phase 1, on these axes.

Loading a dataset or proposing a method before the user has stated the outcome anchors the work to whatever data happens to be nearby. Skipping a necessary profile replaces evidence with a convenient guess. Neither shortcut is helpful: it creates an analysis that is fast to start and expensive to correct.

Axis Establish with the user
Outcome Question, audience, decision the analysis informs, and deliverables
Universe Unit of observation, entity inclusion rule, sample period, and authoritative source when sources disagree
Sources Available data, access/location, expected refresh/vintage, and known restrictions
Constraints Replication target, required methods, deadline, compute/cost limits, and reproducibility needs
Evidence What makes each planned output credible: a check, an inspectable exhibit, a source comparison, or user judgment

Ask in one AskUserQuestion call when answers are independent. Ask cascading questions separately: a source choice that determines available variables must be answered before variable questions.

Three facts decide these axes, and each prevents a defect that is expensive to find later:

  • A sample period and an entity universe are research choices, not properties inferred from the first query result. A rate at the wrong grain is a different statistic with a familiar label.
  • The universe predicate belongs where scope is decided. Applying it to a lookup or a denominator can turn available values into nulls; a 43.7% null-denominator incident came from exactly that duplicate filtering mistake.
  • A criterion that cannot name evidence is a wish. The explicit TBD (<phase>) convention is legitimate only when profiling is the scheduled evidence-producing phase; never invent coverage.

work's remaining axes are taken as work states them, with two domain bindings: work axis 4 (observable success criteria) is answered with the DQ runner over the plan's ## Data Outputs plus the target project's own test and lint commands when the project has them, and those strings become mechanicalChecks verbatim; work axis 5 (review surface) is answered by the plan's ## Review Surfaces section. The ds-dq entry is never conditional. The tests and lint entries are omitted entirely when the project has no such command — work's probe runs a cmd verbatim, so an unsubstituted <the project's lint command> placeholder blocks the gate on a placeholder instead of on data quality.

Then gather planning evidence — a read-only profile, never implementation. For each source that materially affects the plan, collect or dispatch a profile covering: location/access, approximate shape, columns/types, date coverage, and likely row grain/key; nulls, duplicates, type drift, category/distribution anomalies, and likely join risks; raw size and whether source-side filtering, caching, partitioning, or server-side computation is needed; and a small representative sample only when access and project policy permit it. Use direct read-only inspection for one small local source; for independent sources, dispatch read-only profilers in parallel and consolidate. Do not make a profiling agent implement a pipeline, mutate project files, or spawn further agents. Do not pull a full source merely to estimate it. If an answer depends on implementation, state it as a planned evidence task rather than pretending the profile established it.

Four discovery rules run in this same planning step, each governed by its own constraint file:

  • Large sources. If a source may be large (roughly 50M rows, 500 MB to ship, or described as bulk/large/uncertain), read ${CLAUDE_PLUGIN_ROOT}/rules/ds-pull-sizing-decision.md and follow it. The profile must compare filtered raw and candidate aggregate/server-side paths before planning commits to one. Do not pull a full source merely to estimate it.
  • External-skill discovery. When the plan will use another skill or data provider, discover its relevant references and examples before choosing an approach: read ${CLAUDE_PLUGIN_ROOT}/rules/ds-external-skill-decision.md and follow it. Record the resulting ADOPT, PATCH, or GREENFIELD decision in the plan itself.
  • Master datasets. For multi-output work that shares a sample, read ${CLAUDE_PLUGIN_ROOT}/rules/ds-master-datasets.md. Plan the minimal canonical analysis dataset(s), their grain and keys, and which planned outputs consume each one.
  • Parameter transparency. For analytic filters or tunable thresholds, read ${CLAUDE_PLUGIN_ROOT}/rules/ds-parameter-transparency.md; name one configuration location, rationale, and treatment of convenience choices in the plan.

Phase 2 — PLAN

work's Phase 2. The plan opens with frontmatter workflow: ds — required, so a context clear at approval resumes here and not in work.

Five domain requirements on the plan:

  • The source/access strategy and the profile-derived risks. The plan states how each source is reached, and the data-quality and scale risks the read-only profile actually surfaced. A risk found at CLARIFY that reaches no plan section is a risk nothing acts on.

  • Reproducibility decisions, appropriate to the work: source vintages, seeds, environments and config. R1 (fresh re-run reproducibility) is judged by the review lens's data-quality item, so a plan recording none of these leaves R1 with nothing to judge against.

  • A ## Data Outputs table, in exactly this grammar, because scripts/ds-dq.py parses it and an output absent from it is one nothing will check:

    ## Data Outputs
    
    | Path | Grain | Key Columns | Required Window |
    |---|---|---|---|
    | data/processed/panel.parquet | one row per firm-fiscal-year | pk: gvkey, fyear; event: gvkey, datadate | datadate: 2005-01-01..2025-12-31 |
    | data/processed/industry_xwalk.csv | one row per SIC code | sic | n/a |
    
    • Path — the produced artifact, relative to the project root. .parquet, .csv, or .tsv; one row per artifact the plan promises to produce.
    • Grain — the declared row grain, in words. This is the claim DQ3 verifies rather than assumes.
    • Key Columns — the declared primary key DQ3a tests for uniqueness. Write a, b for a bare primary key, or pk: a, b; event: c, d to also declare the coarser business/event key DQ3c needs to catch amendments and restatements. Without an event: clause DQ3c reports N/A, and the runner says why.
    • Required Window — the sample period COV checks, as [column: ]YYYY-MM-DD..YYYY-MM-DD. Write n/a for an unwindowed output; COV then reports N/A with that as its reason. Naming the column is optional only when exactly one date column exists; an ambiguous window is a FAIL, not a pass.
  • A ## Review Surfaces section naming the concrete tables, figures, notebook exports, diagnostics, or decisions the user will inspect during human review.

  • refs on every task row and on the lens — required, may be empty. work's spine does not validate it; wc-probe P7 refuses an absent key in THIS file, so a live run assembled from an approved plan is unchecked. Write refs: [] to state "no domain rules" rather than omitting the key.

  • Batch extraction strategy. A task whose work is per-document LLM coding or extraction is a task that LAUNCHES a gemini-batch job on pre-cut excerpts (with a 1-request synchronous test first). It is never an agent reading the documents.

Phase 3 — GOAL

work's Phase 3 unchanged.

Phase 4 — the work call

The args go in the plan's <!-- work:dispatch --> arming block, and the dispatch is work's own work-dispatch.sh — never a hand-written runner line. That script owns the TIER 1 plan-lint gate, which refuses to dispatch on a major/critical plan finding and fails CLOSED on a verdict it cannot count; hand-rolling the invocation silently drops it. work owns the wait, the result handling and the return shape too, and work-result.sh reads the verdict. This run's projectDir is the session repo, so work's own run directory is already inside it and no --run-dir override applies. There is no built-in Workflow call — the guard at ~/.claude/hooks/main-thread-guard.sh denies that tool outright.

bash ${CLAUDE_PLUGIN_ROOT}/skills/work/scripts/work-dispatch.sh   # armed plan; or pass one
bash ${CLAUDE_PLUGIN_ROOT}/skills/work/scripts/work-dispatch.sh --provider codex   # "run this through codex"

Forward the provider. A provider named in this skill's $ARGUMENTS, however it is spelled — --provider codex, --dispatch codex, "run this on gpt" — is --provider codex on the line above. --provider is the only spelling the scripts take, and both reject the others by name. Omitting it silently runs the user's codex request on claude.

{
  projectDir,
  goal: "<one sentence>",

  // The plan's table verbatim. Every task carries refs, empty or not. The four constraint
  // aggregates are UNCONDITIONAL — every implementation task carries all four, alongside
  // whichever vendored references that task's own work needs.
  tasks: [
    { id: "T1",
      name: "<data pull or pipeline task>",
      work: "<what to build>",
      writablePaths: ["<narrow>"],
      acceptance: "<the criterion the verifier checks>",
      refs: ["${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-conventions.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-analysis-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-engineering-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/references/etl-enforcement.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/references/sql-patterns.md"] },

    { id: "T2",
      name: "<task whose acceptance is evidentiary>",
      work: "<what to build>",
      writablePaths: ["<narrow>"],
      acceptance: "<the criterion the verifier checks>",
      refs: ["${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-conventions.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-analysis-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-engineering-constraints.md",
             "${CLAUDE_PLUGIN_ROOT}/skills/ds/references/verification-patterns.md"] },
  ],

  // The DS gate: the runner reads the approved plan's ## Data Outputs and opens each artifact
  // itself. ds-dq is never conditional. tests and lint are the TARGET project's own commands,
  // collected at CLARIFY, and are included ONLY when the project has them — a probe runs cmd
  // verbatim, so an unsubstituted placeholder blocks the gate on a placeholder. Omit the entry.
  // ONE entry point. These were three entries until 2026-09-15; a list of N independent
  // commands loses one silently. The project's own test and lint commands are ARGUMENTS
  // because this skill cannot know them — omit a flag and that leg reports "not declared",
  // which is visible, where a dropped entry is not.
  mechanicalChecks: [
    { name: "ds",
      cmd: "bash ${CLAUDE_PLUGIN_ROOT}/skills/ds/scripts/check.sh --plan <planPath> --project-dir <projectDir> [--test-cmd \"<the project's test command>\"] [--lint-cmd \"<the project's lint command>\"]" },
  ],
  // work-checks.sh runs it as a command (no agent); Jev scores the wired DS rules (A1, A4, DEN, DQ4, DQ6, E7, M1, R1, UNI; DQ1 waits in constraints/jev/uncalibrated/ and ds-dq.py decides it); a rule with p >= 0.85 lands in rulesThatFailed and blocks, lower ones reach the lens as a ranked checklist.
  ruleChecks: { name: "jev-rules", cmd: "bun ${CLAUDE_PLUGIN_ROOT}/skills/work/scripts/rule-check.ts --project-dir <projectDir> --plan <planPath>" },

  // One lens after verification and mechanical checks; its checklist covers all five dimensions.
  //
  // It does NOT pin Explore. Explore is a built-in agent with a PREDEFINED prompt that no preloaded
  // skill reaches, and it skips the CLAUDE.md hierarchy — so a constraint-indexed judgement
  // dispatched there is graded from memory of constraint ids it was never given. ds-reviewer's body
  // is a file this repo controls, and it is read-only by tools allowlist AND by
  // tests/agent-contract.test.mjs — the same structural property Explore is pinned for, in an agent
  // whose prompt can be told what it is grading. The four aggregates are not vendored into any
  // skill: they reach the lens as refs, from their one canonical home.
  lens: {
    agentType: "ds-reviewer",
    refs: ["${CLAUDE_PLUGIN_ROOT}/skills/ds/references/ds-checks.md",
           "${CLAUDE_PLUGIN_ROOT}/skills/ds/references/verification-patterns.md",
           "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-constraints.md",
           "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-common-conventions.md",
           "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-analysis-constraints.md",
           "${CLAUDE_PLUGIN_ROOT}/skills/ds/rules/ds-engineering-constraints.md"],
    prompt: "Judge the datasets, tables and figures in the working tree against the approved plan and the goal. Read every file in refs in full before judging the items that name one. CHECKLIST, every item in scope on every run: (1) CRITERIA vs ARTIFACTS — for each success criterion in the plan and goal, is there an artifact in the tree that satisfies it? Missing or partial satisfaction is a finding, CRITICAL where the deliverable cannot stand without it. (2) SCOPE fidelity — did the changes stay inside the plan's task table and writable paths? Out-of-scope edits, unrequested features and silently skipped plan items are findings, CRITICAL where an edit landed outside every declared writable path. (3) DATA-QUALITY JUDGEMENT, against ds-checks.md. A1, A4, DEN, DQ4, DQ6, E7, M1, R1 and UNI are the jev-rules verdicts in the digest: do not re-grade them, except to rule on a verdict the digest ranks below the block line. A rule in rulesThatFailed is not re-judged either: diagnose it and route it like a mechanical failure. Jev does not score DQ1 or DEL; ds-dq.py decides DQ1. DEL (coverage improved because the base shrank) is yours and MODEL-EVALUATED: report it with the evidence you actually read, never as PASS, which presents a judgement as a computation, and a coverage improvement not attributable to the base shrinking is a finding. Two judgements reach past the wired rule texts and stay yours, stated as broader than any verdict in the digest: whether the sources the outputs combine admit the same entities, which one shared filter predicate does not establish, and whether the vintages, environment and config the plan records would let a fresh re-run reproduce the result, which seeded draws alone do not. Plan criterion compliance is item (1). A judgement you cannot support with evidence you actually read is a finding, never a pass. (4) METHODOLOGY, against verification-patterns.md: a statistic computed at a grain other than the one the plan declared, a universe predicate applied where scope was not meant to be decided, a claim whose evidence is read from code rather than observed from a run, and an output the plan promised that nothing checks. (5) DS-CONSTRAINTS — grade the implemented code and outputs against the indexed constraints in the four aggregates, C1-C6, V1-V9, A1-A6, E1-E7. Grade only the constraints the task actually touches; an engineering constraint applied to a pure analysis task is a wrong finding that costs a round. Report every constraint finding with the file, the line and the quoted code, naming the constraint id, and list every id you considered including those you judged satisfied. NEVER report a constraint judgement as a computation — it is MODEL-EVALUATED. Severity across the whole checklist: `major` at minimum, `critical` where the defect invalidates the output's stated grain, universe or inference, never `minor`, which would leave the gate passing over a real universe defect. MODE — RED (a task was flagged or a mechanical check failed): diagnose EVERY failure in the digest and route it, naming cause and fix, to the task id whose writablePaths own the file, or to 'plan' when no task can own the fix. MODE — GREEN (everything passed): make one open-ended pass over the whole checklist and report each finding with an ownerTask. In both modes, rule every carried finding open or closed against evidence you actually read; silence leaves it open.",
  },

  authorityExtra: [
    "THE DS CONSTRAINT CORPUS IS ONE COMMAND AWAY. Run `${CLAUDE_PLUGIN_ROOT}/scripts/load-constraints ds` for the index — every rule scoped to this workflow, with an openable path — then read the ones your task touches. Do not work from a paraphrase of them in a brief: a paraphrase is a lossy copy of a corpus that moves.",
    "IRON LAW OF DS PLANNING — ask before you look; plan only from evidence you actually gathered.",
    "IRON LAW OF DS VERIFICATION — no check result without the runner's own output. A mechanical check reported from reading the code, or an N/A justified by a reason the model composed, is the model certifying its own enumeration. Every mechanical result is a line ${CLAUDE_PLUGIN_ROOT}/skills/ds/scripts/ds-dq.py emitted, quoted as emitted.",
    "Never report M1, UNI, DEN, DEL or R1 as PASS. The runner lists them as MODEL-EVALUATED; Jev scores M1, UNI, DEN and R1, and DEL is a judgement reported with the evidence read.",
    "DQ4 and DQ6 are `always N/A` from the runner, and `always N/A` is not a third kind of pass — the runner emits a line for them only because ENUM requires one, and an N/A never sets its non-zero exit. Jev's DQ4 and DQ6 verdicts score them against the input → transform → output count chain and the before/after shape. Never read their N/A as `the runner checked this`.",
    "An artifact absent from the plan's ## Data Outputs table is one nothing will check and cannot be claimed as verified. Do not verify an output the table never declared.",
    "The analysis is done by dispatched agents. Main chat writes no .py, .ipynb, .R, .sas, .sql or .qmd file, by any tool.",
    "Standing DS doer authority — every implementation task follows the indexed constraints in the four aggregates under ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/: ds-common-constraints.md (C1-C6), ds-common-conventions.md (V1-V9 — assumption-over-evidence, deferred verification, statistical validity, P-hacking prevention, sample-selection documentation), ds-analysis-constraints.md (A1-A6 — robustness checks, standard-error specification, visualization integrity, table-figure pairing, chart typography, chart colour) and ds-engineering-constraints.md (E1-E7 — determinism and seeds, schema contracts, join audits with row counts and match rates, idempotency, loud error handling, native document input, network politeness), each indexing the self-contained files under ${CLAUDE_PLUGIN_ROOT}/constraints/. All four are named in every implementation task's refs, and refs are contractual reads, not a reading list: read all four in full before writing code. ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/ds-checks.md stays a separate load.",
    "Rules: ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/ds-checks.md defines all thirteen checks; ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/etl-enforcement.md governs pipelines; ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/sql-patterns.md governs data pulls; ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/verification-patterns.md governs evidence; ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/competing-hypothesis.md governs debugging.",
  ].join("\n"),

  implementerAgentType: "ds",   // the doer's own prompt replaces Claude Code's software-engineering one, which frames a dataset as a codebase
  verifierAgentType: "Explore",
}

implementerAgentType names ds because the default agent carries Claude Code's software-engineering system prompt, and the deliverable here is a dataset, a table and a figure a human reads — not a codebase. An agent is justified only by a custom prompt, hooks or preloaded skills; ds earns it on the first alone — the constraint aggregates reach it as task refs, not as a preloaded skill.

verifierAgentType pins Explore because it has no Edit and no Write: a judge that structurally cannot modify the tree beats a prompt asking it not to. The lens buys the same property a different way — ds-reviewer is read-only by tools allowlist — because Explore's prompt is predefined and no preloaded skill or CLAUDE.md reaches it; the lens carries the four aggregates in its own refs.

Add ${CLAUDE_PLUGIN_ROOT}/skills/ds/references/competing-hypothesis.md to a task's refs when that task is a diagnosis rather than a build. authorityExtra names it; refs is what makes an implementer read it in full.

The runner's own contract suite lives at ${CLAUDE_PLUGIN_ROOT}/skills/ds/scripts/ds_dq_test.py; add it as a mechanicalChecks entry on any run that touches the runner.

Phase 5 — HUMAN REVIEW

work's Phase 5 unchanged, over the plan's ## Review Surfaces. A clean technical verification is evidence for that conversation, not human acceptance.

Red flags

Situation Wrong move Right move
Sizing a source pull the whole thing to see how big it is the transfer is the failure you are meant to prevent — profile filtered counts and aggregate candidates read-only
Profiling a source treat a head sample as the profile nulls, grain failures and type drift live outside the head — profile shape, tail/coverage, keys and quality signals
Naming a produced artifact name it in prose a runner given prose cannot open it, key it, or window it — add its row to ## Data Outputs before approval
The DQ result let the implementer report it the doer cannot see the assumption it made in both places — the runner is a mechanicalCheck and the JS reads its exit code
M1/UNI/DEN/DEL/R1 report them as PASS that presents a judgement as a computation — Jev's verdicts decide M1, UNI, DEN and R1; DEL is MODEL-EVALUATED with the evidence read
DQ4/DQ6 reported N/A read the N/A as the runner having checked them always N/A is not a third kind of pass — the runner computes neither and an N/A never sets its non-zero exit; Jev's DQ4 and DQ6 verdicts decide them
Per-document LLM coding or extraction fan out agents to read each document launch a gemini-batch job on pre-cut excerpts (with a 1-request synchronous test first)
A judgement that depends on the constraint index dispatch a built-in agent (Explore, Plan, general-purpose) their prompts are predefined, no preloaded skill reaches them and they skip the CLAUDE.md hierarchy, so the constraints are graded from memory — dispatch a custom agent whose body you control, like ds-reviewer
Handing a doer the constraint aggregates name the four paths in the task prompt's prose, or copy the aggregates into a skill prose is discretionary and a copy is a second source of truth tests/constraints-no-duplication.test.ts fails on — put the four canonical paths in the task's refs, which work defines as reads the doer owes in full
Project state write a SPEC.md, STATE.md or LEARNINGS.md competing state makes progress ambiguous — the approved plan is the authority and work hashes it
Something work does not obviously do write a ds/workflow.js ask which work parameter is missing — mechanicalChecks is what makes the DQ runner the gate