Skip to content

Repository files navigation

AgentML

Local-first, zero-cost AutoML. Upload a CSV and a multi-agent system runs the full ML pipeline — cleaning, EDA, feature engineering, model training, evaluation — streaming its reasoning, code, plots, and tables in real time. Everything runs on your machine: local models via Ollama by default, a local Jupyter kernel for execution, and a local SQLite store for history.

  • Your data never leaves your machine. No upload to a cloud service, no third-party analytics. With the default Ollama provider, not even prompts go out.
  • $0 per run. No subscription, no metered API — the default setup has no cloud dependency at all. (Anthropic/OpenAI are supported as opt-in providers if you want a stronger model and don't mind the tokens.)
  • You stay in control. Watch every decision as it streams, and approve, modify, or reject each pipeline stage through human-in-the-loop gates.

Warning

AgentML runs LLM-generated Python on your machine and has no authentication. It is designed to run locally, for a single trusted user, bound to 127.0.0.1. The code validator is a guardrail, not a security sandbox — an agent can still read and write files your user account can access. Do not expose this server to a network or run it on shared/multi-user infrastructure without adding your own authentication and OS-level isolation. See Security.

Screenshots

Upload a CSV and just ask — the dataset is previewed in chat, and the agent starts reasoning about your data immediately:

CSV upload with data preview and the agent starting its analysis

Agent Mode running the pipeline — the agent streams its reasoning, executes code in the Jupyter kernel, and tracks progress through the five pipeline stages (Prep → EDA → Features → Training → Evaluation):

Agent pipeline run with streamed reasoning and code execution

Rich output in chat — plots render inline as the agent explores your data:

EDA charts rendered inline in the chat

Learn ML concepts interactively — no dataset required. Ask about a concept ("I want to learn gradient descent") and the agent writes a runnable demo, plots it, and explains the intuition step by step:

Agent writing a gradient descent demo from a plain-language learning request

Gradient descent visualized with step-by-step markers and a plain-language explanation

Features

Multi-Agent Pipeline

  • 8 specialized agents coordinated by LangGraph:
    • Orchestrator — Routes between pipeline stages, manages forward and backward navigation
    • General Agent — Handles free-form conversation and data exploration (no pipeline)
    • Preprocessing Agent — Data cleaning, type fixing, missing values, duplicates
    • EDA Agent — Exploratory data analysis on cleaned data
    • Feature Engineering Agent — Encoding, scaling, feature creation and selection
    • Modeling Agent — Algorithm selection, training, cross-validation
    • Evaluation Agent — Metrics, comparisons, final recommendations
    • Hungry Agent — Quality review gate that cross-references stage findings to catch missed opportunities

Two Operating Modes

  • Chat Mode — Step-by-step control. Ask questions, run code, explore data. No pipeline triggers. You drive every action. Also works with no dataset at all — use it as an interactive ML tutor that answers concept questions with runnable, plotted examples.
  • Agent Mode — Autonomous end-to-end pipeline. The system understands your data, asks clarifying questions, then runs the full ML pipeline with human-in-the-loop approval gates between stages.

Intelligent Pipeline Navigation

  • Forward flow: preprocessing > eda > feature engineering > modeling > evaluation
  • Backward navigation: If evaluation shows poor results, the orchestrator can route back to earlier stages with specific improvement strategies
  • Iterative improvement loop: Performance thresholds trigger automatic revisits with a 2-attempt limit per stage
  • "Now I Know Better" restart: After completing the pipeline, the system can propose restarting with insights gained

Human-in-the-Loop (HITL)

  • Approval gates at every stage transition in Agent Mode
  • Options: approve, modify (with feedback), or reject (redo the stage)
  • 10-minute timeout with auto-approve fallback

Real-Time Streaming

  • WebSocket-based streaming of agent thinking, decisions, code execution, plots, and tables
  • Live pipeline progress indicator
  • Structured message parts: thinking blocks, decision tags, code cells with rich output

Execution Engine

  • Persistent Jupyter kernel per session with full pandas/sklearn/matplotlib support
  • Process-isolated execution — The kernel runs in a child process via ZMQ. If libzmq crashes, only the child dies; the server spawns a new one automatically
  • Execution state tracking via ExecutionLedger — variables tracked outside the kernel for crash recovery
  • Error loop detection — 2 consecutive errors trigger recovery guidance, 3 force escalation, kernel crashes handled separately

Session Management

  • No-upload chat — Start a session without a CSV for general conversation
  • Read-only expired sessions — When a session's CSV is no longer on disk, the session switches to insights-only mode (no code execution, but conversation history and findings preserved)
  • Per-session concurrency locks — Prevents concurrent agent runs on the same session
  • Auto-cleanup — 1-hour idle timeout with periodic session cleanup
  • Session rename via sidebar

Persona Mode

  • Normal — Professional, numbers-focused output
  • Quirky — Puns, pop culture references, and playful language in reasoning (code stays clean)

Quick Start

Prerequisites

  • Python 3.11+ (3.12 recommended)
  • Node.js 18+
  • Ollama for the default fully-local setup — install it and pull a model: ollama pull qwen3:8b. (Skip this only if you plan to use Anthropic/OpenAI instead.)

Backend

cd backend
python -m venv venv

# Activate virtual environment
# Windows: venv\Scripts\activate
# macOS/Linux: source venv/bin/activate

pip install -r requirements.txt
python -m ipykernel install --user
python -m uvicorn main:app --reload --port 8002

Frontend

npm install
npm start

Open http://localhost:3000 and start analyzing. With Ollama running, it works out of the box — no API key, no account. To use a cloud provider instead, pick it and add a key in Settings.

You can either upload a CSV and let the agent pipeline run, or just type "hi" to start a chat session without any dataset.

Configuration

Environment Variables

Variable Description Default
AGENTML_API_KEY API key for the active cloud provider (also ANTHROPIC_API_KEY / OPENAI_API_KEY) (none — set via UI or env)
AGENTML_LLM_PROVIDER anthropic, openai, or ollama ollama
AGENTML_CORS_ORIGINS Comma-separated allow-list of browser origins. Not set → local dev origins only. Setting * disables the allow-list (unsafe — see Security). http://localhost:3000, http://127.0.0.1:3000
AGENTML_ALLOW_PRIVATE_OLLAMA Allow an Ollama URL on a private/LAN address (off by default to blunt SSRF) false
AGENTML_SESSION_TTL_DAYS Purge session history after N days of inactivity (0 = keep forever) 30
REACT_APP_API_URL Backend API URL http://localhost:8002
REACT_APP_WS_URL Backend WebSocket URL derived from API URL

Settings can also be configured via the Settings modal in the UI. See .env.example and backend/.env.example for templates.

Security

AgentML's core feature — an AI agent that writes and runs Python against your data — is also its main risk. Read this before running it anywhere but your own laptop.

Threat model: single trusted local user. The backend has no authentication. Anyone who can reach the HTTP/WebSocket port can create sessions, run the agent, and therefore execute code as your user account. That is acceptable when it is bound to 127.0.0.1 on your own machine and nothing else can reach it. It is not acceptable on a shared host, a public IP, or behind a naive port-forward.

Code execution is not sandboxed. guardrails/code_validator.py blocks obvious escapes (import os, subprocess, eval, shell magics, dunder introspection) and raises the bar against a careless model, but it is a denylist, not a jail. Because pandas/numpy/sklearn are intentionally allowed, generated code can still read any file your account can read (pd.read_csv('~/.ssh/id_rsa')) and write files (df.to_csv(...)). If you need a real boundary, run the backend inside a container as a non-root user with no network egress and only the dataset directory mounted.

Hardening that ships by default:

  • Server binds to 127.0.0.1 (loopback) via npm run backend.
  • CORS defaults to the local dev origins only — a wildcard is never the default, so a random website can't drive your local API from your browser. Override with AGENTML_CORS_ORIGINS only for origins you trust.
  • Ollama URLs resolving to private/link-local/metadata addresses are rejected (SSRF), unless you opt in with AGENTML_ALLOW_PRIVATE_OLLAMA=1.
  • Uploads are size-capped (50 MB) as they stream, CSV-only, with sanitized filenames.
  • Prompt-injection defense escapes agent-protocol tags in dataset/column names and user text; per-field length caps bound context flooding.
  • HTTP and WebSocket rate limiters throttle abusive clients.

Secrets. Provider API keys are stored in plaintext — on the backend in backend/.agentml_settings.json (gitignored) and in the browser's localStorage. Both are readable by anything running as your user / on the origin. Prefer supplying keys via environment variables, and treat a machine running AgentML as holding those keys in the clear. If you don't want cloud keys involved at all, use the Ollama provider (the default) for fully local inference.

If you deploy this beyond localhost, you are responsible for adding: authentication and per-user session isolation, OS-level sandboxing of the kernel, and a real secrets store. None of that is built in.

Found a vulnerability? Please report it privately via a GitHub security advisory rather than a public issue.

Architecture

Frontend (React + Zustand)
    |
    | WebSocket / HTTP
    v
Backend (FastAPI)
    |
    +-- Agent Graph (LangGraph)
    |       |
    |       +-- Entry Router (zero-cost, no LLM call)
    |       |       |
    |       |       +-- General Agent (chat mode)
    |       |       +-- Orchestrator (pipeline mode)
    |       |               |
    |       |               +-- 5 Stage Agents
    |       |               +-- Hungry Agent (quality review)
    |       |
    |       +-- execute_code tool
    |               |
    |               v
    +-- Jupyter Kernel (subprocess-isolated via ZMQ)
    |
    +-- SQLite Database (sessions, messages, experiments)

For the full system design, see docs/architecture.md. For a per-file walkthrough of what every component does and how it connects, see docs/components.md.

Project Structure

agentml/
├── backend/                     # Python backend (FastAPI + LangGraph + Jupyter)
│   ├── main.py                  # FastAPI app, CORS, rate limit, lifespan, route mounts
│   ├── config.py                # Settings singleton (LLM provider, API keys, persona)
│   ├── agent/
│   │   ├── pipeline.py          # LangGraph topology + nodes + checkpointer (the big one)
│   │   ├── driver.py            # run_agent_streaming — the entry point the WS calls
│   │   ├── common.py            # Shared building blocks: _get_llm, message utils, thresholds
│   │   ├── routing.py           # STAGES + get_next_stage (deterministic stage order)
│   │   ├── schemas_llm.py       # Structured-output models (EvaluationDecision, DebateVerdict)
│   │   ├── debate.py            # Debate kernel-code assets (scoreboard/viz/preflight)
│   │   ├── state.py             # AgentState TypedDict carried through graph nodes
│   │   ├── tools.py             # execute_code tool — only tool any agent can call
│   │   ├── ledger.py            # ExecutionLedger — tracks kernel variables externally
│   │   ├── events.py            # EventEmitter — queues streaming events to the WS
│   │   ├── parser.py            # Parses <thinking>/<decision>/<stage>/etc tags
│   │   ├── llm_utils.py         # invoke_with_retry / ainvoke_with_retry
│   │   ├── hitl.py              # Human-in-the-loop gate definitions
│   │   └── prompts/             # System prompt TEXT only — fetched via get_prompt(stage)
│   │       ├── __init__.py          # get_prompt() lazy registry + available_stages()
│   │       ├── base.py              # BASE_INSTRUCTIONS + QUIRKY_PERSONA (shared fragments)
│   │       ├── general.py           # GENERAL_PROMPT (unified entry point)
│   │       ├── orchestrator.py      # EVAL_DECISION_PROMPT (end-of-run gate)
│   │       ├── preprocessing.py
│   │       ├── eda.py
│   │       ├── feature.py
│   │       ├── modeling.py          # MODELING_A_PROMPT + MODELING_B_PROMPT (debate specialists)
│   │       ├── evaluation.py
│   │       ├── hungry.py            # accuracy-obsessed review gate
│   │       └── debate.py            # DEBATE_A/B_SYSTEM + JUDGE_SYSTEM personas
│   ├── api/
│   │   ├── schemas.py           # Pydantic request/response models
│   │   └── routes/
│   │       ├── upload.py        # POST /api/upload, /api/upload-multiple
│   │       ├── chat.py          # POST /api/chat (legacy sync fallback)
│   │       ├── ws.py            # /ws/{session_id} (primary streaming endpoint)
│   │       ├── sessions.py      # CRUD on sessions
│   │       ├── settings.py      # GET/POST /api/settings
│   │       └── models.py        # GET /api/models/available (cloud + Ollama)
│   ├── executor/
│   │   └── notebook.py          # NotebookExecutor — subprocess-isolated Jupyter kernel
│   ├── db/
│   │   ├── database.py          # SQLite (sessions, messages, experiments)
│   │   └── models.py            # Pydantic record models
│   ├── guardrails/
│   │   ├── code_validator.py    # AST allow/block list (blocks os/sys/eval/etc)
│   │   ├── prompt_sanitizer.py  # Prompt injection defense (escapes agent tags)
│   │   └── rate_limiter.py      # HTTP + WebSocket rate limiters
│   └── utils/
│       ├── session_manager.py   # ChatSession dataclass + in-memory store + lifecycle
│       ├── data_utils.py        # Column metadata + preview row formatting
│       └── plot_utils.py        # Matplotlib figure → base64 helper
│
├── src/                         # React frontend
│   ├── index.js                 # React root
│   ├── App.js                   # <AppLayout><ChatLayout /></AppLayout>
│   ├── api/
│   │   └── client.js            # Axios instance + WebSocket factory
│   ├── store/
│   │   └── chatStore.js         # Zustand store — single source of truth (~700 LOC)
│   ├── utils/
│   │   └── apiError.js          # Normalize axios/FastAPI errors to user text
│   └── components/
│       ├── layout/
│       │   ├── AppLayout.jsx    # Sidebar + main content wrapper
│       │   └── Sidebar.jsx      # Session list, rename, delete, new chat
│       ├── chat/
│       │   ├── ChatLayout.jsx       # Header, banners, MessageList, ChatInput
│       │   ├── MessageList.jsx      # Scrollable, auto-scroll, streaming overlay
│       │   ├── MessageBubble.jsx    # Renders each message part by type
│       │   ├── ChatInput.jsx        # Textarea + drag-drop CSV + model selector
│       │   ├── ModelSelector.jsx    # Dropdown listing cloud + Ollama models
│       │   ├── CodeBlock.jsx        # Collapsible code cell w/ output
│       │   ├── ChartOutput.jsx      # Base64 PNG renderer
│       │   ├── TableOutput.jsx      # DOMPurify-sanitized pandas HTML tables
│       │   ├── ThinkingBlock.jsx    # Collapsible <thinking> block
│       │   ├── ThinkingIndicator.jsx # Animated indicator w/ stage message
│       │   ├── DecisionCard.jsx     # <decision> callout
│       │   └── HITLCard.jsx         # Human-in-the-loop prompt UI
│       ├── pipeline/
│       │   └── PipelineProgress.jsx # Horizontal 5-stage progress bar
│       └── shared/
│           ├── SettingsModal.jsx    # API keys, persona, Ollama URL
│           └── DataTable.jsx        # Generic table (currently unused)
│
├── docs/                        # Documentation
│   ├── architecture.md          # High-level system design + data flows
│   ├── components.md            # Per-file reference (this is your map)
│   ├── api.md                   # HTTP + WebSocket API reference
│   ├── setup.md                 # Installation, environment, troubleshooting
│   └── images/                  # Screenshots used in the README
│
├── public/                      # CRA public/ (favicon, index.html)
└── package.json                 # Frontend dependencies + CRA scripts

Tech Stack

Backend: FastAPI, LangGraph, LangChain (OpenAI / Anthropic / Ollama bindings), jupyter-client, SQLite, Pydantic

Frontend: React 18, Zustand, TailwindCSS, Framer Motion, Lucide Icons, ReactMarkdown, react-syntax-highlighter, DOMPurify, axios, react-dropzone

AI: Claude (Sonnet 4.5 / Opus 4), OpenAI (GPT-4o / 4o-mini / o3-mini), or any Ollama model (default: qwen3:8b). Configurable via the in-app Settings modal.

Documentation

New to the codebase? Read docs/components.md first, then open backend/agent/driver.py and follow run_agent_streaming end-to-end (the graph itself is built in backend/agent/pipeline.py).

License

MIT

About

A local data scientist agent

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages