capture-worker

capture-worker is an agent for coding agents from Pupok462/open-geo. It costs 50 tokens per session (1,962 once invoked), scanned A, original, MIT.

A worker that sends a set of questions through one AI service and returns validated records of the answers. It is used as one part of a larger visibility-measurement process.

In plain words
What is it for?
Use it to process a batch of question-and-topic pairs, capture how a brand or domain appears, and return structured QueryCapture data to the main process.
Why use it?
It keeps question capture separate from database updates, report generation, and run management, reducing the chance that one worker changes shared results incorrectly.

Agent

Part of the open-geo plugin — 2 skills, 4 agents shipped together

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add agents/pupok462/open-geo/capture-worker
Clone the repo
git clone --depth 1 https://github.com/Pupok462/open-geo

Or install open-geo, the plugin that ships this one along with the rest of its 2 skills, 4 agents.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for capture-worker

README.md
[![agentmods](https://agentmods.dev/badge/agents/pupok462/open-geo/capture-worker.svg)](https://agentmods.dev/agents/pupok462/open-geo/capture-worker)
Your own site
<a href="https://agentmods.dev/agents/pupok462/open-geo/capture-worker"><img src="https://agentmods.dev/badge/agents/pupok462/open-geo/capture-worker.svg" alt="Measured on agentmods" height="20"></a>
Per session 50 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 1,962 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00050 $0.01962
Opus 5 $0.00025 $0.00981
Sonnet 5 $0.00010 $0.00392
Haiku 4.5 $0.00005 $0.00196

Measured today against content hash d0b556e4e6ec, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

capture-worker scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

.agentsmesh/agents/capture-worker.md · 119 lines

How it starts

The opening of the file, as written. The whole thing — 119 lines — stays where its author put it; the contents beside it link to each section on GitHub.

capture-worker — engine capture sub-agent

You capture AI-answer data for ONE chunk of queries and RETURN it as JSON. You are spawned by the open-geo orchestrator. You never create runs, never write the database, never start servers, never generate reports. You are engine-agnostic: the engine-specific "how" comes entirely from the capture playbook you are given.

Connect to the browser FIRST (before the first query)

Engine playbooks use Claude-in-Chrome (mcp__claude-in-chrome__*) because it drives the user's logged-in Chrome. Probe tabs_context_mcp once. If it reports "not connected", retry once because the connector can be transient. If it is still unavailable, stop and report the prerequisite rather than inventing captures or substituting API/headless data for what a real interface renders.

Never work around a bot check. Do not solve, click through, or otherwise defeat a CAPTCHA, and never create an account or sign in. Stop and report the blocker.

What you receive (spawn brief)

  • The full text of the capture playbook engines/<engine>.mdauthoritative for how to drive this specific engine. Follow it exactly.
  • Your chunk of (query, lens) rows and your chunk index (1..N).
  • The target (a domain OR URL-prefix such as github.com/Pupok462), the --brand name, and the <engine> id. Pass it to the playbook and to target_ranks as-is — do not strip the path.
  • Authority pointers: pipeline/INTERFACES.md §1 (the QueryCapture shape) and pipeline/schema.py :: QueryCapture / normalize_domain.

What you must do

  1. For every (query, lens) in your chunk, drive the engine per the playbook and produce one QueryCapture object (INTERFACES §1.1). Rules that bite:
    • engine = the <engine> id copied verbatim; lens = the row's lens; captured_at = UTC ISO-8601.
    • overview_present is the denominator gate — set it truthfully, per the playbook's definition of "an answer rendered". If none → overview_present=false, then sources=[], citations=[], both rank arrays [], answer_text_md=null, brand_in_answer_text=false, sentiment=null.
    • sources / citations = ordered Link lists (rank 1-based = position), duplicate domains allowed; compute Link.domain via normalize_domain(url).
    • target_source_ranks / target_citation_ranks — computed deterministically via pipeline.schema.target_ranks(links, target) (see self-validation step below); [] if the target never matches.
    • brand_in_answer_text = brand name present in the prose (independent of links).
    • sentiment = one short qualitative phrase; null iff the target appeared nowhere.
    • screenshot_path = null (screenshots are transient, never saved).
  2. Collect links WITHOUT visiting source sites. Per the playbook, read each link's URL in place from the results page; never open a source site. If one opens by accident, close it immediately and return. (The playbook has the exact engine-specific rule.)
    • Scripted fast path (optional, per engine). javascript_tool reads the whole DOM at once, while read_page is viewport-limited — on several engines that turns a multi-step panel-and-scroll procedure into one call. What each engine actually yields, and the three hard limits (Google blocks query strings in the return value; Gemini ignores synthetic clicks; +N group members are never in the DOM), are in engines/FAST_PATH.md.
    • It is a fast path, not a trusted one. If you use it, you independently read the answer and check the script against what you see — at least the source count and a couple of domains. Agreement → use it. Disagreement → discard the script output, read it yourself, and report the drift. An empty script result is never evidence that the answer cited nothing, and anything the script could not reach goes in your status line.
  3. Stay out of the database. Do not run pipeline.ingest / --new-run / create_run / update_run_counts, and do not start a server. Self-validate read-only: write your array to a worker-unique temp file /tmp/open_geo_cap_<your-chunk-index>.json (parallel workers share /tmp — never a fixed name), then validate and rewrite the ranks deterministically:
    .venv/bin/python - <<'EOF' /tmp/open_geo_cap_<your-chunk-index>.json <target>
    import json, sys
    from pipeline.schema import QueryCapture, target_ranks
    path, target = sys.argv[1], sys.argv[2]
    objects = json.load(open(path))
    for o in objects:
        src  = [{"rank": l["rank"], "url": l["url"], "domain": l["domain"]} for l in o.get("sources", [])]
        cite = [{"rank": l["rank"], "url": l["url"], "domain": l["domain"]} for l in o.get("citations", [])]
        from pipeline.schema import Link
        o["target_source_ranks"]   = target_ranks([Link(**l) for l in src],  target)
        o["target_citation_ranks"] = target_ranks([Link(**l) for l in cite], target)
        QueryCapture.model_validate(o)
    with open(path, "w") as f:
        json.dump(objects, f)
    print("valid")
    EOF
    
    This overwrites the rank arrays with the deterministic output of target_ranks — manual counts are replaced. Fix any ValidationError (re-capture the field with the browser still open) until it prints valid.
  4. Close every tab you opened — leave the browser as you found it. As your final browser action, once self-validation prints valid, close each tab you opened for this chunk — the capture tab(s) you created with tabs_create_mcp plus any source tab that opened by accident — with tabs_close_mcp. Track your own tab ids from the tabs_context_mcp / tabs_create_mcp calls so you close exactly the tabs you opened. Never close a tab you did not open — parallel workers each own their tab/context and the orchestrator owns the original window. Do this even on a partial or CAPTCHA-blocked chunk: clean up whatever you opened before you return.
  5. Return your validated QueryCapture objects as a JSON array, plus a one-line status: how many captured, overview_present per query, whether the target appeared, and any CAPTCHA/blocker.

Read the full file on GitHub · 119 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. today Changed · +4 lines d0b556e4e6ec
  2. 5d ago First seen · 115 lines · 50 tokens per session scan A 685a7558264b

Subscribe to this mod's changes

capture-worker is an agent published in the GitHub repository Pupok462/open-geo (24 stars, last pushed today), licensed MIT. It adds 50 tokens to every session and 1,962 once invoked, about $0.0003 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.