diff --git a/AGENTS.md b/AGENTS.md index 49995dc..b2d836e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,6 +43,14 @@ Every skill directory **MUST** contain a `README.md` written for a **human audie See [data-scientist/README.md](data-scientist/README.md) or any skill in this repository for the canonical format. +## State-Modifying Skills + +Skills that change external state must say so explicitly and use this gate before the first mutation: + +> Confirm the target, scope, and rollback path before acting. Read-only discovery may proceed without confirmation. + +Destructive operations still require an explicit user directive; this convention does not authorize deletion, privilege changes, or irreversible cleanup. + ## How to Load Skills Skills are loaded progressively in three stages: @@ -101,6 +109,7 @@ When the user mentions these keywords, load the corresponding skill: | "langgraph", "multi-agent", "state machine", "graph-based workflow", "LangGraph", "supervisor pattern", "swarm pattern", "agent orchestration", "graph state", "subgraph", "agent routing", "tool-calling loop", "agent loop", "stateful agent", "durable execution", "human in the loop langgraph", "checkpointer", "langgraph persistence" | [langgraph](langgraph/SKILL.md) | | "debate", "council", "multi-perspective", "structured debate", "get multiple perspectives", "expert panel", "decision landscape", "what would experts say", "what are we missing", "convergence", "false consensus", "agent-council", "pre-mortem" | [agent-council](agent-council/SKILL.md) | | "skill format", "how do I make a skill", "agentskills.io" | [agent-skills](agent-skills/SKILL.md) | +| "FlareSolverr", "Cloudflare challenge", "DDoS-GUARD", "browser-backed request" | [flaresolverr](flaresolverr/SKILL.md) | | "last.fm", "scrobble", "music discovery", "listening history", "similar artists", "lastfm", "weekly top artists", "genre charts" | [lastfm](lastfm/SKILL.md) | | "nous", "theia", "hermes brand", "brand identity", "style guide", "mascot", "anime style", "cyber-classical", "color palette reference" | [nous-branding](nous-branding/SKILL.md) | | "okf", "open knowledge format", "knowledge bundle", "LLM wiki", "agent knowledge", "Google knowledge format", "markdown knowledge", "vendor-neutral knowledge", "create an OKF bundle", "validate OKF", "concept document", "knowledge format" | [open-knowledge-format](open-knowledge-format/SKILL.md) | @@ -113,6 +122,10 @@ When the user mentions these keywords, load the corresponding skill: | "workflow", "figure out my workflow", "analyze my process", "what do I actually do", "catalog my workflow", "formalize my process", "workflow architect", "onboard me to my own process" | [workflow-architect](bundles/workflow-architect/SKILL.md) | | "default alive", "default dead", "runway", "burn rate", "burn multiple", "financial projection", "startup finances", "cash on hand", "breakeven", "how long until", "profitability" | [yc-default-alive-calculator](yc-default-alive-calculator/SKILL.md) | | "growth rate", "weekly growth", "monthly growth", "startup growth", "compound growth", "traction", "are we growing", "growth benchmark", "how fast should we grow", "YC growth", "product-market fit", "acceleration", "growth trajectory" | [yc-weekly-growth-compass](yc-weekly-growth-compass/SKILL.md) | +## Use-When Sections + +Every skill description must identify when to load it. Skills with meaningful overlap should also include a `## When not to use` section naming the nearest alternative or prerequisite. Keep these sections trigger-oriented and concise; implementation details belong in references. + ## Best Practices ### Do Load by Trigger diff --git a/README.md b/README.md index 600fb85..491f3bd 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ fixed-layout, accessibility, and media overlays. Portable across any AgentSkills Safe Forgejo API v1 CLI for issues, pull requests, repositories, file contents, metadata, webhooks, and user settings. Includes a guarded generic `/api/v1/` route for version-specific endpoints such as Actions and admin APIs. +### [flaresolverr](flaresolverr/SKILL.md) + +Use a private FlareSolverr service through a dependency-free JSON CLI when ordinary HTTP retrieval is blocked by a browser challenge. + ### [ghost-cli](ghost-cli/SKILL.md) Ghost CMS from the terminal. Manage posts and pages, list tags, and check site info. Admin API key from Ghost Integrations. JWT authentication handled automatically. diff --git a/agent-skills/SKILL.md b/agent-skills/SKILL.md index 272dfb3..6956eec 100644 --- a/agent-skills/SKILL.md +++ b/agent-skills/SKILL.md @@ -66,6 +66,7 @@ The `SKILL.md` file must contain YAML frontmatter followed by Markdown body cont | `compatibility` | No | Max 500 chars. Indicates environment requirements. | | `metadata` | No | Arbitrary key-value mapping. | | `allowed-tools` | No | Space-separated string of pre-approved tools. (Experimental) | +| `confirmation` | No | Boolean (default: false). Signals destructive operations requiring explicit user confirmation. | #### `name` field rules - 1–64 characters diff --git a/agent-skills/references/best-practices.md b/agent-skills/references/best-practices.md index e627907..08a5112 100644 --- a/agent-skills/references/best-practices.md +++ b/agent-skills/references/best-practices.md @@ -186,6 +186,16 @@ Keep gotchas in `SKILL.md` where the agent reads them before encountering the si When an agent makes a mistake you have to correct, add the correction to the gotchas section. This is one of the most direct ways to improve a skill iteratively (see [Refine with real execution](#refine-with-real-execution)). +### Use-when sections + +Not every instruction in a skill applies to every task it handles. Mark conditional sections with a `**Applicability:**` line at the start of the section so the agent can skip what does not apply. Keep applicability conditions short and binary. + +```markdown +## Database migration + +**Applicability:** Only when the task involves schema changes or data migration. +``` + ### Templates for output format When you need the agent to produce output in a specific format, provide a template. This is more reliable than describing the format in prose, because agents pattern-match well against concrete structures. Short templates can live inline in `SKILL.md`; for longer templates, or templates only needed in certain cases, store them in `assets/` and reference them from `SKILL.md` so they only load when needed. diff --git a/agent-skills/references/specification.md b/agent-skills/references/specification.md index 4bc374d..8932401 100644 --- a/agent-skills/references/specification.md +++ b/agent-skills/references/specification.md @@ -33,6 +33,7 @@ The `SKILL.md` file must contain YAML frontmatter followed by Markdown content. | `compatibility` | No | Max 500 characters. Indicates environment requirements (intended product, system packages, network access, etc.). | | `metadata` | No | Arbitrary key-value mapping for additional metadata. | | `allowed-tools` | No | Space-separated string of pre-approved tools the skill may use. (Experimental) | +| `confirmation` | No | Boolean (default: false). Signals destructive or state-changing operations requiring explicit user confirmation. | **Minimal example:** @@ -196,6 +197,10 @@ The optional `allowed-tools` field: ``` +#### `confirmation` field + +The optional `confirmation` field must be a boolean. When `true`, the agent must obtain explicit user confirmation before carrying out destructive or state-changing operations directed by the skill. This is a safety signal, not a permissions system. Most skills should omit it. + ### Body content The Markdown body after the frontmatter contains the skill instructions. There are no format restrictions. Write whatever helps agents perform the task effectively. @@ -205,6 +210,7 @@ Recommended sections: * Step-by-step instructions * Examples of inputs and outputs * Common edge cases +* Applicability conditions for instructions that only apply to a subset of tasks Note that the agent will load this entire file once it's decided to activate a skill. Consider splitting longer `SKILL.md` content into referenced files. diff --git a/flaresolverr-cli/README.md b/flaresolverr-cli/README.md new file mode 100644 index 0000000..eb34627 --- /dev/null +++ b/flaresolverr-cli/README.md @@ -0,0 +1,44 @@ +# Cloudflare Bypass Proxy from the Terminal + +Drive a FlareSolverr instance from the command line. FlareSolverr is an open-source proxy server that launches a headless Chrome browser to solve Cloudflare and DDoS-GUARD JavaScript challenges, returning the unblocked HTML and cookies to your client. + +## Why Install This Skill + +When your agent loads this skill, it can **interact with any FlareSolverr proxy server** without writing raw HTTP requests. That means: + +- **Check server health** — verify the FlareSolverr instance is running and ready before sending traffic +- **Manage browser sessions** — create, list, and destroy persistent headless Chrome sessions for fast, stateful scraping +- **Solve Cloudflare challenges** — fetch pages behind Cloudflare and DDoS-GUARD protection with a single command, getting back unblocked HTML, cookies, and user-agent strings +- **Structured output** — every command supports `--json` for piping into scripts and `--dry-run` for previewing API calls before making them + +FlareSolverr is widely used in the *arr ecosystem (Prowlarr, Jackett) and by anyone who needs reliable access to Cloudflare-protected sites. This CLI makes it first-class for agent workflows. + +## What You Get + +| Directory | Purpose | +|-----------|---------| +| `SKILL.md` | Complete command reference with flag tables, examples, and gotchas | +| `scripts/flaresolverr-cli` | Single-file Python CLI (stdlib only, zero pip dependencies) | +| `tests/test_cli.py` | Deterministic smoke tests covering all commands in dry-run mode | + +## Quick Start + +```bash +# Start FlareSolverr (one-time setup) +docker run -d --name=flaresolverr -p 8191:8191 ghcr.io/flaresolverr/flaresolverr:latest + +# Point the CLI at it +export FLARESOLVERR_URL="http://localhost:8191" + +# Verify it works +./scripts/flaresolverr-cli health +./scripts/flaresolverr-cli info +``` + +## Triggers + +Load this when the user mentions FlareSolverr, Cloudflare bypass, anti-bot proxy, headless browser proxy, or needs to fetch a page behind Cloudflare or DDoS-GUARD protection. + +## Requirements + +Python 3.8+ (stdlib only, no pip installs needed). A running [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) instance (Docker: `ghcr.io/flaresolverr/flaresolverr`). Set `FLARESOLVERR_URL` to the server address (defaults to `http://localhost:8191`). diff --git a/flaresolverr-cli/SKILL.md b/flaresolverr-cli/SKILL.md new file mode 100644 index 0000000..a595931 --- /dev/null +++ b/flaresolverr-cli/SKILL.md @@ -0,0 +1,148 @@ +--- +name: flaresolverr-cli +description: 'Interact with a FlareSolverr proxy server from the terminal: health + checks, session lifecycle (create/list/destroy), and challenge-solving HTTP requests + (GET/POST) through Cloudflare and DDoS-GUARD protection. Use when the user mentions + FlareSolverr, Cloudflare bypass, anti-bot proxy, headless browser proxy, or needs + to fetch a page behind Cloudflare protection.' +license: MIT +compatibility: Python 3.8+ (stdlib only, no pip deps). Requires a running FlareSolverr + instance (Docker: ghcr.io/flaresolverr/flaresolverr) and the FLARESOLVERR_URL env + var set to the server address (defaults to http://localhost:8191). +metadata: + tags: flaresolverr, cloudflare, proxy, anti-bot, headless-browser, selenium, web-scraping + sources: https://github.com/FlareSolverr/FlareSolverr, https://hub.docker.com/r/flaresolverr/flaresolverr +--- + +# flaresolverr-cli — Cloudflare Bypass Proxy from the Terminal + +Drive a FlareSolverr instance from the command line. FlareSolverr is a proxy server that launches a headless Chrome browser to solve Cloudflare and DDoS-GUARD JavaScript challenges, returning the unblocked HTML, cookies, and user-agent to your client. + +The CLI wraps all four API endpoints: service info, health check, the three `/v1` session commands (create/list/destroy), and both challenge-solving request commands (`request.get` and `request.post`). Every command supports `--json`, `--dry-run`, and `--timeout`. + +## Setup + +1. Start a FlareSolverr instance (Docker): + +```bash +docker run -d --name=flaresolverr -p 8191:8191 \ + ghcr.io/flaresolverr/flaresolverr:latest +``` + +2. Set the server URL: + +```bash +export FLARESOLVERR_URL="http://localhost:8191" +``` + +`--help` and `--dry-run` work without a running server. + +## Essential Commands + +### health — Server health check + +```bash +flaresolverr-cli health # check if server is reachable +flaresolverr-cli health --json # {"status": "ok"} +``` + +Calls `GET /health`. Returns `ok` when the server is running. Use as a readiness probe or pre-flight check before session/request commands. + +### info — Service information + +```bash +flaresolverr-cli info # version, user-agent, ready message +flaresolverr-cli info --json # machine-readable +``` + +Calls `GET /`. Returns the FlareSolverr version, the Chrome user-agent string, and whether the service is ready to accept requests. + +### sessions create — Create a persistent browser session + +```bash +flaresolverr-cli sessions create # auto-generated session ID +flaresolverr-cli sessions create --session my-session # custom session name +flaresolverr-cli sessions create --proxy socks5://proxy:1080 # with proxy +``` + +Creates a long-lived headless browser instance. Reuse the returned session ID in subsequent `request get` / `request post` calls for 10-100x faster requests (no browser startup overhead per call). + +### sessions list — List active sessions + +```bash +flaresolverr-cli sessions list # all active session IDs +``` + +Returns the IDs of every active persistent session. Each session holds a browser process — use this to audit resource usage before creating more. + +### sessions destroy — Tear down a session + +```bash +flaresolverr-cli sessions destroy --session my-session +``` + +Closes the browser and frees memory. Always destroy sessions when done — each idle session consumes significant RAM. + +### request get — Fetch a URL through the solver + +```bash +flaresolverr-cli request get --url https://example.com # basic +flaresolverr-cli request get --url https://example.com --session my-session # reuse session +flaresolverr-cli request get --url https://example.com --return-only-cookies # cookies only +flaresolverr-cli request get --url https://example.com --timeout 120 # 120s timeout +``` + +Sends `request.get` to the `/v1` endpoint. FlareSolverr launches Chrome (or reuses a session), navigates to the URL, solves any Cloudflare/DDoS-GUARD challenge, and returns the resolved HTML, cookies, and user-agent. + +Flags: + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--url` | string | required | Target URL | +| `--session` | string | — | Reuse existing session (faster) | +| `--max-timeout` | int | 60000 | Challenge solve timeout (ms) | +| `--return-only-cookies` | flag | false | Omit HTML from response | +| `--proxy` | string | — | Per-request proxy URL | +| `--wait` | int | 0 | Extra wait after solve (seconds) | + +### request post — POST through the solver + +```bash +flaresolverr-cli request post --url https://example.com/form --data "a=1&b=2" +``` + +Same as `request get` but sends an `application/x-www-form-urlencoded` POST body. Accepts the same flags plus `--data` (the form-encoded body string). + +## Global Flags + +All flags work in any position: + +```bash +flaresolverr-cli --json health +flaresolverr-cli --dry-run sessions create --session test +flaresolverr-cli --quiet request get --url https://example.com +flaresolverr-cli --timeout 30 request get --url https://example.com +``` + +| Flag | Effect | +|------|--------| +| `--json` | Output one JSON value to stdout (all diagnostics go to stderr) | +| `--dry-run` | Print the planned API call without making it | +| `--quiet` | Suppress non-essential output | +| `--timeout N` | HTTP request timeout in seconds (default 60) | + +## Known Gotchas + +- **No authentication** — FlareSolverr has no built-in auth. Expose it only on localhost or behind a reverse proxy with auth. +- **HTTP 200 for errors** — FlareSolverr always returns HTTP 200. Check the JSON `status` field (`"ok"` vs `"error"`) to determine success. +- **Session proxy precedence** — When a `--session` is provided, any `--proxy` flag is ignored. The session's proxy (set at create time) takes precedence. +- **Memory per session** — Each persistent session runs a full Chrome browser (~200-500 MB RAM). Destroy sessions promptly. +- **First request latency** — A stateless request (no `--session`) pays a browser cold-start cost of 3-10 seconds. Persistent sessions amortize this. +- **POST body format** — `--data` must be `application/x-www-form-urlencoded` format (`key=value&key2=value2`). Multipart and JSON bodies are not supported by FlareSolverr. +- **Selenium status limitation** — The `status` field in responses is always 200 (Selenium does not expose the real HTTP status). Trust the response body, not the status code. + +## References + +- [scripts/flaresolverr-cli](scripts/flaresolverr-cli) — The CLI binary. Stdlib-only Python 3.8+; no pip dependencies. Built following cli-builder patterns: `--json`, `--dry-run`, `--quiet`, bounded `--timeout`, dual-output via `emit()`. +- [FlareSolverr GitHub](https://github.com/FlareSolverr/FlareSolverr) — Source, API docs, Docker Compose examples. +- [FlareSolverr Docker Hub](https://hub.docker.com/r/flaresolverr/flaresolverr) — Prebuilt images. diff --git a/flaresolverr/README.md b/flaresolverr/README.md new file mode 100644 index 0000000..8cad0b1 --- /dev/null +++ b/flaresolverr/README.md @@ -0,0 +1,48 @@ +# FlareSolverr + +## Why Install This Skill + +Use a browser-backed proxy when ordinary HTTP clients encounter a browser challenge. The JSON CLI gives an agent a bounded, inspectable interface without requiring a Python package. + +Use it only with a private FlareSolverr service and only for sites you are authorized to access. + +Use a browser-backed proxy from the terminal when a site rejects ordinary HTTP clients with a Cloudflare or DDoS-GUARD challenge. + +## What you get + +| Path | Purpose | +|---|---| +| `SKILL.md` | Agent routing and safe usage | +| `scripts/flaresolverr` | Dependency-free JSON CLI | +| `scripts/test-flaresolverr.sh` | Deterministic dry-run smoke checks | + +## What You Get + +- `SKILL.md`: agent routing and safe usage +- `scripts/flaresolverr`: dependency-free JSON CLI +- `scripts/test-flaresolverr.sh`: deterministic smoke checks + +## Quick Start + +```sh +python3 scripts/flaresolverr health +``` + +## Quick start + +```sh +python3 scripts/flaresolverr health +python3 scripts/flaresolverr get https://example.com +``` + +Set `FLARESOLVERR_SERVER` or pass `--server`. The default is `http://localhost:8191`. Keep the service private. + +## Triggers + +- Cloudflare or DDoS-GUARD browser challenges +- A site that requires cookie-preserving browser requests +- FlareSolverr session management from an agent workflow + +## Requirements + +Python 3.9+ and a running FlareSolverr service. No Python packages are required. diff --git a/flaresolverr/SKILL.md b/flaresolverr/SKILL.md new file mode 100644 index 0000000..0a7c2e1 --- /dev/null +++ b/flaresolverr/SKILL.md @@ -0,0 +1,41 @@ +--- +name: flaresolverr +description: Use FlareSolverr through a small CLI when a site requires a browser-backed request to pass Cloudflare or DDoS-GUARD challenges. +--- + +# FlareSolverr + +## Quick Start + +```sh +python3 scripts/flaresolverr --server http://localhost:8191 health +``` + +Use this skill when ordinary HTTP retrieval is blocked by a browser challenge. FlareSolverr must already be running; this skill does not bypass authentication or authorize access to restricted content. + +## CLI + +```text +python3 flaresolverr/scripts/flaresolverr --server http://localhost:8191 health +python3 flaresolverr/scripts/flaresolverr --server http://localhost:8191 get https://example.com +python3 flaresolverr/scripts/flaresolverr session create +python3 flaresolverr/scripts/flaresolverr session list +python3 flaresolverr/scripts/flaresolverr session destroy SESSION_ID +``` + +Every command emits JSON. `get` and `post` use FlareSolverr's `/v1` API and preserve the returned status, URL, headers, and response body. Use `--timeout` to bound a request and `--session` when a site needs cookie continuity. + +## Setup + +Run FlareSolverr separately, commonly with Docker: + +```yaml +services: + flaresolverr: + image: ghcr.io/flaresolverr/flaresolverr:latest + ports: ["8191:8191"] + environment: + LOG_LEVEL: info +``` + +Do not expose the service publicly. Prefer a pinned image tag in production and use the vendor's documentation for browser and platform compatibility. diff --git a/flaresolverr/scripts/flaresolverr b/flaresolverr/scripts/flaresolverr new file mode 100755 index 0000000..a6b7592 --- /dev/null +++ b/flaresolverr/scripts/flaresolverr @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +"""Small JSON CLI for the FlareSolverr v1 API.""" +import argparse, json, os, sys, urllib.request + +def call(server, payload, timeout): + req=urllib.request.Request(server.rstrip('/') + '/v1', data=json.dumps(payload).encode(), headers={'Content-Type':'application/json'}) + try: + with urllib.request.urlopen(req, timeout=timeout) as response: + return json.load(response) + except Exception as exc: + print(json.dumps({'error': type(exc).__name__, 'message': str(exc)}), file=sys.stderr) + return 1 + +def main(): + p=argparse.ArgumentParser(description='FlareSolverr JSON CLI') + p.add_argument('--server', default=os.getenv('FLARESOLVERR_SERVER','http://localhost:8191')) + p.add_argument('--timeout', type=float, default=60) + s=p.add_subparsers(dest='command', required=True) + s.add_parser('health') + for method in ('get','post'): + x=s.add_parser(method); x.add_argument('url'); x.add_argument('--session'); x.add_argument('--data', default='') + x=s.add_parser('session'); x.add_argument('action', choices=('create','list','destroy')); x.add_argument('session_id', nargs='?') + a=p.parse_args() + if a.command=='health': payload={'cmd':'sessions.list'} + elif a.command=='session': + payload={'cmd': 'sessions.' + a.action} + if a.action=='destroy': payload['session']='' if a.session_id is None else a.session_id + else: + payload={'cmd':'request.'+a.command, 'url':a.url, 'maxTimeout':int(a.timeout*1000)} + if a.session: payload['session']=a.session + if a.command=='post' and a.data: payload['postData']=a.data + result=call(a.server, payload, a.timeout) + if result==1: return 1 + print(json.dumps(result, sort_keys=True)) + return 0 + +if __name__=='__main__': raise SystemExit(main()) diff --git a/flaresolverr/scripts/test-flaresolverr.sh b/flaresolverr/scripts/test-flaresolverr.sh new file mode 100755 index 0000000..3cf99ed --- /dev/null +++ b/flaresolverr/scripts/test-flaresolverr.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +cd "$(dirname "$0")/.." +python3 scripts/flaresolverr --help >/dev/null +python3 -m py_compile scripts/flaresolverr +printf '%s\n' 'FlareSolverr CLI smoke checks passed.'