Unbroker: Automate Data Broker Opt-Outs with Hermes Agent
Autonomously remove your info from data-broker sites.
Written by Neura Market from the official Hermes Agent documentation for Unbroker. Commands, paths, and version numbers are reproduced from the source unchanged.
Read the official documentationUnbroker is a Hermes Agent skill that finds where a person's personal information, such as name, addresses, phone, email, and relatives, is exposed on data brokers and people-search sites, then removes it. It automates the opt-out process where possible, and guides human steps only when a site demands a CAPTCHA, government ID, phone call, or fax. You would reach for this if you need to clean up after a doxxing, reduce your digital footprint, or set up recurring privacy monitoring for yourself or a family member.
What it does
Unbroker manages the entire opt-out lifecycle for multiple people independently. It maintains a deterministic state through a Python CLI (scripts/pdd.py), which handles configuration, dossiers with recorded consent, the broker database, tier planning, a ledger, drafts, reports, email sending via SMTP, verification-link polling via IMAP, and an autonomous action queue. The agent performs scanning and form-driving with native tools: web_extract and browser_navigate for searching and web forms, and cronjob for recurring re-scans.
The skill is designed to run hands-off. After intake with recorded consent, there are exactly two legitimate human touchpoints: the intake conversation itself, and one consolidated human-task digest at the end of the run. Between those, the agent never asks the operator to choose configuration, never pauses before individual submissions when autonomy is full, and never interrupts the run for human-only work. Instead, it records such work and surfaces it once in the final digest.
The hard limits that autonomy never overrides: no acting without recorded consent, no disclosure beyond the planned fields, no CAPTCHA or anti-bot bypass, and confirmed_removed only after a verifying re-scan.
Before you start
Unbroker requires python with only the standard library; no extra packages are needed for the core engine. The skill works zero-config without optional upgrades, but setup --auto turns on every upgrade it detects, reading credentials from the shell environment and from $HERMES_HOME/.env so keys Hermes already loads for its own tools are picked up without re-exporting.
Optional upgrades include:
- Cloud browser (recommended default):
BROWSERBASE_API_KEY. When present,setup --autoselects it as the baseline. A real residential-IP cloud browser clears soft or managed CAPTCHAs, such as Cloudflare Turnstile or hCaptcha/reCAPTCHA checkbox, as normal operation, keeping those brokers automated. This is not CAPTCHA solving; no solver service or fingerprint spoofing. Hard interactive or behavioral challenges fall back to a human task. Without the key, the plain agent browser is used and soft-CAPTCHA brokers drop to human tasks. - Email automation, with two options:
- Browser mode (no password):
setup --email-mode browser. The agent sends opt-out or CCPA emails and opens verification links through the operator's logged-in webmail using browser tools. Nothing is stored. This requires Hermes to be pointed at the operator's own logged-in browser, not a cloud browser, because a headless cloud browser holds no webmail session and is itself gated on webmail and session-bound broker gates. Drive the operator's real Chrome over CDP by launchingchrome --remote-debugging-port=9222 --user-data-dir="$HOME/.hermes/chrome-debug"(a dedicated debug profile signed into the webmail once, not the Default profile) and connect the browser tools to127.0.0.1:9222. The$PDD cdpcommand launches this for you. Falls back to drafts for an email if the inbox isn't reachable. - SMTP/IMAP (stored creds):
EMAIL_ADDRESS+EMAIL_PASSWORD(+EMAIL_SMTP_HOST/EMAIL_IMAP_HOSTfor non-mainstream providers; gmail/outlook/yahoo/icloud/fastmail inferred). The CLI sends viasend-emailand reads verify links viapoll-verification. Theagentmailskill also counts.
- Browser mode (no password):
- Google Sheets tracker: the
google-workspaceskill. - The
scraplingskill for stealth or Cloudflare-protected pages.
Run everything through the terminal tool, not execute_code, because that sandbox scrubs env and redacts output, which breaks reading the dossier. The engine stores data under $PDD_DATA_DIR (default $HERMES_HOME/unbroker), written with 0600 permissions.
Setup and readiness
Start with autonomous setup. This detects capabilities and picks the most autonomous valid config without asking questions. Then run a readiness check.
PDD="python scripts/pdd.py"
$PDD setup --auto
$PDD doctor
The doctor command shows config, broker count, and which upgrades are on or available. It also shows whether encryption is actually engaged, not just whether age is installed.
Intake and consent
The intake conversation is the one human conversation in the whole run. Collect everything in one pass: names, aliases, current and prior cities, emails, and phones. Consent is mandatory; without it the engine refuses to plan or act.
$PDD intake --full-name "..." [--alias ...] [--email ... --phone ...] [--city --state] [--prior-location "City,ST"] --consent
This creates a consenting subject and prints a subject_id. For California subjects, also read references/legal/drop.md: next will surface a drop_submit one-shot that deletes from every registered broker at once, which is the single highest-use action. File it, then record it.
$PDD drop [--filed]
For non-CA subjects, the registry is covered by targeted CCPA or GDPR emails, and the people-search sites are worked directly.
The autonomous loop
The core of Unbroker is a loop over next, which returns the exact ordered actions to take right now. Execute every action, record outcomes, re-run next, and repeat until it returns no actions.
$PDD next
while true:
q = $PDD next <subject>
if q.actions is empty: break
execute EVERY action in order; record each outcome via $PDD record
next emits, in order: refresh_brokers (stale cache), fanout_scan or scan_inline (Phase 1 crawl), poll_verification (in-flight email confirmations), verify_removal (due re-checks), optout_web_form or optout_email_send (Phase 2, parents-first with playbook steps), indirect_email_send, and stealth_rescan. Human-only work never appears as an action; it accumulates in the human digest. In autonomy=full, execute actions without pausing; honor confirm_first in assisted mode.
Broker database and planning
Unbroker ships with a curated broker database that can be refreshed. The registry covers state-level data broker registries, which are a separate lane from scanned people-search sites.
$PDD brokers [--priority crucial]
$PDD refresh-brokers
$PDD registry [--search NAME]
Planning determines per-broker tier, method, search vectors, and the exact fields to disclose. The batch view overlays ledger state and groups brokers by next action.
$PDD plan [--priority crucial]
$PDD plan --batch
The batch plan collapses ownership clusters, so a parent removal that clears children is one action, not many. It orders found cluster-parents-first and emits a tailored parent_playbook. The phase is discover while anything is unscanned, otherwise delete.
Batch operation: two-phase crawl and delete
For anything past a couple of brokers, run this as map, reduce, act, not broker-by-broker.
Phase 1: Discover (read-only, parallel, idempotent)
Crawl every broker first and record a verdict for each: found, not_found, indirect_exposure, or blocked. Scanning has no side effects, so it is safe to parallelize and retry. The parent drives web_extract probes directly for most sites, since people-search sites often render results as static HTML. Escalate to browser_* only for JS-only sites, and to delegate_task subagents only for reasoning-heavy work like large-scale namesake disambiguation.
Do not hand a browser-toolset subagent a big list of brokers to crawl; in the field this timed out repeatedly because browser navigation is heavy. A blocked site is not a subagent job either; record blocked and requeue it for a stealth or cloud browser pass. Subagent reports are self-reports; the parent re-fetches key URLs to confirm a found before trusting it.
For fanout_scan, run the fanout command and spawn one subagent per batch in parallel, passing each batch's ready-made brief.
$PDD fanout [--priority crucial] [--size 5]
For scan_inline, scan the few brokers yourself. Either way, each broker gets every search_vectors entry via the methods ladder: web_extract, site: probe, browser_navigate, then scrapling. A 404 is inconclusive, not not_found. Record blocked when antibot is set and no stealth browser is available. Confirm subject versus namesake or relative before recording.
$PDD record [--found true] [--evidence JSON] [--disclosed F --channel C] [--reason "..."]
Reduce: plan --batch
This collapses the crawl into a phase-oriented plan. It groups by next action, collapses ownership clusters, and prints next_actions.
Phase 2: Delete (sequential, irreversible)
Work the reduced groups parents first. Do the cluster parents, skipping the covered children, then re-scan each parent's children after it confirms. Send indirect_exposure cases as CCPA or GDPR delete-my-PII emails. Defer blocked to the stealth-browser pass. Opt-outs hit CAPTCHAs, email-verification loops, and session binding; work them one at a time, carefully, but do not stop to ask permission per submission in autonomy=full. In assisted, confirm each one.
Usually prefer deletion over suppression where a broker offers both, but follow the record's deletion.prefer. PeopleConnect is the exception: deleting your user data removes your suppressions and does not stop public-records re-listing, so you suppress-and-maintain instead.
Blind opt-out is the default, not a fallback. Submit an opt-out or deletion on every site with an accessible removal channel, even when a listing was not first confirmed, because it discloses only the subject's own identifiers to the broker's own official channel. A guided flow that matches email, DOB, and name and says "no results" is a stronger not_found than any scrape. When a form is automation-hostile, default to the broker's cited rights-request email rather than recording blocked. CAPTCHA policy: never defeat behavioral, token, or slider challenges; it is acceptable to read a static distorted-text or plain-arithmetic CAPTCHA on the subject's own opt-out, but stop if the site rejects the whole submission after a correct answer, because it is fingerprinting the automation. Third-party or indirect records are the exception; still confirm those before acting.
PeopleConnect delete-wipes-suppression is a permanent rule. A PeopleConnect deletion wipes the suppression and the subject re-lists across the whole affiliate cluster. If a "Your deletion request for PeopleConnect.us is Complete" email ever appears, the suppression is gone, so re-run suppression and re-verify the Control step reads "suppressed". Never leave this cluster on a completed deletion.
Executing opt-outs
When next says so, actions come pre-ordered parents-first with steps from each broker record's own optout.playbook. Deletion usually beats suppression. When an action carries prefer_deletion, complete the record's deletion lane, not just the hide-my-listing flow. When it carries prefer_suppression instead, as with PeopleConnect, do the suppression flow and keep it maintained; use their Delete button only for a deliberate data-purge.
Per method:
- web_form: drive
optout_urlwithbrowser_navigate,browser_type, andbrowser_click, submit onlydisclosure_fields, screenshot the confirmation, then run the action'safterrecord command. Playbooks may end with a right-to-delete email follow-up; do it for full erasure. - email: use
send-emailto render and record the request in one step. The recipient is locked to the broker's own address.nextpicks the kind from residency; never claim CCPA or GDPR for someone who cannot. In browser mode it returns a recipient-lockedcomposepayload to send via webmail; in programmatic mode it SMTP-sends.nextalso routes human-gated forms through a broker's deletion email when one exists, the rescue lane. Draft-only falls back torender-emailplus a digest entry.
$PDD send-email --listing [--kind ccpa_indirect ...]
$PDD render-email --listing
- captcha: soft or managed challenges clear automatically on the default cloud browser; proceed as normal. Only a hard interactive or behavioral challenge it cannot pass is recorded
blocked, requeued for the stealth or operator-browser pass. Never use a solver service. - phone_callback / account / gov_id / fax / mail / voice without a deletion email: never an agent action;
nextalready routed these to the digest. Record them as human tasks.
$PDD record human_task_queued --reason "..."
Verification
Verification confirms that a removal actually happened. In programmatic mode, poll IMAP for verification links. In browser mode, extract a broker's verification link from webmail text you read.
$PDD poll-verification [--broker ]
$PDD verify-link --text ''
Either way, open the link in the same browser, because several brokers bind the verification session to the browser that opens it. Finish the flow, then record awaiting_processing. Mark confirmed_removed only after a verifying re-scan shows the listing gone, never off the submission flow's own confirmation page.
Wrap-up and scheduling
When next returns no actions, present the consolidated human digest if non-empty, then the status report. If the Sheets tracker is on, append rows via the google-workspace skill.
$PDD tasks
$PDD status
$PDD report --sheets
next returns next_wake_at, the earliest due re-check. Create one cronjob that re-runs this skill's loop for the subject, with a prompt like: "run the unbroker loop for : $PDD next and execute all actions". Processing windows, verification polls, and reappearance sweeps all flow through the same queue, so the case keeps advancing with zero human attention.
When not to use it
Unbroker does not defeat anti-bot systems, does not act on anyone without recorded consent, and does not remove public records such as voter, property, or court records, or accounts the person controls. If the goal is to remove public records or accounts the person controls, this skill is not the right tool. Also, if the operator is not willing to record consent or to provide the necessary identity facts at intake, the skill will refuse to act.
Limits and gotchas
- Never disclose more than the broker already shows. Submit only
disclosure_fields. The engine never volunteers SSN or ID numbers; you must not either. - No consent, no action. The engine enforces this; do not work around it to "research" a third party.
send-emailis idempotent and rate-limited. It refuses to re-send a case alreadysubmittedor beyond, and SMTP sends are paced byemail_min_interval_seconds(default 20s) with retry and backoff. Do not loop it to "make sure"; a successful SMTP handoff is not proof of delivery. The due-queue re-scan is the real confirmation.- Ledger writes are locked. Concurrent runs serialize safely; if you see a lock timeout, another run is mid-write. Let it finish; do not delete the
.lockby hand. - Autonomy does not mean improvisation. Full autonomy means not asking between steps; it does not loosen any gate. If a broker demands more than the planned
disclosure_fieldsmid-flow, stop that case and queue it as a human task rather than deciding alone to disclose extra PII. - Don't interrupt the run with questions. Config choices are
setup --auto's job; human-only work goes to the digest. The only mid-run question that is ever warranted is a missing-identity fact that blocks scanning, and that should have been collected at intake. - Use
terminal, notexecute_codeforpdd.py, because secret scrubbing and output redaction break it. - Dossiers are plaintext by default (JSON,
0600underHERMES_HOME). For at-rest encryption run$PDD setup --encryption age; it generates a localagekey and encrypts dossiers and ledgers, while the audit log holds field names only and stays plaintext. It guards casual, backup, or commit exposure, not a fullHERMES_HOMEread. SetPDD_AGE_IDENTITYto a separate volume for real key separation.$PDD doctorshows whether encryption is actually engaged. - "Hidden from free search" does not mean deleted. Only mark
confirmed_removedafter verifying the record is actually gone; note paid-tier retention in the report. - Soft CAPTCHAs clear by default; do not fight the hard ones. The default cloud browser passes managed or soft challenges as normal operation. For a hard interactive one it genuinely cannot pass, record
blockedand let the stealth or operator-browser pass take it. Never use a third-party solver service or fingerprint spoofing. - Broker pages change. If a flow breaks, record
blockedand flag the broker file inreferences/brokers/for re-verification instead of guessing. - Verify non-field-verified records before submitting. Records with
confidence: autocame from parsing BADBOOL; readoptout.notesandoptout.linksto confirm the real opt-out URL. Records withconfidence: documentedcarry the correct published opt-out URL but have not been field-verified, so confirm the live flow via the operator's residential browser on first use, then setlast_verified. Field-verified curated records, such as the cluster parents, have checked mechanics and take precedence.
Verification and dry run
Run the hermetic test suite to confirm the skill works in your environment.
scripts/run_tests.sh tests/skills/test_unbroker_skill.py
Or use the dependency-free runner:
python tests/skills/test_unbroker_skill.py
For a dry run without touching real data:
$PDD setup --auto && $PDD doctor && SID=$($PDD intake --full-name "Test Person" --email t@example.com --consent | python -c 'import sys,json;print(json.load(sys.stdin)["subject_id"])') && $PDD next "$SID"
This should produce a readiness summary plus an ordered action queue.
What pairs with this
Unbroker works well with several related skills. The google-workspace skill provides the Google Sheets tracker for reporting. The agentmail skill offers per-broker aliases for email automation. The himalaya skill can handle email if you prefer a different mail client. The scrapling skill helps with stealth or Cloudflare-protected pages. The osint-investigation skill complements the discovery phase when you need deeper background research on a subject or a broker.