name: code-first-helpers
description: Use when authoring Python scripts via the code.read_file/edit_file/write_file/run quartet to do data profiling, cleaning, modeling, BigQuery, or Kaggle work — documents the autonoml.helpers API so the script doesn't have to introspect it.
priority: 92
tool-prefixes:
- code.
triggers:
- autonoml.helpers
- profile
- clean
- feature engineering
- baseline
- workflow script
- python script
- run_dir
- register_artifact
tags:
- code_first
- helpers
Code-First Helpers
Use this skill whenever you plan to write Python files under scripts/ and run them with
code.run. The autonoml.helpers package is the script-friendly API surface — it wraps the
runtime's typed services so a script can call eda.summarize(df) or
tabular.baseline_pipeline(df, target=...) instead of orchestrating tool calls.
Do not introspect the package via dir(), inspect, or one-off probe scripts. Every
helper signature, return shape, and constraint is documented below. Trust the contract.
Contract
- Use when authoring scripts under
<run>/scripts/and running them withcode.runfor profiling, cleaning, feature engineering, baselining, or any custom Python work that the typed tools don't cover directly. - Do not introspect the helper package at runtime. Do not run
python -c,dir(ah), or writeinspect_*.pyprobes — every signature and return field is documented here. - Do not call
code.edit_fileon a path that has not just been read withcode.read_file(Read-before-Edit invariant). - Required inputs are the active run directory (
autonoml.helpers.run_dir()), pandas DataFrames or pre-staged CSV/Parquet files, and an explicit target column for any modeling step. - Expected outputs are registered artifacts in the conventional dirs:
data/processed/<name>_cleaned.csv(kind=data),models/<name>_baseline.joblib(kind=model),reports/<name>_*.md|csv(kind=report),metadata/<name>_*.json(kind=metadata) — each accompanied byregister_artifact(...)so the runtime's scorecard and planner see them. - Common failures are: introspection storms eating the turn budget; cleaned-dataset paths
the planner can't recognize (must contain one of
clean,cleaned,prepared,processed,transformed,encoded,ml_ready); writing the same step under multiple script names instead of editing one; callingcode.edit_filewithout a prior read on the same path.
The four code tools (quartet)
| Tool | Required arg | Returns |
|---|---|---|
code.read_file |
path: "scripts/foo.py" |
numbered lines plus content_hash (must read before edit) |
code.edit_file |
path, old_string, new_string |
surgical replace; fails if not unique, unread, or stale |
code.write_file |
path, content |
create-only; fails if path exists |
code.run |
argv: ["python", "scripts/foo.py"] |
stdout/stderr; auto-registers files in data/, models/, reports/, metadata/, scripts/ |
argv for code.run is run-relative. The cwd is the active run directory, and the runtime
rewrites python scripts/<name>.py to the active run's script path automatically.
autonoml.helpers API (authoritative)
paths
from autonoml.helpers import run_dir # -> pathlib.Path of active run directory
Reads AUTONOML_RUN_DIR. Raises RuntimeError if unset.
registry
from autonoml.helpers import register_artifact, ArtifactRegistration
register_artifact(
path, # str | Path; absolute or run-relative
kind=Literal["data","model","report","metadata","script","other"],
metadata: dict | None = None,
supersedes: str | None = None,
) -> ArtifactRegistration
Appends to <run>/.autonoml_artifact_registrations.jsonl. The runtime ingests this file
after code.run exits. Explicit registrations override auto-registration kind/metadata for
the same path. The file does not need to exist when you register — the runtime checks
existence at ingest time.
dataframe
from autonoml.helpers import dataframe
dataframe.read(path, *, max_rows=None) -> pd.DataFrame
dataframe.profile(df) -> ProfileResult
# ProfileResult: row_count, sampled_row_count, columns: dict[str, dict], warnings
dataframe.sample(df, n, *, stratify_by=None, random_state=42) -> pd.DataFrame
dataframe.validate(df, schema: dict[str, str]) -> ValidationResult
# schema maps column -> dtype name; ValidationResult.valid: bool,
# columns, missing_columns, extra_columns, dtype_mismatches
dataframe.transform(df, operations: list[TransformOp]) -> pd.DataFrame
# ops: {"op":"drop_columns","columns":[...]}, {"op":"cast_dtype","columns": {"col": "dtype"}},
# {"op":"replace_values","column":...,"mapping":{...}},
# {"op":"filter_rows","column":...,"op_kind":"eq|ne|gt|lt|ge|le|isin|notin|isnull|notnull","value":...},
# {"op":"rename_columns","mapping":{old:new,...}}
Do not use nonexistent fields: ProfileResult.column_count, ProfileResult.duplicate_rows,
ProfileResult.payload, ValidationResult.passed, or ValidationResult.issues.
eda
All functions take a pd.DataFrame (some take extra kwargs) and return a structured dataclass:
from autonoml.helpers import eda
eda.summarize(df, *, target_column=None) -> SummaryResult
eda.missingness(df) -> MissingnessResult
eda.leakage_check(df, *, target) -> LeakageResult
eda.target_associations(df, *, target, method="auto") -> AssociationsResult
eda.correlations(df, *, columns=None, method="pearson") -> CorrelationsResult
eda.grouped_stats(df, *, group_by, metrics) -> GroupedStatsResult
eda.compare_segments(df, *, group_by, metrics) -> GroupedStatsResult
eda.outliers(df, *, method="iqr", columns=None) -> OutliersResult
eda.statistical_test(df, *, test="auto", columns=None, target) -> TestResult
EDA results are dataclasses. They do not carry .payload. For JSON metadata, use:
from dataclasses import asdict
json.dumps(asdict(result), indent=2, default=str)
Do not pass top_k to target_associations or correlations; those helpers do not accept it.
Common EDA fields:
MissingnessResult.columns: list of dicts withcolumn,null_count,null_rate,non_null_count.LeakageResult.findings: list ofLeakageFinding(column, risk_level, reason, evidence).AssociationsResult.associations: list ofTargetAssociation(column, method, score, n, details).CorrelationsResult.correlations: list ofCorrelationPair(column_a, column_b, correlation, abs_correlation, method, n).
tabular
from autonoml.helpers import tabular
tabular.baseline_pipeline(
df,
*,
target: str,
lightweight: bool = True, # True skips deep search / heavy SHAP
cv_folds: int = 5,
test_size: float = 0.2,
random_state: int = 42,
) -> BaselineResult
# BaselineResult fields:
# leaderboard: pd.DataFrame (ranked candidates)
# best_model: Any (fitted estimator, joblib-loaded)
# best_model_name: str
# best_model_family: str
# primary_metric_name: str (e.g. "balanced_accuracy", "rmse")
# primary_metric_value: float
# predictions: pd.DataFrame | None
# feature_importance: pd.DataFrame | None
# config: dict[str, Any]
# warnings: list[str]
Does prepare + run inside a throwaway workspace; raises KeyError if target not in
df.columns.
bigquery
from autonoml.helpers import bigquery
bigquery.client().query(
sql: str,
*,
max_bytes_billed: int, # MANDATORY (no default)
destination: Path | None = None,
) -> pd.DataFrame
max_bytes_billed is fail-loud — a missing or zero value raises with the dry-run estimate
in the error message so you can pick a real cap.
kaggle
from autonoml.helpers import kaggle
kaggle.check_setup() -> dict
kaggle.search_datasets(query, *, limit=20) -> list[KaggleDataset]
kaggle.list_dataset_files(handle) -> list[KaggleFile]
kaggle.download_dataset(
handle: str,
*,
max_bytes: int, # MANDATORY (no default)
destination: Path | None = None,
overwrite: bool = False,
) -> Path
Post-download size check with cleanup on overrun.
Read-before-Edit Invariant
code.edit_file rejects edits to a path you have not just read with code.read_file. The
runtime tracks the path and full-file content hash. If a write or external change happens
between the read and the edit, the edit fails; read again before editing. This mirrors Claude
Code's edit contract and prevents whole-file rewrites disguised as edits.
Standard Workflow Pattern
For a typical "load → profile → clean → baseline → report" cycle, the agent writes one
script per step and runs it with code.run. Each script ends by calling
register_artifact(...) for every output that should show up in the run's artifact list.
# scripts/profile_<dataset>.py
from dataclasses import asdict
from pathlib import Path
import pandas as pd
from autonoml.helpers import run_dir, register_artifact, dataframe, eda
df = pd.read_csv(run_dir() / "data" / "raw" / "<file>.csv")
summary = eda.summarize(df, target_column="<target>")
report_path = run_dir() / "reports" / "<dataset>_profile.md"
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text("# Profile\n\n" + str(summary))
register_artifact(report_path, kind="report",
metadata={"section": "profile"})
profile_json = run_dir() / "metadata" / "<dataset>_profile.json"
profile_json.parent.mkdir(parents=True, exist_ok=True)
profile_json.write_text(__import__("json").dumps({
"profile": asdict(dataframe.profile(df)),
"summary": asdict(summary),
}, indent=2, default=str))
register_artifact(profile_json, kind="metadata")
Hard Rules
- Do not run ad-hoc
python -c "..."to introspect helpers. The API above is the contract. - Do not write probe scripts (
inspect_helpers.py,inspect_*_fields.py, …) — every signature is in this skill. - Do not use
code.edit_filewithout a priorcode.read_fileon the same path. - Do not invent helper functions. If you need behaviour outside this surface, write it inline
with
pandas/numpydirectly in your script. - Do not skip
register_artifactfor outputs that must appear in the run's artifact list (cleaned datasets, models, reports, metrics JSON). The auto-registration covers basic files in conventional dirs but loses themetadata={"section": ...}hints the scorecard uses. - Do not name a cleaned dataset something the planner won't recognize. Use a path containing
one of:
clean,cleaned,prepared,processed,transformed,encoded,ml_ready. - Do not write multiple scripts that do the same step. One profile script, one clean script,
one baseline script — replace via
code.edit_file, not re-create with a new name.
When NOT to Use This Skill
- For pure typed-tool work (
dataframe.profile_file,tabular.run_experiment,bigquery.query_to_file), use the corresponding skill. The code-first surface is for cases the typed tools don't cover or when you specifically want script-level control. - For BigQuery or Kaggle source acquisition, prefer the dedicated skills' warehouse/dataset workflows first; drop into this skill only when you need post-fetch custom processing.
References
references/quickstart.md— three minimal end-to-end script patterns (profile, clean, baseline). This is an optional prompt reference, not a run-workspace file; do not callcode.read_fileon it.