agentleFS
DeiblerDeibler/edmund-harness/skills/cloudflare/SKILL.md

cloudflare

Skill24 starsChanged 2 months agoMITView on GitHub

Headless browser automation via Cloudflare Browser Run — screenshot pages, render PDFs, extract markdown/HTML/links, scrape DOM elements with CSS selectors, or AI-extract structured JSON. Runs real Chrome on Cloudflare's global network; handles JavaScript-heavy SPAs. All outputs are saved to the sandbox under cloudflare/<type>/.

69 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use nextjs-on-cloudflare, basin and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • CloudflareSkill

    nextjs-on-cloudflare

    Build, migrate, and deploy Next.js apps on Cloudflare Workers with vinext. Use when starting a Next.js project on Cloudflare, moving an existing app to Workers, choosing between vinext and OpenNext, or setting up vinext for Workers. For setup, migration, or deployment, install vinext's upstream skills with `npx skills add cloudflare/vinext` if missing, then read and follow the applicable skill and docs.

    Also in 5 projects that use this

  • CloudflareSkill

    basin

    Build and troubleshoot Cloudflare Basin analytics workflows with Basin Pipelines, Basin Catalog, and Basin SQL. Use for streaming data into R2 Iceberg tables, managing catalogs, or querying those tables; also use for requests using the former Data Platform, Pipelines, R2 Data Catalog, or R2 SQL names.

    Also in 5 projects that use this

  • hoodiniSkill

    analytics-metrics

    Build data visualization and analytics dashboards. Use when creating charts, KPI displays, metrics dashboards, or data visualization components. Triggers on analytics, dashboard, charts, metrics, KPI, data visualization, Recharts.

    Also in 3 projects that use this

  • hoodiniSkill

    aws-account-management

    Manage AWS accounts, organizations, IAM, and billing. Use when setting up AWS Organizations, managing IAM policies, controlling costs, or implementing multi-account strategies. Triggers on AWS Organizations, AWS IAM, AWS billing, Cost Explorer, SCPs, multi-account, AWS SSO, Identity Center.

    Also in 3 projects that use this

  • OpenAISkill

    sandbox-sdk

    Build sandboxed applications for secure code execution. Load when building AI code execution, code interpreters, CI/CD systems, interactive dev environments, or executing untrusted code. Covers Sandbox SDK lifecycle, commands, files, code interpreter, and preview URLs. Biases towards retrieval from Cloudflare docs over pre-trained knowledge.

    Also in 10 projects that use this

  • +4 more from hoodini
  • +3 more from cloudflare

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 3 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 59 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run real Chrome on Cloudflare's global network.

    line 8
  2. Very specific:

    All files are saved with a <timestamp>-<url-slug>.<ext> filename inside the sandbox.

    line 23
  3. Very specific:

    Every CF tool accepts async: true.

    line 40
  4. Distinctive:

    All tools return the local sandbox path of the saved file.

    line 97
  5. Very specific:

    JSON / HTML: if the user wants to see it, send_attachment(path) or summarize inline.

    line 102
  6. Very specific:

    If you get empty or incomplete results, add wait_until: "networkidle0":

    line 108
  7. Distinctive:

    Keep organized — don't let the directory grow unbounded across long sessions.

    line 184

“Common” is measured: kept by at least 6 in 10 of the 59 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

cloudflare — Browser Run

Run real Chrome on Cloudflare's global network. No Puppeteer setup, no headless browser to manage. One tool call, one output file.

Tool reference

ToolWhat it doesOutput dir
cf_screenshotFull-page or viewport screenshot (PNG)cloudflare/screenshot/
cf_pdfRender page or HTML as PDFcloudflare/pdf/
cf_markdownExtract clean Markdown (strips nav, ads, scripts)cloudflare/markdown/
cf_contentFull rendered HTML after JS executioncloudflare/content/
cf_snapshotScreenshot + HTML in one callcloudflare/screenshot/ + cloudflare/html/
cf_linksAll links (or visible-only / same-domain)cloudflare/json/
cf_scrapeDOM element data by CSS selectorcloudflare/json/
cf_jsonAI-powered structured data extractioncloudflare/json/

All files are saved with a <timestamp>-<url-slug>.<ext> filename inside the sandbox.

async: true — works for ALL slow tools

The async: true pattern is generic across the harness. It works for:

  • All cf_* tools (screenshot, pdf, markdown, content, snapshot, links, scrape, json)
  • generate_image, generate_video, generate_audio
  • transcribe_audio (for long audio)
  • web_fetch (for slow / large fetches)

Whenever a tool is slow enough to make the user wait, pass async: true. Same mechanic everywhere: detached worker, cron wake-up, result in the envelope.

⚠️ Always pass async: true

Every CF tool takes 15-90 seconds. Calling them synchronously holds the session lock — the user gets zero responses until the tool returns. Never do this.

Every CF tool accepts async: true. When set, the tool:

  1. Spawns a detached worker process that makes the actual API call
  2. Returns immediately with a background job id (session lock releases instantly)
  3. Saves the output to the sandbox as the worker completes
  4. Fires an automatic wake-up event in this session once done — you get invoked again with the result path in the envelope

The correct pattern:

user: "screenshot example.com"
edmund: send_message("on it, give me a sec")
        cf_screenshot({ url: "https://example.com", full_page: true, async: true })
          → "Background job started: bg_xyz123. ... End your turn now."
        [TURN ENDS]  ← session lock released, user can keep messaging

[worker runs, saves PNG, fires wake-up cron]

edmund wakes up with event:
        "Background tool job finished (status: done). ... Saved: /path/to/screenshot.png"
edmund: send_attachment("/path/to/screenshot.png", "here you go")

Never do this:

edmund: cf_screenshot({ url: "...", full_page: true })   ← NO async:true, blocks session 30-90s

Rule: if in doubt, pass async: true. Inline sync mode is only for rare cases where you need the result within the same turn (e.g., you're already mid-chain and need the data to continue a calculation). For user-facing "fetch/capture/extract X", it's always async.

check_bg_job / list_bg_jobs

You usually don't need these — completed background jobs wake you up automatically with the result included. But:

  • list_bg_jobs — see what's currently running ("what are you working on?")
  • check_bg_job(id) — inspect a specific job's status

When to use which tool

Reading an article or doc? → cf_markdown. Returns the content inline + saves to disk. Cheapest and fastest.

Need the visual? → cf_screenshot. Returns path only — follow up with send_attachment(path) to share.

Generating a report or invoice from HTML? → cf_pdf. Always use send_attachment(path) to share.

JS-heavy page (SPA, React, Vue)? → add wait_until: "networkidle0" to any tool. This waits for all network activity to settle before capturing.

Full DOM including dynamically injected elements? → cf_content. Saves rendered HTML; use the Read tool to inspect it.

Both screenshot and HTML at once? → cf_snapshot. Single API call, two output files.

Site mapping, crawl seeding, link auditing? → cf_links. Use visible_only: true to skip hidden/footer links; exclude_external: true to stay on-domain.

Scraping specific data fields? → cf_scrape with CSS selectors for precise extraction without AI overhead.

Structured data in a known shape? → cf_json with a schema. For less structured extraction, use prompt alone.

Delivery

All tools return the local sandbox path of the saved file. To share with the user:

  • Images / screenshots: send_attachment(path) — iMessage delivers inline.
  • PDFs: send_attachment(path) — iMessage delivers as downloadable.
  • Markdown: already returned inline, no attachment needed for short content.
  • JSON / HTML: if the user wants to see it, send_attachment(path) or summarize inline.

Never just print the path and say "here's the file" — the user can't see your filesystem.

JavaScript-heavy pages

If you get empty or incomplete results, add wait_until: "networkidle0":

cf_markdown({ url: "https://app.example.com/dashboard", wait_until: "networkidle0" })

For very slow pages, try "networkidle2" (waits for ≤2 open connections instead of 0).

Sending a screenshot example

1. cf_screenshot({ url: "https://example.com", full_page: true })
   → saved to /sandbox/cloudflare/screenshot/2026-04-20T12-30-00-example-com.png

2. send_attachment("/sandbox/cloudflare/screenshot/2026-04-20T12-30-00-example-com.png",
                   "here's the screenshot")

AI JSON extraction example

Extract product info:

cf_json({
  url: "https://store.example.com/product/123",
  prompt: "Get the product name, price, availability status, and SKU",
  schema: {
    type: "object",
    properties: {
      name: { type: "string" },
      price: { type: "number" },
      available: { type: "boolean" },
      sku: { type: "string" }
    }
  }
})

Extract with prompt only (less structured):

cf_json({
  url: "https://news.ycombinator.com",
  prompt: "Get the top 5 story titles and their point counts"
})

CSS scraping example

cf_scrape({
  url: "https://news.ycombinator.com",
  selectors: [".titleline > a", ".score"]
})

Returns text, HTML, and attributes for each matching element.

Sub-agent usage

Sub-agents have the same tool palette. When an agent calls cf_screenshot, cf_pdf, etc., the output goes into the agent's own sandbox (<parent-sandbox>/agents/<id>/cloudflare/<type>/).

To run browser capture in the background and surface the result:

spawn_agent(task: "Screenshot https://example.com full-page and return the file path")

The agent calls cf_screenshot, writes the result, and returns the path in its final text. You then read_agent_result(id) and send_attachment(path).

Output cleanup

Files accumulate in cloudflare/ over time. To clean up stale captures:

ls cloudflare/screenshot/    # see what's there
rm cloudflare/screenshot/2026-04-18*   # remove specific date

Keep organized — don't let the directory grow unbounded across long sessions.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.