notebook-ml-architect — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited notebook-ml-architect (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Expert guidance for production-quality ML notebooks.
| Operation | Use Case |
|---|---|
| audit | Analyze notebook for anti-patterns, leakage, reproducibility issues |
| refactor | Transform notebook into modular Python pipeline |
| template | Generate new notebook from EDA/classification/experiment template |
| report | Create markdown summary from executed notebook |
| convert | Extract Python script from notebook |
When auditing a notebook:
python scripts/analyze_notebook.py <notebook.ipynb>Transform notebooks into production pipelines:
Look for markdown headers that indicate logical sections:
Convert repeated or complex cell code into functions:
# Before: inline code
df = pd.read_csv('data.csv')
df = df.dropna()
df['feature'] = df['a'] * df['b']
# After: function
def load_and_prepare_data(path: str) -> pd.DataFrame:
df = pd.read_csv(path)
df = df.dropna()
df['feature'] = df['a'] * df['b']
return dfproject/
├── data.py # Data loading and preprocessing
├── features.py # Feature engineering
├── model.py # Model definition
├── train.py # Training loop
├── evaluate.py # Evaluation metrics
├── config.py # Configuration parameters
└── main.py # Pipeline entry pointpython scripts/convert_to_script.py notebook.ipynb output.py --group-by-sectionsGenerate new notebooks from templates:
assets/templates/eda_template.ipynb)assets/templates/classification_template.ipynb)assets/templates/experiment_template.ipynb)Copy template to project and customize:
cp ~/.claude/skills/notebook-ml-architect/assets/templates/classification_template.ipynb ./my_experiment.ipynbOr generate programmatically with modifications.
Use the reproducibility header snippet:
# Copy from assets/snippets/reproducibility_header.py import sys
print(f"Python: {sys.version}")
for pkg in ['numpy', 'pandas', 'sklearn', 'torch']:
try:
mod = __import__(pkg)
print(f"{pkg}: {mod.__version__}")
except ImportError:
pass pip freeze > requirements.txt
# Or for conda:
conda env export > environment.ymlWhen you need accurate API information:
1. Call resolve-library-id with library name
2. Call get-library-docs with the returned ID and topicExamples:
When you need up-to-date recommendations:
web_search_exa for discoverycrawling_exa to pull full content from good URLsdeep_search_exa for focused queriesExamples:
When you need to see how others do it:
searchGitHub with:
- query: specific code pattern
- language: ["Python"]
- path: ".ipynb" for notebooksExamples:
Parse notebook and extract structure:
python scripts/analyze_notebook.py <notebook.ipynb> [--output json|text]Output includes:
Execute notebook with parameters:
python scripts/run_notebook.py input.ipynb output.ipynb \
--params '{"learning_rate": 0.01, "epochs": 100}' \
--timeout 3600Extract Python from notebook:
python scripts/convert_to_script.py notebook.ipynb output.py \
--include-markdown \
--group-by-sections \
--add-mainProblem: Preprocessing on full dataset before split
# BAD
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # Fits on all data
X_train, X_test = train_test_split(X_scaled)Fix: Split first, fit on train only
# GOOD
X_train, X_test = train_test_split(X)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # Transform onlyProblem: Variables from previous runs affect results
# Cell 1 run multiple times
results.append(model.score(X_test, y_test)) # results grows each runFix: Initialize state in cell
results = [] # Always start fresh
results.append(model.score(X_test, y_test))Problem: Different results each run
X_train, X_test = train_test_split(X, y) # Random each timeFix: Set seeds explicitly
SEED = 42
X_train, X_test = train_test_split(X, y, random_state=SEED)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.