Add it to Claude Code
claude mcp add flyto-core -- python -m flyto_core.mcpMake your agent remember this setup
flyto-core's config, env vars, and the gotchas you hit — recalled in every future Claude Code, Cursor, and Codex session.
npx conare@latestFree · one command · indexes the sessions already on disk. Set up in the browser instead →
What it does
- Deterministic execution engine for AI agents
- Full execution tracing with evidence snapshots
- Replay capability from any specific step
- Supports browser automation via Playwright
- Includes 412 modules across 78 categories
Tools 6
browser.launchLaunches a browser instance for automation tasks.browser.gotoNavigates the browser to a specified URL.browser.evaluateExecutes JavaScript code within the browser context.browser.screenshotCaptures a screenshot of the current page.browser.viewportSets the browser viewport dimensions.file.writeWrites data to a local file.Try it
Original README from flytohub/flyto-core
flyto-core
A debuggable automation engine. Trace every step. Replay from any point.
Try in 30 seconds
pip install flyto-core[browser] && playwright install chromium
flyto recipe competitor-intel --url https://github.com/pricing
Step 1/12 browser.launch ✓ 420ms
Step 2/12 browser.goto ✓ 1,203ms
Step 3/12 browser.evaluate ✓ 89ms
Step 4/12 browser.screenshot ✓ 1,847ms → saved intel-desktop.png
Step 5/12 browser.viewport ✓ 12ms → 390×844
Step 6/12 browser.screenshot ✓ 1,621ms → saved intel-mobile.png
Step 7/12 browser.viewport ✓ 8ms → 1280×720
Step 8/12 browser.performance ✓ 5,012ms → Web Vitals captured
Step 9/12 browser.evaluate ✓ 45ms
Step 10/12 browser.evaluate ✓ 11ms
Step 11/12 file.write ✓ 3ms → saved intel-report.json
Step 12/12 browser.close ✓ 67ms
✓ Done in 10.3s — 12/12 steps passed
Screenshots captured. Performance metrics extracted. JSON report saved. Every step traced.
What happens when step 8 fails?
With a shell script you re-run the whole thing. With flyto-core:
flyto replay --from-step 8
Steps 1–7 are instant. Only step 8 re-executes. Full context preserved.
3 recipes to try now
# Competitive pricing: screenshots + Web Vitals + JSON report
flyto recipe competitor-intel --url https://competitor.com/pricing
# Full site audit: SEO + accessibility + performance
flyto recipe full-audit --url https://your-site.com
# Web scraping → CSV export
flyto recipe scrape-to-csv --url https://news.ycombinator.com --selector ".titleline a"
Every recipe is traced. Every run is replayable. See all 32 recipes →
Install
pip install flyto-core # Core engine + CLI + MCP server
pip install flyto-core[browser] # + browser automation (Playwright)
playwright install chromium # one-time browser setup
The 85-line problem
Here's what competitive pricing analysis looks like in Python:
<table> <tr> <td width="50%">Python — 85 lines
import asyncio, json, time
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://competitor.com/pricing")
# Extract pricing
prices = await page.evaluate("""() => {
const cards = document.querySelectorAll(
'[class*="price"]'
);
return Array.from(cards).map(
c => c.textContent.trim()
);
}""")
# Desktop screenshot
await page.screenshot(
path="desktop.png", full_page=True
)
# Mobile
await page.set_viewport_size(
{"width": 390, "height": 844}
)
await page.screenshot(
path="mobile.png", full_page=True
)
# Performance
perf = await page.evaluate("""() => {
const nav = performance
.getEntriesByType('navigation')[0];
return {
ttfb: nav.responseStart,
loaded: nav.loadEventEnd
};
}""")
# Save report
report = {
"prices": prices,
"performance": perf,
}
with open("report.json", "w") as f:
json.dump(report, f, indent=2)
await browser.close()
asyncio.run(main())
</td>
<td width="50%">
flyto-core — 12 steps
name: Competitor Intel
steps:
- id: launch
module: browser.launch
- id: navigate
module: browser.goto
params: { url: "{{url}}" }
- id: prices
module: browser.evaluate
params:
script: |
JSON.stringify([
...document.querySelectorAll(
'[class*="price"]'
)
].map(e => e.textContent.trim()))
- id: desktop_shot
module: browser.screenshot
params: { path: desktop.png, full_page: true }
- id: mobile
module: browser.viewport
params: { width: 390, height: 844 }
- id: mobile_shot
module: browser.screenshot
params: {