| name | unbroker |
| description | Autonomously remove your info from data-broker sites. |
| version | 1.0.0 |
| author | SHL0MS (github.com/SHL0MS) |
| license | MIT |
| platforms | ["linux","macos","windows"] |
| prerequisites | {"commands":["python"]} |
| metadata | {"hermes":{"tags":["privacy","data-broker","opt-out","ccpa","gdpr","security","doxxing"],"category":"security","related_skills":["google-workspace","agentmail","himalaya","scrapling","osint-investigation"],"homepage":"https://github.com/Aditya232-rtx/ouro"}} |
unbroker
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 and
form-driving with native tools: web_extract and browser_navigate for searching and web forms, and
cronjob for recurring re-scans.
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.
Prerequisites
python (stdlib only; no extra packages needed for the core engine).
- Optional upgrades (the skill works zero-config without these;
setup --auto turns on every
one it detects, reading credentials from the shell env and from $OURO_HOME/.env so keys
Ouro already loads for its own tools are picked up without re-exporting - each one converts a
class of human tasks into agent actions):
- Cloud browser (recommended default):
BROWSERBASE_API_KEY. setup --auto selects it
whenever the key is present, and it is the intended baseline: a real residential-IP cloud
browser clears soft/managed CAPTCHAs (Cloudflare Turnstile, hCaptcha/reCAPTCHA checkbox) as
normal operation, so those brokers stay automated (T1) instead of becoming human tasks. This
is not CAPTCHA "solving" - no solver service, no fingerprint spoofing; only interactive/behavioral
("hard") challenges the browser genuinely cannot pass fall back to a human task. Without the key,
the plain agent browser is used and soft-CAPTCHA brokers drop to T2 (human).
- Email automation, two credential-free-or-not options:
- Browser mode (no password):
setup --email-mode browser. The agent sends opt-out/CCPA
emails and opens verification links through the operator's logged-in webmail using
browser_* tools. Nothing is stored. This requires Ouro to be pointed at the operator's own
logged-in browser, NOT a cloud browser: a headless cloud browser (Browserbase) holds no
webmail session and is itself Cloudflare/DataDome-gated on webmail and on session-bound broker
gates (e.g. PeopleConnect guided-mode). Drive the operator's real Chrome over CDP - launch
chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.ouro/chrome-debug" (a dedicated
debug profile signed into the webmail once, not the Default profile) and connect the browser
tools to 127.0.0.1:9222. $PDD cdp launches this for you (finds Chrome/Chromium/Brave/Edge,
starts it detached on the dedicated profile, prints the CDP endpoint; --check to test, --print
for the command). See references/methods.md -> "Browser backends: scan vs execute".
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_HOST for non-mainstream providers; gmail/outlook/yahoo/icloud/fastmail inferred).
The CLI sends via and reads verify links via . The
skill (per-broker aliases) also counts.
How to Run
Run everything through the terminal tool. From this skill's directory:
PDD="python scripts/pdd.py"
The engine stores data under $PDD_DATA_DIR (default $OURO_HOME/unbroker), written
0600. Run via terminal, not execute_code (that sandbox scrubs env and redacts output, which
breaks reading the dossier).
Quick Reference
| Command | Purpose |
|---|
$PDD setup --auto | Autonomous setup: detect capabilities, pick the most autonomous valid config (no questions) |
$PDD doctor | Readiness check: config, broker count, and which upgrades are on/available |
$PDD cdp [--check] [--print] [--port N] | Launch/detect the operator's Chrome over CDP for Phase-2 browser + webmail (dedicated debug profile; the reliable way to send webmail and clear session-bound gates) |
$PDD intake --full-name "..." [--alias ...] [--email ... --phone ...] [--city --state] [--prior-location "City,ST"] --consent | Create a consenting subject; captures aliases + multiple emails/phones + prior locations; prints subject_id |
$PDD next <subject> | The autonomous loop driver: ordered agent actions right now + human digest + next_wake_at |
$PDD brokers [--priority crucial] | List the people-search broker database (curated + live) |
$PDD refresh-brokers | Pull the latest BADBOOL people-search list and the CA Data Broker Registry (next requeues this automatically when the cache is stale) |
$PDD registry [--search NAME] | State registry coverage (CA ~545 ingested; VT/OR/TX portals surfaced); the DROP/email lane, not scanned |
$PDD drop <subject> [--filed] | The one-shot legal lever: one CA DROP request deletes from ALL registered brokers; --filed records it |
$PDD plan <subject> [--priority crucial] | Per-broker tier + method + search_vectors + the exact fields to disclose |
$PDD plan <subject> --batch | Reduce view: overlays ledger state, groups brokers by next action (unscanned/found/indirect/blocked/in_progress/done), collapses ownership clusters, orders found cluster-parents-first + emits a tailored parent_playbook, prints next_actions |
|
Batch operation (two-phase: crawl-all, then 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 / blocked). Scanning has no side
effects, so it is safe to parallelize and retry. Getting the full exposure map before acting is
what unlocks cluster dedup and prioritization below. Default: the parent drives web_extract
probes directly - most people-search sites render name/phone/address results as static HTML that
web_extract reads in seconds. Escalate to browser_* only for the few JS-only sites, and to
delegate_task subagents only for genuinely reasoning-heavy work (large-scale namesake/relative
disambiguation). Do NOT hand a browser-toolset subagent a big list of brokers to crawl - in the
field this timed out repeatedly (600s, ~5-6 brokers each, no summary) because browser navigation is
heavy; the ledger writes that survived came at 10x the cost of parent web_extract. A blocked
(DataDome/Cloudflare/antibot) site is not a subagent job either: record blocked and requeue it
for a stealth/cloud browser (Browserbase) pass. Subagent reports are self-reports - the parent
re-fetches key URLs to confirm a found before trusting it (this cuts both ways: it caught a real
listing the parent had wrongly assumed was a false positive).
- REDUCE -
$PDD plan <subject> --batch. Collapses the crawl into a phase-oriented plan: groups by
next action, collapses ownership clusters (a parent removal that clears children is ONE action,
not N - e.g. one Intelius/PeopleConnect suppression covers Truthfinder/Instant Checkmate/US Search/โฆ),
and prints next_actions. phase is discover while anything is unscanned, else delete.
- Phase 2 - DELETE (sequential, irreversible). Work the reduced groups parents first:
plan --batch orders the found group cluster-parents-first (most children first) and emits a
parent_playbook with tailored, ordered steps per parent - follow that order and those steps
(full recipes in references/methods.md โ "Ownership clusters - DO PARENTS FIRST"). Do the
cluster parents (skipping the covered children), re-scan each parent's children after it confirms
(they usually drop out), then the standalone listings; send the cases as
CCPA/GDPR delete-my-PII emails (), and defer to the
stealth-browser pass. Opt-outs hit CAPTCHAs, email-verification loops, and session binding - work
them (this is the opposite of fan-out), but do NOT stop to ask
permission per submission in ; in , confirm each one. where a broker offers both (Spokeo/BeenVerified) - but follow the
record's : (), where deleting
your user data removes your suppressions and does not stop public-records re-listing, so you
suppress-and-maintain instead.
Subagent reports are self-reports: the parent re-verifies key claims (listing URLs, match basis) before
recording found and before any deletion.
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 : run and - do
not scan all brokers yourself sequentially. For : scan the few brokers yourself.
Either way, each broker gets entry via the
ladder ( โ probe โ โ ), a 404 is INCONCLUSIVE
(not ), is recorded when is set and no stealth browser is available,
and subject vs namesake/relative is confirmed before recording:
.
The parent re-verifies key claims from subagents before trusting them.
Pitfalls
- Never disclose more than the broker already shows. Submit only
disclosure_fields. The engine
never volunteers SSN/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-email is idempotent + rate-limited. It refuses to re-send a case already submitted
or beyond (use --force only if a genuine re-send is needed), and SMTP sends are paced by
email_min_interval_seconds (default 20s) with retry/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 (cron + manual) serialize safely; if you ever see a
lock timeout, another run is mid-write - let it finish, don't delete the
.lock by hand.
- Autonomy โ improvisation. Full autonomy means not asking between steps; it does not loosen any
gate. If a broker demands MORE than the planned
disclosure_fields mid-flow, stop that case and
queue it (human_task_queued --reason) 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's ever warranted is a missing-identity fact that
blocks scanning (e.g. no city at all) - and that should have been collected at intake.
- Use
terminal, not execute_code for pdd.py (secret scrubbing + output redaction break it).
- Dossiers are plaintext by default (JSON,
0600 under OURO_HOME). For at-rest encryption run
$PDD setup --encryption age - it generates a local age key and encrypts dossiers + ledgers (the
audit log holds field names only and stays plaintext). It guards casual/backup/commit exposure, not
a full-OURO_HOME read; set PDD_AGE_IDENTITY to a separate volume for real key separation.
$PDD doctor shows whether encryption is actually engaged (not just whether age is installed).
- "Hidden from free search" โ deleted. Only mark
confirmed_removed after verifying the record is
actually gone; note paid-tier retention in the report.
Verification
scripts/run_tests.sh tests/skills/test_unbroker_skill.py (hermetic; no network), or the
dependency-free runner python 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 | python -c 'import sys,json;print(json.load(sys.stdin)["subject_id"])') && $PDD next "$SID" and confirm a readiness summary plus an ordered action queue.