agentsclimarketplace

Kaggle

Skill Borda/AI-Rig/plugins/cc_research/skills/kaggle

Generate a Kaggle competition notebook as a Jupytext `# %%` Python script following the user's established ML research style: PTL for DNN training, best-fit tool selection, EDA→Baseline→Train→Inference pipeline with per-stage lens cells, small single-purpose cells each carrying a why. Tuned to win (leakage-safe CV, metric-aligned modeling) as much as to teach. Writes output to .experiments/kaggle/<name>.py.From its SKILL.md

Install
npx -y skills add Borda/AI-Rig --skill kaggle

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

2 things to look at

  • 24 stars24 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.
  • runs commandsInstructs the agent to run 6 commands, including `ls -td ~/.claude/plugins/cache/borda-ai-rig/foundry/*/agents/sw-engineer.md 2>/dev/null | head -1` and 5 more.

SKILL.md

19.2 KB, ~5.0k tokens by cl100k_base, as published. Nobody here has run it

<objective>

Generate Kaggle competition notebook script, Jupytext # %% format.

Two goals, equal weight — neither traded for other:

  • Win — leaderboard-competitive: leakage-safe CV, metric-aligned loss/model choice, tuning/ensembling when it moves the score, not style theater
  • Teach — read top to bottom like a university/seminar lecture on solving this competition: reader new to it follows the full reasoning chain, every decision motivated, nothing left as unexplained code

Follows user's ML research style distilled from past notebooks:

  • PTL always for DNN training (PyTorch Lightning + torchmetrics) — even simple baselines
  • Tool agnostic — best-fit library for problem; PTL when training loop needed
  • Stages with lenses — each major stage: quick sanity check cell (show one batch, print shapes, verify submission format)
  • Small, single-purpose cells — one action per cell (load, one transform, one plot, one check); never bundle setup + run + verify to save cell count
  • Every cell earns its place — one-line why (comment or markdown sentence) before/in each cell: the specific reason this step happens now — never a restatement of what the code does
  • Section markdown is extensive and structured — full explanation of what/why/how-it-advances-the-goal per section, formatted as tables/lists/blockquotes over dense prose paragraphs; markdown before a plot sets up the question, markdown after states the finding and its implication — plot and prose flow as one beat, never an orphaned chart
  • # ! bash over subprocess — package installs, nvidia-smi, ls -lh, # ! head submission.csv
  • EDA is visual — distribution plots, sample grids, dimension scatters before any model
  • Inference included — model save pattern + separate load-and-infer cells
  • CSVLogger + seaborn — metrics plotted from metrics.csv after every training run

NOT for writing Python packages, modules, production code — notebook scripts only. NOT research literature survey — use /research:topic for SOTA literature search.

</objective> <inputs>
  • $ARGUMENTS: one of:
    • <competition-name> — short slug for output filename; generates blank template
    • <competition-name> <url> — fetches competition overview from URL before generating
    • <competition-name> "<description>" — inline description of problem and data
    • --type <type> — hint: classification, regression, segmentation, detection, tabular (auto-detected when omitted)
    • --eda-only — generate only EDA sections (no model/training/submission); always online (no offline setup)
    • --inference-only — generate inference notebook from checkpoint (no EDA, no training); always offline (frozen packages pattern); loads checkpoint from PATH_CHECKPOINT constant; output suffix -inference.py
    • --offline-setup — include offline package setup (frozen_packages pattern) in setup cell; auto-applied when --inference-only; ignored when --eda-only (EDA always online)
    • --resume <path> — read existing .py script, extend/improve it

Output: .experiments/kaggle/<competition-name>.py

</inputs> <constants>
OUTPUT_DIR:    .experiments/kaggle/
CELL_MARK:     "# %%"
MD_CELL_MARK:  "# %% [markdown]"
# NOTE: documentation-only — not referenced as shell vars across separate Bash() calls (state doesn't persist); keep values in sync with literal use sites (Steps 1, 3, 4).
</constants> <compaction>

Key boundary: end of Step 3 — notebook script generated by foundry:sw-engineer, written to OUTFILE. Preserve: OUTFILE path (derived from TMPDIR keys), COMPETITION_NAME (TMPDIR key), mode flags (EDA_ONLY, INFERENCE_ONLY, OFFLINE_SETUP). Clear at Step 1 start (stale prior run) and after Step 4 package-distillation gate resolves.

</compaction> <workflow>

Task hygiene: call TaskList first; close orphaned tasks. Create tasks per phase.

Step 1: Parse arguments and gather context

# loads: compaction-contract.md
export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}"
ARGS="$ARGUMENTS"
COMPETITION_NAME=$(echo "$ARGS" | awk '{print $1}')
RESUME_FLAG=""
EDA_ONLY=false
INFERENCE_ONLY=false
OFFLINE_SETUP=false
PROBLEM_TYPE=""

[[ "$ARGS" == *"--eda-only"* ]]      && EDA_ONLY=true
[[ "$ARGS" == *"--inference-only"* ]] && INFERENCE_ONLY=true
[[ "$ARGS" == *"--offline-setup"* ]]  && OFFLINE_SETUP=true
[[ "$ARGS" =~ --type[[:space:]]([a-z]+) ]] && PROBLEM_TYPE="${BASH_REMATCH[1]}"
[[ "$ARGS" =~ --resume[[:space:]]([^[:space:]]+) ]] && RESUME_FLAG="${BASH_REMATCH[1]}"

# inference always offline; EDA always online (overrides --offline-setup)
[ "$INFERENCE_ONLY" = "true" ] && OFFLINE_SETUP=true
[ "$EDA_ONLY" = "true" ]       && OFFLINE_SETUP=false

echo "Competition: $COMPETITION_NAME"
echo "Type: ${PROBLEM_TYPE:-auto-detect}"
echo "EDA only: $EDA_ONLY | Inference only: $INFERENCE_ONLY | Offline setup: $OFFLINE_SETUP"

# Persist for Steps 3+4 (bash state lost across Bash() calls)
echo "$COMPETITION_NAME" > "${TMPDIR:-/tmp}/kaggle-competition-name-${CSID}"
echo "$EDA_ONLY"         > "${TMPDIR:-/tmp}/kaggle-eda-only-${CSID}"
echo "$INFERENCE_ONLY"   > "${TMPDIR:-/tmp}/kaggle-inference-only-${CSID}"
echo "$OFFLINE_SETUP"    > "${TMPDIR:-/tmp}/kaggle-offline-setup-${CSID}"

mkdir -p .experiments/kaggle/  # timeout: 3000
KEEP_ITEMS=""
if [[ "$ARGS" =~ --keep[[:space:]]\"([^\"]+)\" ]]; then
    KEEP_ITEMS="${BASH_REMATCH[1]}"
fi
# Clear stale contract from any prior incomplete run (compaction-contract.md §Lifecycle)
rm -f .temp/state/skill-contract.md  # timeout: 5000
echo "${KEEP_ITEMS:-}" > "${TMPDIR:-/tmp}/kaggle-keep-items-${CSID}"  # persist for Step 3 contract write

Flag mutual-exclusion check — if EDA_ONLY and INFERENCE_ONLY are both true (both --eda-only and --inference-only passed): print ! Conflicting flags: `--eda-only` and `--inference-only` are mutually exclusive (`--eda-only` is always-online with no training; `--inference-only` is always-offline/frozen-package with no EDA — see `foundation.md`). Pick one. then invoke AskUserQuestion — (a) Abort · (b) Continue ignoring both (falls back to full mode: neither eda-only nor inference-only applied). On Abort: stop.

Unsupported flag check — scan $ARGUMENTS for remaining --<token> tokens after supported flags extracted (--eda-only, --inference-only, --offline-setup, --type, --resume, --keep). Found: print ! Unknown flag(s): `--<token>`. Supported: `--eda-only`, `--inference-only`, `--offline-setup`, `--type <type>`, `--resume <path>`, `--keep "<items>"`. then invoke AskUserQuestion — (a) Abort · (b) Continue ignoring. On Abort: stop.

Context collection — run in parallel:

  1. URL provided in args: WebFetch competition page; extract problem description, target metric, data format, evaluation — read and quote actual text, never paraphrase from training knowledge
  2. --resume: read existing script (Read tool)
  3. Scan .experiments/kaggle/ (Glob pattern *.py) for prior scripts; read first 30 lines of each — find similar past competitions, use as structural reference
  4. Check resources/competitors/ for .ipynb/.py files — found: read each, summarise approach (model choice, preprocessing, feature engineering, augmentation). Use findings to inform detection method and domain-specific preprocessing decisions in Step 2.

Grounding protocol — mandatory before Step 2:

Build fact table. Each fact needs source: [fetched], [user], [past-notebook:<file>], or [inferred-from:<fact>]. Never mark fact [inferred] without citing prior fact it derives from.

FactValueSource
problem_type??
input_modality??
output_format??
eval_metric??
data schema (CSV columns / image format)??
submission format??

Gaps — ask before generating:

After building fact table, count facts still marked ? or [inferred] without prior grounded fact. Any of these unknown:

  • input_modality — cannot generate Dataset class
  • eval_metric — cannot choose torchmetric
  • submission format — cannot generate Submission section

Invoke AskUserQuestion with up to 4 questions covering all unknown required facts. Never guess or hallucinate competition-specific details (column names, file paths, data schema). State "unknown — will use placeholder" if user skips.

Acknowledge past-notebook similarity explicitly: "Found similar past notebook: <file> — reusing <pattern> from it."

Step 2: Determine problem profile

From gathered context, determine:

PropertyValue
problem_typeclassification / regression / segmentation / detection / tabular
input_modalityimage-2d / image-3d / tabular / time-series / point-cloud / mixed
output_formatlabel / scalar / mask / bboxes / rle
eval_metricAUC / F1 / RMSE / Dice / IoU / mAP / ...
recommended_modelsee §Model selection below
use_ptltrue if DNN training; false for pure XGBoost/sklearn pipelines

Model selection rules (best-fit, not default):

  • Image classification → timm.create_model (EfficientNetV2, ConvNeXt, ViT-B) + PTL
  • Image regression → timm.create_model backbone (num_classes=0) + PTL regression head
  • Image segmentation → segmentation_models_pytorch (UNet/UNet++) + PTL; MONAI for 3D
  • Object detection → torchvision.models.detection or ultralytics YOLO + PTL wrapper if needed
  • Tabular → xgboost.XGBClassifier/Regressor with sklearn Pipeline; PTL only if DNN features needed
  • Point cloud → MONAI or pytorch3d; PTL always
  • Time series → torch.nn.LSTM or tsfresh features + XGBoost; PTL when DNN

PTL rule: use PTL whenever training loop needed — even simple single-layer models. Exception: pure sklearn/XGBoost pipelines, no neural network component.

Step 3: Generate notebook script

Foundry availability check — verify before spawning:

FOUNDRY_AVAILABLE=$(ls -td ~/.claude/plugins/cache/borda-ai-rig/foundry/*/agents/sw-engineer.md 2>/dev/null | head -1)  # timeout: 5000
[ -z "$FOUNDRY_AVAILABLE" ] && { printf "⚠ foundry plugin not available — kaggle notebook generation requires foundry:sw-engineer\nInstall: claude plugin install foundry@borda-ai-rig\n"; exit 1; }

Spawn prompt assembled from the inline problem profile below plus exactly one resolved composition row:

# Re-hydrate flags persisted in Step 1 (bash state lost between Bash calls)
export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}"
IFS= read -r COMPETITION_NAME < "${TMPDIR:-/tmp}/kaggle-competition-name-${CSID}" 2>/dev/null || COMPETITION_NAME="$COMPETITION_NAME"
IFS= read -r EDA_ONLY < "${TMPDIR:-/tmp}/kaggle-eda-only-${CSID}" 2>/dev/null || EDA_ONLY="false"
IFS= read -r INFERENCE_ONLY < "${TMPDIR:-/tmp}/kaggle-inference-only-${CSID}" 2>/dev/null || INFERENCE_ONLY="false"
_KAGGLE_MODES="${CLAUDE_PLUGIN_ROOT:-plugins/cc_research}/skills/kaggle/modes"
COMPOSITION_FILE="$_KAGGLE_MODES/composition.md"
MODE="full"
[ "$EDA_ONLY" = "true" ] && MODE="eda-only"
[ "$INFERENCE_ONLY" = "true" ] && MODE="inference-only"

# Derive output filename from mode — must match the composition contract before spawning
OUTPUT_SUFFIX=""
[ "$INFERENCE_ONLY" = "true" ] && OUTPUT_SUFFIX="-inference"
OUTFILE=".experiments/kaggle/${COMPETITION_NAME}${OUTPUT_SUFFIX}.py"
echo "$MODE" > "${TMPDIR:-/tmp}/kaggle-mode-${CSID}"
echo "Mode: $MODE · Output: $OUTFILE"
cat "$COMPOSITION_FILE"  # timeout: 5000

Select the exact $MODE row from composition.md (loaded above) and cat each named contract once, from left to right, plus style-rules.md once:

_KAGGLE_MODES="${CLAUDE_PLUGIN_ROOT:-plugins/cc_research}/skills/kaggle/modes"
case "$MODE" in
  full) _CONTRACTS="foundation.md eda.md training.md inference.md submission.md" ;;
  eda-only) _CONTRACTS="foundation.md eda.md" ;;
  inference-only) _CONTRACTS="foundation.md inference.md submission.md" ;;
esac
for _c in $_CONTRACTS style-rules.md; do
    echo "=== $_c ==="
    cat "$_KAGGLE_MODES/$_c"
done

Load modality-dispatch.md only when a selected section requests a modality branch:

_KAGGLE_MODES="${CLAUDE_PLUGIN_ROOT:-plugins/cc_research}/skills/kaggle/modes"
cat "$_KAGGLE_MODES/modality-dispatch.md"  # timeout: 5000

Do not load unselected section contracts. Pass the selected row and resolved contract contents to foundry:sw-engineer after the problem profile block below.

Spawn foundry:sw-engineer with this prompt preamble (inline, then continue with the resolved composition contracts):

Write a complete Kaggle competition notebook script to `<OUTFILE>` (substitute expanded path from bash block above).

Format: Jupytext `# %%` Python script — every cell separated by `# %%` (code) or `# %% [markdown]` (markdown).

## Problem profile
- Competition: <competition-name>
- Problem type: <problem_type>
- Input: <input_modality>
- Output: <output_format>
- Metric: <eval_metric>
- Model: <recommended_model>
- Use PTL: <use_ptl>
- Description: <competition description if available>

[Continue with the selected row from composition.md, followed by the resolved section contracts in order, style-rules.md, and the selected modality branch when applicable.]

## Completion

Write `<OUTFILE>`. Return only:

{"status":"done","file":"<OUTFILE>","lines":N,"sections":N,"problem_type":"<type>","mode":"<MODE>","confidence":0.N}

Synchronous spawn note: foundry:sw-engineer spawned synchronously (not run_in_background=true), so CLAUDE.md §6 poll-based monitoring unreachable mid-call. After Agent() returns, check agent's output under .experiments/kaggle/; missing or empty → treat as timed out, surface with ⏱ marker — never silently omit.

# Compaction contract — boundary: after Step 3 notebook generated (compaction-contract.md §Lifecycle)
export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}"
IFS= read -r _COMPETITION < "${TMPDIR:-/tmp}/kaggle-competition-name-${CSID}" 2>/dev/null || _COMPETITION=""
IFS= read -r _INF < "${TMPDIR:-/tmp}/kaggle-inference-only-${CSID}" 2>/dev/null || _INF="false"
IFS= read -r _KEEP < "${TMPDIR:-/tmp}/kaggle-keep-items-${CSID}" 2>/dev/null || _KEEP=""
_SUFFIX=""; [ "$_INF" = "true" ] && _SUFFIX="-inference"
_OUTFILE=".experiments/kaggle/${_COMPETITION}${_SUFFIX}.py"
_KEEP_APPEND=""; [ -n "$_KEEP" ] && _KEEP_APPEND="; user-keep: $_KEEP"
mkdir -p .temp/state  # timeout: 5000
{
    echo "## Active Skill Contract"
    echo "- skill: research:kaggle · phase: verify (after Step 3 notebook generated)"
    echo "- run-dir: .experiments/kaggle"
    echo "- preserve: outfile=${_OUTFILE}, competition=${_COMPETITION}${_KEEP_APPEND}"
    echo "- next: Step 4 verify structure, follow-up gate, package distillation"
} > .temp/state/skill-contract.md  # timeout: 5000

Step 4: Verify and report

After agent completes:

  1. Read first 30 lines of generated file to verify # %% structure
  2. Count cell markers: grep -c "^# %%" .experiments/kaggle/<name>.py
  3. Resolve the current row from composition.md; verify every listed section is present and no unlisted section was generated
  4. Mechanically check for bare # heading-spacer lines (style-rules.md rule 13) — prose compliance alone proved insufficient in practice; auto-fix rather than trust the generating pass
# Re-derive OUTFILE from flags persisted in Step 1 (bash state lost between steps)
export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}"
IFS= read -r COMPETITION_NAME < "${TMPDIR:-/tmp}/kaggle-competition-name-${CSID}" 2>/dev/null || COMPETITION_NAME="$COMPETITION_NAME"
IFS= read -r INFERENCE_ONLY < "${TMPDIR:-/tmp}/kaggle-inference-only-${CSID}" 2>/dev/null || INFERENCE_ONLY="false"
IFS= read -r MODE < "${TMPDIR:-/tmp}/kaggle-mode-${CSID}" 2>/dev/null || MODE="full"
OUTPUT_SUFFIX=""; [ "$INFERENCE_ONLY" = "true" ] && OUTPUT_SUFFIX="-inference"
OUTFILE=".experiments/kaggle/${COMPETITION_NAME}${OUTPUT_SUFFIX}.py"
echo "=== Composition ==="; echo "$MODE"
echo "=== Cell count ==="; grep -c "^# %%" "$OUTFILE"  # timeout: 5000
echo "=== Sections ===";   grep "^# %% \[markdown\]" "$OUTFILE"  # timeout: 5000
echo "=== File size ===";  wc -l "$OUTFILE"  # timeout: 5000

echo "=== Bare '#' heading-spacer check (rule 13) ==="
BARE_HASH_COUNT=$(grep -cE '^#+[[:space:]]*$' "$OUTFILE" 2>/dev/null || echo 0)
echo "Found: $BARE_HASH_COUNT"
if [ "$BARE_HASH_COUNT" -gt 0 ]; then
    grep -nE '^#+[[:space:]]*$' "$OUTFILE"  # timeout: 5000
    python3 -c "
import re
path = '$OUTFILE'
with open(path) as f:
    text = f.read()
fixed = re.sub(r'(?m)^#+[ \t]*$', '', text)
with open(path, 'w') as f:
    f.write(fixed)
"  # timeout: 5000
    echo "Auto-fixed: $BARE_HASH_COUNT bare '#' spacer line(s) converted to true blank lines"
fi

Print to terminal:

  • Output path ($OUTFILE)
  • Mode + resolved composition contracts
  • Problem type + recommended model
  • Cell count and section list
  • Missing required sections flagged with ⚠
  • Bare # heading-spacer count found/auto-fixed (0 when clean)

Invoke AskUserQuestion as follow-up gate:

  • (a) Open in editor — ! code $OUTFILE
  • (b) Extend with additional sections
  • (c) Regenerate with different model/approach
  • (d) Done

On (a): run ! code "$OUTFILE" via Bash. On (b): re-enter Step 3 with extension directive. On (c): re-enter Step 2 with user-specified changes.

Package distillation gate — invoke after follow-up gate resolves to Done:

Benefits to state before asking: shared helpers tested once, used everywhere; wheel attachment on Kaggle faster than re-inlining; subsequent notebooks shorter; package tests catch regressions before submission.

Invoke AskUserQuestion:

  • (a) Yes — scaffold src/<package>/ with extracted helpers + tests
  • (b) Skip — keep everything inlined for now

If (a):

  1. Identify every function in notebook with no hardcoded paths, no plt.show(), no tqdm calls
  2. Write each to src/<package>/<module>.py with full Google-style docstring + Example: block — all standard coding patterns apply (doctests for pure functions, Args:/Returns: sections, full if __name__ == "__main__": guards where appropriate); these are package modules, not notebook cells
  3. Create tests/test_<module>.py covering each function
  4. Create notebooks/01_<competition-name>_pkg.py — inline definitions replaced by package imports; never modify validated baseline $OUTFILE

If (b): skip; repeat this gate offer after next notebook written.

rm -f .temp/state/skill-contract.md  # clear contract — kaggle notebook complete (compaction-contract.md §Lifecycle)  # timeout: 5000
</workflow>

What ships with it: 8 files

25.7 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. 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.