unbroker
This CoWork OS bundled port is based on the upstream Hermes Agent unbroker skill:
https://github.com/NousResearch/hermes-agent/tree/main/optional-skills/security/unbroker
CoWork runtime mapping:
- Treat
terminal as CoWork's shell/run_command capability.
- Treat
web_extract as CoWork web search, fetch, or extraction tools.
- Treat
browser_* as the available CoWork browser automation tools.
- Treat
delegate_task as CoWork multi-agent orchestration when available.
- Treat
cronjob as CoWork scheduling/automation.
- The Python engine stores data under
$PDD_DATA_DIR when set. Otherwise it prefers
$COWORK_HOME/unbroker, then $COWORK_USER_DATA_DIR/unbroker, then the upstream legacy
$HERMES_HOME/unbroker / ~/.hermes/unbroker path.
Code is MIT licensed. Broker data includes BADBOOL-derived data under CC BY-NC-SA 4.0; keep the
license and attribution notes in LICENSE.txt and the README intact when redistributing.
Find where a person's personal information (name, addresses, phone, email, relatives) is exposed on
data brokers and people-search sites, then remove it - automatically where possible, with guided
human steps only where a site demands a CAPTCHA, government ID, phone call, or fax. Manages multiple
people independently. It does not defeat anti-bot systems, does not act on anyone without
recorded consent, and does not remove public records (voter/property/court) or accounts the
person controls.
The Python CLI (scripts/pdd.py) owns the deterministic state - config, dossiers + consent, the
broker database, tier planning, the ledger, drafts, reports, email sending (SMTP), verification-link
polling (IMAP), and the autonomous action queue (next). You (the agent) do the scanning,
form-driving, parallel work, and scheduling with the matching CoWork tools.
Autonomy contract
This skill is designed to run hands-off. After intake (+ recorded consent) there are exactly TWO
legitimate human touchpoints: (1) the intake conversation itself, and (2) ONE consolidated human-task
digest at the end of the run ($PDD tasks). Between those:
- Never ask the operator to choose configuration.
$PDD setup --auto detects capabilities and
picks the most autonomous valid config itself.
- Never pause before individual submissions when
autonomy=full (the default): the consent
recorded at intake is standing authorization for T0-T2 opt-outs. (autonomy=assisted restores
per-submission confirmation for cautious operators - honor confirm_first flags in next output.)
- Never interrupt the run for human-only work. Record it (
record ... human_task_queued --reason "...") and keep going; it all surfaces once in the final digest.
- Drive the whole run as a loop over
$PDD next <subject> - it returns the exact ordered actions
to take right now (scan, poll verification, re-check, opt out parents-first, requeue blocked), plus
the human digest. Execute every action, record outcomes, re-run next, repeat until
done_for_now. Then present the digest, report, and schedule the cron.
The hard limits that autonomy never overrides: no acting without recorded consent, no disclosure
beyond disclosure_fields, no CAPTCHA/anti-bot bypass, and confirmed_removed only after a
verifying re-scan.
When to Use
- "Remove my (or my family member's) data from data brokers / people-search sites."
- "Opt me out", "delete me from Spokeo/Whitepages/etc.", "clean up after a doxxing."
- "Set up recurring privacy monitoring" (brokers re-list people).
- Checking which brokers still expose someone and why.
Operational setup
Before running any command, read references/operations.md for prerequisites, safe command syntax, quick reference, batch sequencing, consent boundaries, and failure recovery. Never infer consent or submit removals outside the recorded scope.
Procedure (the autonomous loop)
Setup (once, no questions). Run $PDD setup --auto - it detects capabilities and configures
the most autonomous valid combination itself (programmatic email when EMAIL_* creds exist,
Browserbase when its key exists, age encryption when the binary exists, autonomy=full). Then
$PDD doctor and show the operator the readiness output for information, not as a question -
proceed immediately. Mention what would unlock more automation (e.g. email creds) but do not wait.
Intake + consent (the ONE human conversation). $PDD intake ... with --consent (and
--consent-method). Without consent the engine refuses to plan or act. Collect everything in one
pass - names/aliases, current + prior cities, emails, phones - so you never have to come back with
questions. For California subjects, also read references/legal/drop.md: next will surface a
drop_submit one-shot that deletes from every registered broker (~545) at once, which is the
single highest-leverage action. File it, then drop <subject> --filed. For non-CA subjects the
registry is covered by targeted CCPA/GDPR emails (registry --search, then send-email); the
people-search sites are worked directly in either case.
Drain the queue. Loop:
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/scan_inline (Phase 1
crawl - see step 4), poll_verification (in-flight email confirmations), verify_removal (due
re-checks), optout_web_form/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 q.human_digest. In autonomy=full, execute actions without pausing; honor
confirm_first in assisted mode.
Scanning (when next says so). For fanout_scan: run $PDD fanout <subject> and spawn one
CoWork subagent per batch, in parallel when multi-agent tools are available, passing that batch's ready-made brief - do
not scan all brokers yourself sequentially. For scan_inline: scan the few brokers yourself.
Either way, each broker gets every search_vectors entry via the references/methods.md
ladder (web extraction -> site: probe -> browser automation -> stealth-capable browser/scraping), a 404 is INCONCLUSIVE
(not not_found), blocked is recorded when antibot is set and no stealth browser is available,
and subject vs namesake/relative is confirmed before recording:
$PDD record <subject> <broker> <found|not_found|indirect_exposure|blocked> --found <bool> --evidence '{"listing_urls":[...]}'.
The parent re-verifies key found claims from subagents before trusting them.
Opt-outs (when next says so). Actions come pre-ordered parents-first with steps from each
broker record's own optout.playbook (field-verified; cluster parents like PeopleConnect,
Whitepages, BeenVerified, Spokeo have exact, live-checked recipes). 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 (PeopleConnect -
deleting removes your suppressions and does not stop re-listing), do the suppression flow and keep
it maintained; use their Delete button only for a deliberate data-purge. Per method:
- web_form → drive
optout_url with browser_navigate/browser_type/browser_click, submit
only disclosure_fields, screenshot the confirmation, then the action's after record command.
Playbooks may end with a right-to-delete send-email follow-up - do it (full erasure, not just
listing suppression).
- email →
$PDD send-email <subject> <broker> --kind <ccpa|gdpr|generic> --to <addr> --listing <url> records + discloses in one step (recipient locked to addresses the broker
record declares; next picks the kind from residency - never claim CCPA/GDPR for someone who
can't). In browser mode it returns a recipient-locked compose payload: compose a new
message to compose.to with compose.subject/compose.body exactly in the operator's webmail
via CoWork browser tools and send (no password); in programmatic mode it SMTP-sends. next also
routes human-gated forms (phone-callback/gov-ID) through a broker's deletion email when one
exists - the rescue lane (verified Whitepages pattern). Draft-only falls back to
render-email + a digest entry.
- captcha → soft/managed challenges clear automatically on the default cloud browser (proceed
as normal); only a hard interactive/behavioral challenge it can't pass is recorded
blocked
(requeued for the stealth/operator-browser pass). Never a solver service.
- phone_callback / account / gov_id / fax / mail / voice (T3) without a deletion email →
never an agent action;
next already routed these to the digest. Record them:
$PDD record <subject> <broker> human_task_queued --reason "...".
Verification (when next says so). In programmatic mode $PDD poll-verification <subject>
finds arrived confirmation links via IMAP (anti-phishing scored, auto-advances state). In
browser mode, open the broker's confirmation email in the operator's webmail and run
$PDD verify-link <subject> <broker> --text '<body>' to score the link. Either way open the
link in the same browser (several brokers bind the verification session to the browser that
opens it), finish the flow, then record awaiting_processing. confirmed_removed ONLY after a
verifying re-scan shows the listing gone - never off the submission flow's own confirmation page.
Wrap up (once per run). When next returns no actions: present $PDD tasks <subject> (the
consolidated human digest) if non-empty, then $PDD status <subject>; if the Sheets tracker is
on, append $PDD report <subject> --sheets rows via CoWork's Google Sheets/Workspace capability.
Schedule the next wake-up. next returns next_wake_at (earliest due re-check). Create ONE
CoWork scheduled automation that re-runs this skill's loop for the subject (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.
Pitfalls
Apply the safety and recovery rules in references/operations.md, especially around CAPTCHA, verification links, duplicate submissions, rate limits, and evidence capture.
Verification
scripts/run_tests.sh tests/skills/test_unbroker_skill.py (hermetic; no network), or the
dependency-free runner python3 tests/skills/test_unbroker_skill.py.
- Dry run:
$PDD setup --auto && $PDD doctor && SID=$($PDD intake --full-name "Test Person" --email t@example.com --consent | python3 -c 'import sys,json;print(json.load(sys.stdin)["subject_id"])') && $PDD next "$SID" and confirm a readiness summary plus an ordered action queue.
1---2name: unbroker3description: Find and remove authorized personal information exposures from data brokers and people-search sites with a consent-gated local workflow.4---56# unbroker78This CoWork OS bundled port is based on the upstream Hermes Agent `unbroker` skill:9https://github.com/NousResearch/hermes-agent/tree/main/optional-skills/security/unbroker1011CoWork runtime mapping:1213- Treat `terminal` as CoWork's shell/run_command capability.14- Treat `web_extract` as CoWork web search, fetch, or extraction tools.15- Treat `browser_*` as the available CoWork browser automation tools.16- Treat `delegate_task` as CoWork multi-agent orchestration when available.17- Treat `cronjob` as CoWork scheduling/automation.18- The Python engine stores data under `$PDD_DATA_DIR` when set. Otherwise it prefers19 `$COWORK_HOME/unbroker`, then `$COWORK_USER_DATA_DIR/unbroker`, then the upstream legacy20 `$HERMES_HOME/unbroker` / `~/.hermes/unbroker` path.2122Code is MIT licensed. Broker data includes BADBOOL-derived data under CC BY-NC-SA 4.0; keep the23license and attribution notes in `LICENSE.txt` and the README intact when redistributing.2425Find where a person's personal information (name, addresses, phone, email, relatives) is exposed on26data brokers and people-search sites, then remove it - automatically where possible, with guided27human steps only where a site demands a CAPTCHA, government ID, phone call, or fax. Manages multiple28people independently. It does **not** defeat anti-bot systems, does **not** act on anyone without29recorded consent, and does **not** remove public records (voter/property/court) or accounts the30person controls.3132The Python CLI (`scripts/pdd.py`) owns the deterministic state - config, dossiers + consent, the33broker database, tier planning, the ledger, drafts, reports, **email sending (SMTP), verification-link34polling (IMAP), and the autonomous action queue (`next`)**. You (the agent) do the scanning,35form-driving, parallel work, and scheduling with the matching CoWork tools.3637## Autonomy contract3839This skill is designed to run **hands-off**. After intake (+ recorded consent) there are exactly TWO40legitimate human touchpoints: (1) the intake conversation itself, and (2) ONE consolidated human-task41digest at the end of the run (`$PDD tasks`). Between those:4243- **Never ask the operator to choose configuration.** `$PDD setup --auto` detects capabilities and44 picks the most autonomous valid config itself.45- **Never pause before individual submissions** when `autonomy=full` (the default): the consent46 recorded at intake is standing authorization for T0-T2 opt-outs. (`autonomy=assisted` restores47 per-submission confirmation for cautious operators - honor `confirm_first` flags in `next` output.)48- **Never interrupt the run for human-only work.** Record it (`record ... human_task_queued49 --reason "..."`) and keep going; it all surfaces once in the final digest.50- **Drive the whole run as a loop over `$PDD next <subject>`** - it returns the exact ordered actions51 to take right now (scan, poll verification, re-check, opt out parents-first, requeue blocked), plus52 the human digest. Execute every action, record outcomes, re-run `next`, repeat until53 `done_for_now`. Then present the digest, report, and schedule the cron.5455The hard limits that autonomy never overrides: no acting without recorded consent, no disclosure56beyond `disclosure_fields`, no CAPTCHA/anti-bot bypass, and `confirmed_removed` only after a57verifying re-scan.5859## When to Use6061- "Remove my (or my family member's) data from data brokers / people-search sites."62- "Opt me out", "delete me from Spokeo/Whitepages/etc.", "clean up after a doxxing."63- "Set up recurring privacy monitoring" (brokers re-list people).64- Checking which brokers still expose someone and why.6566## Operational setup6768Before running any command, read [references/operations.md](references/operations.md) for prerequisites, safe command syntax, quick reference, batch sequencing, consent boundaries, and failure recovery. Never infer consent or submit removals outside the recorded scope.6970## Procedure (the autonomous loop)71721. **Setup (once, no questions).** Run `$PDD setup --auto` - it detects capabilities and configures73 the most autonomous valid combination itself (programmatic email when `EMAIL_*` creds exist,74 Browserbase when its key exists, `age` encryption when the binary exists, `autonomy=full`). Then75 `$PDD doctor` and show the operator the readiness output **for information, not as a question** -76 proceed immediately. Mention what would unlock more automation (e.g. email creds) but do not wait.772. **Intake + consent (the ONE human conversation).** `$PDD intake ...` with `--consent` (and78 `--consent-method`). Without consent the engine refuses to plan or act. Collect everything in one79 pass - names/aliases, current + prior cities, emails, phones - so you never have to come back with80 questions. For California subjects, also read `references/legal/drop.md`: `next` will surface a81 `drop_submit` one-shot that deletes from every registered broker (~545) at once, which is the82 single highest-leverage action. File it, then `drop <subject> --filed`. For non-CA subjects the83 registry is covered by targeted CCPA/GDPR emails (`registry --search`, then `send-email`); the84 people-search sites are worked directly in either case.853. **Drain the queue.** Loop:8687 ```88 while true:89 q = $PDD next <subject>90 if q.actions is empty: break91 execute EVERY action in order; record each outcome via $PDD record92 ```9394 `next` emits, in order: `refresh_brokers` (stale cache), `fanout_scan`/`scan_inline` (Phase 195 crawl - see step 4), `poll_verification` (in-flight email confirmations), `verify_removal` (due96 re-checks), `optout_web_form`/`optout_email_send` (Phase 2, parents-first with playbook steps),97 `indirect_email_send`, and `stealth_rescan`. Human-only work never appears as an action - it98 accumulates in `q.human_digest`. In `autonomy=full`, execute actions without pausing; honor99 `confirm_first` in `assisted` mode.1004. **Scanning (when `next` says so).** For `fanout_scan`: run `$PDD fanout <subject>` and **spawn one101 CoWork subagent per `batch`, in parallel when multi-agent tools are available, passing that batch's ready-made `brief`** - do102 not scan all brokers yourself sequentially. For `scan_inline`: scan the few brokers yourself.103 Either way, each broker gets **every** `search_vectors` entry via the `references/methods.md`104 ladder (web extraction -> `site:` probe -> browser automation -> stealth-capable browser/scraping), a 404 is INCONCLUSIVE105 (not `not_found`), `blocked` is recorded when `antibot` is set and no stealth browser is available,106 and subject vs namesake/relative is confirmed before recording:107 `$PDD record <subject> <broker> <found|not_found|indirect_exposure|blocked> --found <bool> --evidence '{"listing_urls":[...]}'`.108 The parent re-verifies key `found` claims from subagents before trusting them.1095. **Opt-outs (when `next` says so).** Actions come pre-ordered parents-first with `steps` from each110 broker record's own `optout.playbook` (field-verified; cluster parents like PeopleConnect,111 Whitepages, BeenVerified, Spokeo have exact, live-checked recipes). **Deletion usually beats112 suppression**: when an action carries `prefer_deletion`, complete the record's DELETION lane, not113 just the hide-my-listing flow. When it carries `prefer_suppression` instead (**PeopleConnect** -114 deleting removes your suppressions and does not stop re-listing), do the suppression flow and keep115 it maintained; use their Delete button only for a deliberate data-purge. Per method:116 - **web_form** → drive `optout_url` with `browser_navigate`/`browser_type`/`browser_click`, submit117 only `disclosure_fields`, screenshot the confirmation, then the action's `after` record command.118 Playbooks may end with a right-to-delete `send-email` follow-up - do it (full erasure, not just119 listing suppression).120 - **email** → `$PDD send-email <subject> <broker> --kind <ccpa|gdpr|generic> --to <addr>121 --listing <url>` records + discloses in one step (recipient locked to addresses the broker122 record declares; `next` picks the kind from residency - never claim CCPA/GDPR for someone who123 can't). In **browser** mode it returns a recipient-locked `compose` payload: compose a new124 message to `compose.to` with `compose.subject`/`compose.body` exactly in the operator's webmail125 via CoWork browser tools and send (no password); in **programmatic** mode it SMTP-sends. `next` also126 routes human-gated forms (phone-callback/gov-ID) through a broker's deletion email when one127 exists - the **rescue lane** (verified Whitepages pattern). Draft-only falls back to128 `render-email` + a digest entry.129 - **captcha** → soft/managed challenges clear automatically on the default cloud browser (proceed130 as normal); only a hard interactive/behavioral challenge it can't pass is recorded `blocked`131 (requeued for the stealth/operator-browser pass). Never a solver service.132 - **phone_callback / account / gov_id / fax / mail / voice (T3)** *without a deletion email* →133 never an agent action; `next` already routed these to the digest. Record them:134 `$PDD record <subject> <broker> human_task_queued --reason "..."`.135 6. **Verification (when `next` says so).** In **programmatic** mode `$PDD poll-verification <subject>`136 finds arrived confirmation links via IMAP (anti-phishing scored, auto-advances state). In137 **browser** mode, open the broker's confirmation email in the operator's webmail and run138 `$PDD verify-link <subject> <broker> --text '<body>'` to score the link. Either way **open the139 link in the same browser** (several brokers bind the verification session to the browser that140 opens it), finish the flow, then record `awaiting_processing`. `confirmed_removed` ONLY after a141 verifying re-scan shows the listing gone - never off the submission flow's own confirmation page.1427. **Wrap up (once per run).** When `next` returns no actions: present `$PDD tasks <subject>` (the143 consolidated human digest) if non-empty, then `$PDD status <subject>`; if the Sheets tracker is144 on, append `$PDD report <subject> --sheets` rows via CoWork's Google Sheets/Workspace capability.1458. **Schedule the next wake-up.** `next` returns `next_wake_at` (earliest due re-check). Create ONE146 CoWork scheduled automation that re-runs this skill's loop for the subject (a prompt like: *"run the147 unbroker loop for <subject_id>: `$PDD next` and execute all actions"*). Processing148 windows, verification polls, and reappearance sweeps all flow through the same queue, so the case149 keeps advancing with zero human attention.150151## Pitfalls152153Apply the safety and recovery rules in [references/operations.md](references/operations.md), especially around CAPTCHA, verification links, duplicate submissions, rate limits, and evidence capture.154155## Verification156157- `scripts/run_tests.sh tests/skills/test_unbroker_skill.py` (hermetic; no network), or the158 dependency-free runner `python3 tests/skills/test_unbroker_skill.py`.159- Dry run: `$PDD setup --auto && $PDD doctor && SID=$($PDD intake --full-name "Test Person"160 --email t@example.com --consent | python3 -c 'import sys,json;print(json.load(sys.stdin)["subject_id"])')161 && $PDD next "$SID"` and confirm a readiness summary plus an ordered action queue.