genekyle/agent-platform

Proof of concept for an agent platform using Chrome MCP, Docker, FastAPI services, and a React frontend.

0

stars

848

commits

Python

primary language

Sep 3, 2026

updated

README

🧭 Ops Pilot

A supervised browser agent that gets cheaper and more autonomous the longer it runs.

Not a scraper. A per-step decision loop where every action is made by the cheapest tool that's confident, a human catches anything uncertain, and every correction becomes training data for local models that take work off the expensive LLM.

Ops Pilot demo


Python FastAPI React Postgres Claude Status


Why this isn't a web scraper

A scraper reads a fixed page and pulls fields. Ops Pilot operates a browser like a careful human would β€” it looks at the live page, decides what to do next, does it, and checks the result, step after step, across states it has never seen.

A scraper…Ops Pilot…
Parses a known DOMPerceives an arbitrary page (accessibility tree + vision when the AX tree lies)
Follows a hard-coded pathDecides each step with a cheapest-first cascade
Breaks on a new layout / captchaEscalates stop-states (captcha, 2FA, checkpoints) to a human, $0
Costs the same foreverGets cheaper over time β€” it trains local models from its own corrections
Fire-and-forgetSupervised β€” budget-capped, human-in-the-loop, every decision logged

It's a framework for building reliable web automation that improves itself β€” perception, decision, action, and verification as separate, swappable, individually-trainable stages.


The per-step loop

Every step runs the same five stages. Each is the cheapest tool that's still confident; anything uncertain stops for a human.

flowchart LR
    O([Observe page]) --> C{classify<br/>stop-state?}
    C -- captcha / 2FA --> H[[πŸ§‘ Human]]
    C -- ok --> P[propose<br/>AX + vision candidates]
    P --> S{select<br/>cheapest-first cascade}
    S -- low confidence --> H
    S -- confident --> A[act<br/>pluggable executor]
    A --> V{verify<br/>did the page change<br/>as predicted?}
    V -- no, retry --> S
    V -- gave up --> H
    V -- yes --> O
StageWhat it doesHow
classifyIs this a STOP screen? (captcha / 2FA / checkpoint)rules β†’ escalate to human, $0
proposeCandidate elements on the pageraw CDP accessibility tree (role + name + bbox), vision fallback when AX is blind
selectPick the targetthe cascade below
actMove + click / typepluggable executor drivers (style varies; intent is canonical)
verifyDid it work?AX/DOM delta vs. prediction β†’ retry once β†’ escalate

The cheapest-first cascade (the "inner loop")

The whole cost story lives here. A decision falls through layers until one is confident β€” and expensive layers exist only as a catchall.

flowchart TD
    L1[1 Β· Deterministic rules<br/><i>FREE</i>] -->|miss| L2[2 Β· Fingerprint cache<br/><i>FREE</i>]
    L2 -->|miss| L3[3 Β· Tiny page-state classifier<br/><i>local, ~free</i>]
    L3 -->|miss| L4[4 Β· Micro-model selector<br/><i>local, cheap</i>]
    L4 -->|miss| L5[5 Β· Claude Haiku Set-of-Marks<br/><i>~$0.0026, budget-gated</i>]
    L5 -->|AX-blind| L6[6 Β· Vision-native / Human<br/><i>catchall</i>]
    style L1 fill:#1f8a4c,color:#fff
    style L2 fill:#1f8a4c,color:#fff
    style L5 fill:#d97757,color:#fff
    style L6 fill:#7a4ad9,color:#fff

Today, work is done by Layer 2 (cache) and Layer 5 (Haiku). Layers 1/3/4 are deliberately empty β€” they get earned from data once the logs show Haiku is being reached too often. Don't build models ahead of evidence.


The flywheel πŸ›ž β€” why it gets cheaper

This is the thesis. Haiku isn't the product; it's the teacher.

flowchart LR
    R[Run a task] --> L[Log every decision<br/>+ escalation]
    L --> D[(Corpora<br/>per layer)]
    D --> T[Train cheap<br/>local models]
    T --> P[Promote into<br/>the cascade]
    P --> R
    P -.->|Haiku reached less| $[πŸ’° cost / task ↓]

Each run logs the expensive model's picks and the human's corrections. Those become a distillation corpus for tiny local models that slot into the cascade and answer for free β€” so the same task gets cheaper and more autonomous the longer it runs. A hard $5/week autonomous-spend cap keeps the teacher honest.


Inside the app


Control plane β€” operating posture at a glance: active runs, blocked runs needing a human, system health.

Structured capture β€” every data point is scoped to a domain Β· goal Β· scenario session with its own isolated Chrome.

Flywheel metrics β€” cost/day, layer mix, and reason codes over the live corpus. Cache-hit ↑ + cost flat = the wheel is turning.

Movement Playground β€” record real cursor paths vs. the model's motion, growing the corpus for a diffusion-based human-like input model.

The UI also includes a per-page-state Coverage tracker (drive data collection to the gaps), a live Model Test bench (run the SELECT cascade against any capture), and an Eval Runs / Model Registry for the grounding models.


The model roster

Nothing in the loop is a trained model yet β€” that's by design (collect data first, train later). Each has its own corpus, trainer, and a shared eval contract so it can be retrained independently as data accumulates.

ModelRoleTrains from
Page-state classifierperception / cascade L3tagged captures (login wall, feed, captcha, …)
Micro-model selectorcascade L4the SELECT telemetry (Haiku's picks = labels)
Diffusion input modelact / human-like cursor motionrecorded Movement-Playground trajectories
Vision element groundingpropose super-fallbacktraining captures + labels
State-transition / outcomelook-ahead & task successper-step trajectory corpus

Tech stack

LayerTech
Decision enginePython Β· pure port-based loop (unit-tested without a browser)
Perceptionraw Chrome DevTools Protocol (accessibility tree + box model), Set-of-Marks vision
Reasoning (catchall)Claude Haiku 4.5 via the Anthropic API, prompt-cached & budget-gated
Control planeFastAPI Β· SQLAlchemy Β· Postgres Β· Redis
FrontendReact + Vite
InfraDocker Compose (local), corpora as append-only JSONL

Project status

Phase: multi-domain data collection β€” building the corpora that the cheap local layers will train on.

  • βœ… Per-step loop, cheapest-first cascade, verifier, and all guardrails β€” built & tested
  • βœ… Capture β†’ corpus β†’ coverage pipeline across multiple domains (Facebook, Indeed, …)
  • βœ… Stop-state escalation verified on real reCAPTCHA & 2FA
  • πŸ”œ First trainable model: the page-state classifier (L3)
  • πŸ”œ Continuous retraining β†’ the full self-improving flywheel
Guardrails & safety
  • $5/week autonomous spend cap, enforced before every paid call
  • Human escalation on stop-state, over-budget, low-confidence, no-match, or verifier-fail
  • Record-only by default β€” the loop logs its decided intent and fires nothing until trusted
  • Never auto-solves captchas β€” those are a human gate by design
  • Credentials live only in a git-ignored .env, never logged

Local development

Repo layout

  • apps/controlplane-api β€” FastAPI control plane, training & runtime APIs
  • apps/mcp β€” capture server + observer pipeline (CDP-AX proposer)
  • apps/controlplane-ui β€” Vite/React frontend
  • infra β€” local Postgres & Redis via Docker Compose
  • scripts β€” dev startup, shutdown, health-check helpers

One command

make dev

Starts Postgres, Redis, the Control Plane API (:8081), the Capture Server (:8082), and the UI (:5173). Training Chrome is launched on demand per session from the UI. First run also creates .venv, installs Python deps, and runs npm ci.

make setup     # first-time env setup only
make dev-stop  # stop everything
make doctor    # health check

The virtual environment lives at .venv; the dev scripts call .venv/bin/python directly, so no manual activation is needed.

Then, in the UI

  1. Open Training β†’ create a session (domain Β· goal Β· scenario)
  2. Start Session Chrome
  3. Capture against that session-scoped browser

Built as a study in resource-efficient, self-improving web automation β€” perception, decision, action, and verification as separate, individually-trainable stages.

Contributors

genekyle

848 commits

genekyle/agent-platform

Proof of concept for an agent platform using Chrome MCP, Docker, FastAPI services, and a React frontend.

0

stars

848

commits

Python

primary language

Sep 3, 2026

updated

README

🧭 Ops Pilot

A supervised browser agent that gets cheaper and more autonomous the longer it runs.

Not a scraper. A per-step decision loop where every action is made by the cheapest tool that's confident, a human catches anything uncertain, and every correction becomes training data for local models that take work off the expensive LLM.

Ops Pilot demo


Python FastAPI React Postgres Claude Status


Why this isn't a web scraper

A scraper reads a fixed page and pulls fields. Ops Pilot operates a browser like a careful human would β€” it looks at the live page, decides what to do next, does it, and checks the result, step after step, across states it has never seen.

A scraper…Ops Pilot…
Parses a known DOMPerceives an arbitrary page (accessibility tree + vision when the AX tree lies)
Follows a hard-coded pathDecides each step with a cheapest-first cascade
Breaks on a new layout / captchaEscalates stop-states (captcha, 2FA, checkpoints) to a human, $0
Costs the same foreverGets cheaper over time β€” it trains local models from its own corrections
Fire-and-forgetSupervised β€” budget-capped, human-in-the-loop, every decision logged

It's a framework for building reliable web automation that improves itself β€” perception, decision, action, and verification as separate, swappable, individually-trainable stages.


The per-step loop

Every step runs the same five stages. Each is the cheapest tool that's still confident; anything uncertain stops for a human.

flowchart LR
    O([Observe page]) --> C{classify<br/>stop-state?}
    C -- captcha / 2FA --> H[[πŸ§‘ Human]]
    C -- ok --> P[propose<br/>AX + vision candidates]
    P --> S{select<br/>cheapest-first cascade}
    S -- low confidence --> H
    S -- confident --> A[act<br/>pluggable executor]
    A --> V{verify<br/>did the page change<br/>as predicted?}
    V -- no, retry --> S
    V -- gave up --> H
    V -- yes --> O
StageWhat it doesHow
classifyIs this a STOP screen? (captcha / 2FA / checkpoint)rules β†’ escalate to human, $0
proposeCandidate elements on the pageraw CDP accessibility tree (role + name + bbox), vision fallback when AX is blind
selectPick the targetthe cascade below
actMove + click / typepluggable executor drivers (style varies; intent is canonical)
verifyDid it work?AX/DOM delta vs. prediction β†’ retry once β†’ escalate

The cheapest-first cascade (the "inner loop")

The whole cost story lives here. A decision falls through layers until one is confident β€” and expensive layers exist only as a catchall.

flowchart TD
    L1[1 Β· Deterministic rules<br/><i>FREE</i>] -->|miss| L2[2 Β· Fingerprint cache<br/><i>FREE</i>]
    L2 -->|miss| L3[3 Β· Tiny page-state classifier<br/><i>local, ~free</i>]
    L3 -->|miss| L4[4 Β· Micro-model selector<br/><i>local, cheap</i>]
    L4 -->|miss| L5[5 Β· Claude Haiku Set-of-Marks<br/><i>~$0.0026, budget-gated</i>]
    L5 -->|AX-blind| L6[6 Β· Vision-native / Human<br/><i>catchall</i>]
    style L1 fill:#1f8a4c,color:#fff
    style L2 fill:#1f8a4c,color:#fff
    style L5 fill:#d97757,color:#fff
    style L6 fill:#7a4ad9,color:#fff

Today, work is done by Layer 2 (cache) and Layer 5 (Haiku). Layers 1/3/4 are deliberately empty β€” they get earned from data once the logs show Haiku is being reached too often. Don't build models ahead of evidence.


The flywheel πŸ›ž β€” why it gets cheaper

This is the thesis. Haiku isn't the product; it's the teacher.

flowchart LR
    R[Run a task] --> L[Log every decision<br/>+ escalation]
    L --> D[(Corpora<br/>per layer)]
    D --> T[Train cheap<br/>local models]
    T --> P[Promote into<br/>the cascade]
    P --> R
    P -.->|Haiku reached less| $[πŸ’° cost / task ↓]

Each run logs the expensive model's picks and the human's corrections. Those become a distillation corpus for tiny local models that slot into the cascade and answer for free β€” so the same task gets cheaper and more autonomous the longer it runs. A hard $5/week autonomous-spend cap keeps the teacher honest.


Inside the app


Control plane β€” operating posture at a glance: active runs, blocked runs needing a human, system health.

Structured capture β€” every data point is scoped to a domain Β· goal Β· scenario session with its own isolated Chrome.

Flywheel metrics β€” cost/day, layer mix, and reason codes over the live corpus. Cache-hit ↑ + cost flat = the wheel is turning.

Movement Playground β€” record real cursor paths vs. the model's motion, growing the corpus for a diffusion-based human-like input model.

The UI also includes a per-page-state Coverage tracker (drive data collection to the gaps), a live Model Test bench (run the SELECT cascade against any capture), and an Eval Runs / Model Registry for the grounding models.


The model roster

Nothing in the loop is a trained model yet β€” that's by design (collect data first, train later). Each has its own corpus, trainer, and a shared eval contract so it can be retrained independently as data accumulates.

ModelRoleTrains from
Page-state classifierperception / cascade L3tagged captures (login wall, feed, captcha, …)
Micro-model selectorcascade L4the SELECT telemetry (Haiku's picks = labels)
Diffusion input modelact / human-like cursor motionrecorded Movement-Playground trajectories
Vision element groundingpropose super-fallbacktraining captures + labels
State-transition / outcomelook-ahead & task successper-step trajectory corpus

Tech stack

LayerTech
Decision enginePython Β· pure port-based loop (unit-tested without a browser)
Perceptionraw Chrome DevTools Protocol (accessibility tree + box model), Set-of-Marks vision
Reasoning (catchall)Claude Haiku 4.5 via the Anthropic API, prompt-cached & budget-gated
Control planeFastAPI Β· SQLAlchemy Β· Postgres Β· Redis
FrontendReact + Vite
InfraDocker Compose (local), corpora as append-only JSONL

Project status

Phase: multi-domain data collection β€” building the corpora that the cheap local layers will train on.

  • βœ… Per-step loop, cheapest-first cascade, verifier, and all guardrails β€” built & tested
  • βœ… Capture β†’ corpus β†’ coverage pipeline across multiple domains (Facebook, Indeed, …)
  • βœ… Stop-state escalation verified on real reCAPTCHA & 2FA
  • πŸ”œ First trainable model: the page-state classifier (L3)
  • πŸ”œ Continuous retraining β†’ the full self-improving flywheel
Guardrails & safety
  • $5/week autonomous spend cap, enforced before every paid call
  • Human escalation on stop-state, over-budget, low-confidence, no-match, or verifier-fail
  • Record-only by default β€” the loop logs its decided intent and fires nothing until trusted
  • Never auto-solves captchas β€” those are a human gate by design
  • Credentials live only in a git-ignored .env, never logged

Local development

Repo layout

  • apps/controlplane-api β€” FastAPI control plane, training & runtime APIs
  • apps/mcp β€” capture server + observer pipeline (CDP-AX proposer)
  • apps/controlplane-ui β€” Vite/React frontend
  • infra β€” local Postgres & Redis via Docker Compose
  • scripts β€” dev startup, shutdown, health-check helpers

One command

make dev

Starts Postgres, Redis, the Control Plane API (:8081), the Capture Server (:8082), and the UI (:5173). Training Chrome is launched on demand per session from the UI. First run also creates .venv, installs Python deps, and runs npm ci.

make setup     # first-time env setup only
make dev-stop  # stop everything
make doctor    # health check

The virtual environment lives at .venv; the dev scripts call .venv/bin/python directly, so no manual activation is needed.

Then, in the UI

  1. Open Training β†’ create a session (domain Β· goal Β· scenario)
  2. Start Session Chrome
  3. Capture against that session-scoped browser

Built as a study in resource-efficient, self-improving web automation β€” perception, decision, action, and verification as separate, individually-trainable stages.

Contributors

genekyle

848 commits

Languages

Python

82.0%

JavaScript

14.9%

CSS

2.9%