Imported from pycaret/pycaret (
AGENTS.md). Install upstream withnpx skills add pycaret/pycaret. Copyright stays with the author.
AGENTS.md — PyCaret agent instructions
Read by AI coding agents (Claude, Cursor, Copilot, etc.) before touching the repo. Single-source briefing for any agent contributing to PyCaret. Humans should read it too.
TL;DR — the 60-second briefing
- We are building PyCaret — an open-source, self-hosted ML platform (engine + backend + web UI). Product name: PyCaret. UI branding: PyCaret Control Plane. See
docs/revamp/VISION.mdfor the one-pager. - Monorepo:
apps/,services/,packages/,infra/. Every top-level dir has one reason to exist. Seedocs/revamp/ARCHITECTURE.md § 1for the layout rules. - Engine (
packages/engine/) is stateless. Built on sklearn 1.7+. Shipped on PyPI aspycaret. OOP-only; the 3.x functional API is gone. - Backend (
services/api/) is FastAPI + SQLAlchemy. Shipped on PyPI aspycaret-server. Hosts the Control Plane. - Web (
apps/web/) is Vite + React 18 + TypeScript. Dark-mode-first, single-column forms, no mystery meat. - The single contract is
RunConfig. A strict JSON schema that drives notebook / API / UI / LLM-generated runs. Spec:docs/revamp/CONTROL_PLANE_SPEC.md § 6. - Every non-trivial change gets logged in
docs/revamp/release_notes_pycaret4.mdunder the current session block (tags:BREAKING,REMOVED,ADDED,CHANGED,FIXED,DOCS,BUILD,TESTS,DEPS,INTERNAL).
Start here
Read these in order before writing code:
docs/revamp/VISION.md— 1-page product statement.docs/revamp/CONTROL_PLANE_SPEC.md— full technical spec (24 sections). The canonical scope.docs/revamp/ARCHITECTURE.md— live system architecture. Maps spec onto current code.docs/revamp/ROADMAP.md— MVP 1–4 / V2 / V3 phase breakdown. Find the phase you're contributing to.docs/revamp/STATUS.md— what's landed and what's in play. Newest session first.docs/revamp/DECISIONS.md— ADRs. If an option "feels wrong," check here; it's probably already been litigated.docs/revamp/KILL_LIST.md— everything deliberately removed from the engine. Never reintroduce any of it.docs/revamp/release_notes_pycaret4.md— engineering change log. You'll append to this.
Non-negotiables
Universal rules
- Engine is stateless.
result = engine.run(config), notsetup() + compare_models(). No module-level_CURRENT_EXPERIMENT. NoContextVarimplicit-state. - Config is the contract. The same
RunConfigJSON must work from a notebook, the REST API, the UI wizard, and an LLM-generated payload. Don't invent a parallel shape for any single surface. - Artifacts are immutable. Every promotion / retrain creates a new
pipeline_pickle. Never mutate a completed artifact. - Deployments are versioned. Every
Deploymentrow points at one specificPipelinerow. No "moving target" endpoints. - LLM is advisory. LLM calls return
suggested_config_json+reasoning_summary+risk_flags. The user approves. The deterministic engine executes. Never let the LLM directly trigger a destructive action. (See CONTROL_PLANE_SPEC § 12.3.) - Every public verb returns a typed result dataclass —
CompareResult,TuneResult,PredictResult. Never a bare DataFrame. - Every long-running operation emits a structured event through
self.logger.log(EventKind.X, ...). Noprint()inside the engine. - No upper-bound version pins on NumPy, pandas, scipy, sklearn, joblib. The whole point of 4.0 was removing those.
- No reintroducing kill-listed dependencies. See
docs/revamp/KILL_LIST.md.
Tooling conventions
- Python target: 3.13 primary; 3.11 floor.
- Node target: 22 primary; 20 floor.
- Python env:
uvfor env + lockfile,hatchlingbuild backend,rufffor lint + format,pytestfor tests, Alembic for migrations. - Node env:
npm(workspace) withpackage-lock.jsonchecked in, Vite for dev/build, Vitest for tests, ESLint flat config, TypeScript 5.6+ withverbatimModuleSyntax. - Imports (Python): absolute only inside
pycaret/andpycaret_server/. No star imports. Lazy-import heavy optional deps inside the function that needs them. - Imports (TS): use
@/alias tosrc/. Prefer named exports. Useimport typefor types (enforced byverbatimModuleSyntax). - Type hints: everywhere on new Python code.
from __future__ import annotationsat the top of every module. TS strict mode is on. - Docstrings: numpydoc style, as short as truthful. Describe why, not what.
Repo map
pycaret/ repo root
├── pyproject.toml workspace manifest only (no package)
├── uv.lock
├── AGENTS.md CONTRIBUTING.md README.md LICENSE
│
├── packages/ SHIPPABLE LIBRARIES
│ ├── engine/ → `pycaret` on PyPI (4.0.0a1)
│ │ ├── pyproject.toml hatchling build config
│ │ ├── pycaret/ the importable package
│ │ │ ├── api/ typed introspection (for UI + agents)
│ │ │ ├── core/ Experiment, results, errors, tasks
│ │ │ ├── tasks/ 5 task subclasses (public API)
│ │ │ ├── logging/ event-stream logger
│ │ │ ├── containers/ model-registry containers (being drained)
│ │ │ └── internal/ LEGACY god-class (drain in Phase 5)
│ │ └── tests/ 32 engine tests
│ ├── sdk-python/ (V2) Python client (README stub)
│ └── shared-schemas/ (V2) JSON schemas shared Python ↔ TS
│
├── services/ LONG-RUNNING DEPLOYABLES
│ ├── api/ → `pycaret-server` on PyPI (0.1.0a0)
│ │ ├── pyproject.toml
│ │ ├── alembic.ini
│ │ ├── pycaret_server/
│ │ │ ├── api/ HTTP routers (setup, auth, describe,
│ │ │ │ workspaces, projects, experiments,
│ │ │ │ runs, data_sources, deployments)
│ │ │ ├── auth/ bcrypt + JWT helpers
│ │ │ ├── db/ SQLAlchemy models + session + bootstrap
│ │ │ ├── migrations/ Alembic env + versions
│ │ │ ├── runs/ RunOrchestrator + broker + logger_bridge
│ │ │ ├── serving.py DeploymentRegistry (in-proc inference)
│ │ │ ├── config.py pydantic-settings
│ │ │ ├── app.py FastAPI factory
│ │ │ └── cli.py `pycaret-server serve | migrate`
│ │ └── tests/ 30 server tests
│ ├── worker/ (V2) background job runner (README stub)
│ └── deployment-runtime/ (V2) standalone serving (README stub)
│
├── apps/ USER-FACING APPLICATIONS
│ ├── web/ → `@pycaret/ui` (internal)
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── api/ typed client (client + endpoints + types)
│ │ │ ├── state/ Zustand stores (auth)
│ │ │ ├── components/ AuthGate, Layout
│ │ │ └── pages/ Setup, Login, Workspaces, WorkspaceDetail
│ │ └── (6 vitest tests)
│ └── desktop/ (V2) Electron wrapper (README stub)
│
├── infra/ OPS & DEPLOYMENT
│ ├── docker/ Dockerfile.api, Dockerfile.ui, compose, nginx
│ ├── helm/ (V2) Kubernetes chart (README stub)
│ └── terraform/ (V2) AWS / GCP / Azure modules (stubs)
│
├── docs/revamp/ VISION + SPEC + ROADMAP + STATUS + DECISIONS
│ + release_notes + PLATFORM_QUICKSTART
│ + ARCHITECTURE + ARCHITECTURE_ENGINE
│ + AUDIT + KILL_LIST
├── notebooks/ 5 working end-to-end notebooks (01–05)
├── scripts/ maintenance scripts
└── .github/workflows/ CI: lint + test matrix + web + notebooks
Which phase am I in?
Quick decision tree:
- Are you changing Python code inside
packages/engine/pycaret/? You're working on the engine (MVP 1). Followdocs/for_developers/DRAINING_THE_GODCLASS.mdif you're migrating a verb off_legacy. - Are you adding a route / table / service under
services/api/? MVP 2. Add the SQLAlchemy model, write an Alembic migration (autogenerate works well here), add the router, write the integration test. - Are you adding a screen / component to
apps/web/? MVP 3. Match the existing dark-mode palette + component primitives. 100% TypeScript strict. Tests invitest. - Are you editing Docker / Helm / Terraform? MVP 4 (docker) or V2 (helm / terraform). Stay within
infra/. - Are you wiring LLM functionality? Uses the
services/api/pycaret_server/llm/router (Claude + OpenAI). Every call returns an advisoryLLMConsultationrow; the user approves before execution.
Workflow
- Plan. For any non-trivial change, sketch what you'll edit + why in the response to the user before editing.
- Write small, cohesive diffs. One concern per commit.
- Run the relevant test subset locally. For the engine:
uv run pytest packages/engine/tests/ -q. For the API:uv run --package pycaret-server pytest services/api/tests/ -q. For the web:cd apps/web && npm run typecheck && npm run lint && npm test && npm run build. - Append a release-notes entry in
docs/revamp/release_notes_pycaret4.mdunder the current session block. - Update
docs/revamp/STATUS.mdif you finished a roadmap item. - Update
docs/revamp/ROADMAP.mdif you closed a phase or added scope. - Record non-obvious design choices in
docs/revamp/DECISIONS.mdas a new ADR entry (newest first).
Common tasks
Add a new backend route
- Define the SQLAlchemy model(s) in
services/api/pycaret_server/db/models.pyif needed. - Generate the migration:
cd services/api && uv run alembic revision --autogenerate -m "<slug>". Review + format the generated file. - Add the Pydantic schemas in
services/api/pycaret_server/api/schemas.py. - Create / extend the router in
services/api/pycaret_server/api/<module>.py. - Mount it in
services/api/pycaret_server/app.py. - Write the integration test in
services/api/tests/test_<module>.pyusing the TestClient fixture pattern. - Run the server suite:
uv run --package pycaret-server pytest services/api/tests/ -q.
Add a new frontend screen
- Add the typed endpoint(s) to
apps/web/src/api/endpoints.tsand the response types toapps/web/src/api/types.ts. - Create the page under
apps/web/src/pages/<Name>.tsx. - Route it in
apps/web/src/App.tsx(inside the<Layout>for authed, outside for public). - Write at least one Vitest component test.
- Check everything:
cd apps/web && npm run typecheck && npm run lint && npm test && npm run build.
Drain a god-class verb (engine, Phase 5)
- Current state: the verb calls
self._legacy.<verb>(*args, **kwargs)and wraps the return in a typed dataclass. - Reimplement natively using
sklearn.pipeline.Pipeline,sklearn.model_selection, etc. - Keep the signature + return type identical.
- Emit the same structured events.
- Add a test in
packages/engine/tests/test_e2e_oop.py. - Release-notes entry under
CHANGED+INTERNAL.
Add an LLM advisory feature
- Add a new file under
services/api/pycaret_server/llm/consultations/<type>.pywith the prompt template + output schema. - Route through the existing
LLMRouter— don't importanthropicoropenaidirectly outsideservices/api/pycaret_server/llm/providers/. - Persist results as an
LLMConsultationrow. - Output must include
suggested_config_json,suggested_action,reasoning_summary,risk_flags. The user sees all four before anything runs. - Never let the LLM cause a side effect directly.
Deep dives
docs/revamp/ARCHITECTURE_ENGINE.md— engine-internal architecture (god-class, class hierarchy, event system).docs/for_agents/ENGINE_WALKTHROUGH.md— what happens at every step offit→compare_models→predict_model.docs/for_agents/TYPED_RESULTS.md— every result dataclass, its fields, when it's produced.docs/for_agents/EVENT_STREAM.md— the canonicalEventKinds, what they carry, how to subscribe.docs/for_agents/INTROSPECTION_API.md—list_models/describe_model/describe_setup_paramscontract.docs/for_developers/SETUP.md— dev environment, linting, test matrix.docs/for_developers/TESTING.md— how to run / add tests.docs/for_developers/DRAINING_THE_GODCLASS.md— the playbook for migrating a verb off_legacy.