Integration

How PeopleBlade uses Ghostget to read contacts from your accounts

PeopleBlade asks a separately installed Ghostget for one named read at a time and checks every result before it reaches your local contact book.

Drafted with AI from the source code and reviewed by Claude Opus 5.5 (claude-opus-5-5) editorial review.

PeopleBlade keeps your contact book in a SQLite file on your own computer and fills it from accounts you already sign in to. For each live account it asks a separate tool, Ghostget, for one named read, and it checks what comes back before saving anything.

Those accounts hold different pieces of each person. Google Contacts has the email addresses, WhatsApp and Beeper have the numbers and handles of the people you talk to, and LinkedIn's Contact info panel sometimes holds the one email a colleague shared with you. Without a tool like this, combining them means copying by hand or giving an agent your browser and hoping it clicks the right things.

Why handing over a browser is the wrong shape

An agent driving a signed-in browser can do anything you can do in that tab. It can open your messages, send a connection request or post on your behalf, and nothing in the setup says it will not. When a page layout changes, it may quietly read the wrong field and write a mistake into your records that looks like good data.

What you want instead is a short list of things the tool is allowed to do, each with a name, and a way to notice when the answer no longer looks the way it did when someone last reviewed it.

What Ghostget does

Ghostget is a free, open source command line tool that you install and sign in to yourself. It holds the connection to each account and offers named actions in place of your passwords: "list contacts" for Google, "search contacts" for Beeper, "read the Contact info panel of one profile" for LinkedIn. Your agent, or a program like PeopleBlade, asks for a named action and gets a structured answer plus a record of the run. It never gets your credentials or a browser to steer.

Every run reports which action ran, which version of the site adapter handled it, a fingerprint of the action's contract, and whether anything was changed on the account.

How PeopleBlade calls it

PeopleBlade never drives a browser, and it does not ship Ghostget itself. Its published package carries only Ghostget's client-side request and receipt checks. Live Google Contacts, Beeper and WhatsApp imports, and the LinkedIn Contact info read, all go through a ghostget executable you install separately. PeopleBlade's own package pins one exact Ghostget release, 0.18.35, and the setup commands for each account come from the PeopleBlade guide:

peopleblade google sync --auth gmail-main --json
peopleblade beeper sync --auth beeper-main --json
peopleblade whatsapp sync --auth whatsapp-main
peopleblade linkedin contact-info --person-id ID --json

Each command turns into named read actions and nothing else. Google Contacts is authorized with read-only contact scopes, and the sync turns off Gmail statistics, so it does not scan your messages. Beeper is used only for contacts, search results and, on Apple silicon Macs only, optional counts of direct-message activity that carry no message text. WhatsApp reads contacts through a linked device you pair from your phone. LinkedIn is the narrowest: your connections come only from LinkedIn's official data export, and the Contact info command reads one first-degree connection you already imported, one profile per command, through the signed-in LinkedIn browser profile you bound in Ghostget. It never lists connections, reads messages or sends invitations.

Before any of those reads, PeopleBlade asks the executable who it is. If ghostget --version does not print exactly the pinned release, nothing is sent and the command stops with a message saying which release it needs. The same bridge also refuses an executable path that is not absolute, two settings that point at different executables, and a configuration that would make it call itself.

The rules each answer has to pass

When a result comes back, PeopleBlade applies a fixed set of rules before one row reaches your database. Written as plain checks, the idea looks like this:

// Illustrative sketch of the checks, written for this post
function acceptRead(run, asked, reviewed) {
  if (run.changedAnything) throw stop("a read must not change the account");
  if (run.action !== asked.action || run.account !== asked.account)
    throw stop("this answer is for a different request");
  if (run.inputHash !== hash(asked.input))
    throw stop("this answer is for a different question");
  if (run.adapterVersion !== reviewed.adapterVersion
      || run.contractFingerprint !== reviewed.contractFingerprint)
    throw stop("the provider changed; review before trusting it");
  return parseStrictly(run.output); // parse again, then save
}

Four rules sit underneath that sketch, and they hold for every source:

  1. A read stays a read. If the run reports any planned or started change to the account, PeopleBlade rejects it, even if the data looks fine.
  2. The answer matches the question. The action, the account and a hash of the exact input have to match what PeopleBlade asked for.
  3. The contract is the one that was reviewed. PeopleBlade pins the adapter version and the fingerprint of each action's reviewed contract in its own code. A new adapter or a changed contract is not accepted automatically.
  4. Parse again before saving. PeopleBlade does not take Ghostget's word for the output. It runs its own strict parser over the result, then records the run in a local history next to the imported rows.

When a check fails, nothing is written and nothing is retried. For a temporary provider problem, the message says the provider's policy allows one retry after 60 seconds and that PeopleBlade has not retried. For a changed adapter or contract, the message tells you to ask your coding agent to investigate with synthetic test data and propose a PeopleBlade update, and to keep the read blocked until that update is reviewed. The error alone never replaces a pin.

What you get from it

You get contacts from four signed-in accounts in one local record, and neither PeopleBlade nor your agent gets your passwords or a browser to steer. Every imported detail keeps the account and the run it came from. Reading the same LinkedIn profile twice with the same result is recognized as a repeat, and if a later read no longer shows a field, the earlier value is marked inactive rather than deleted.

When Google, Beeper, WhatsApp or LinkedIn changes something, PeopleBlade stops, says so and waits for a reviewed update before it saves anything the changed provider returns.

Where the integration stops

This path reads. PeopleBlade never exposes Ghostget's Beeper send or action operations, and it never sends LinkedIn invitations or messages. The only send PeopleBlade makes through your messaging accounts is exposure attest-send: one signed, counts-only exposure summary you created, sent as a single attachment to the one enrolled iMessage or WhatsApp conversation that matches that contact, only under a one-use grant that expires in 24 hours and only when you pass --confirm. If no conversation matches, or more than one does, nothing is sent. It uses a separate owner-controlled messaging host in Ghostget, not the read path described here, and if the outcome is uncertain it waits for you to check instead of sending again.

X live mutuals are blocked. They wait for a reviewed Ghostget read, and there is no fallback to the X API or to reading pages. Contact info reads work only for first-degree connections you already imported; LinkedIn hides that panel for other profiles, and PeopleBlade does not guess. The core local commands and the official archive imports do not need Ghostget at all.

If you upgrade Ghostget past the reviewed release, the live reads stop with a version message until PeopleBlade updates its pin. These checks confirm that an answer came from the reviewed action in the reviewed format. They do not prove the provider's data is correct, only that PeopleBlade saved what that action returned.

Introducing PeopleBlade covers the rest of the contact book, and Ghostget documents each supported account.

Latest release: v0.5.0. Install the command line tool with bun add --global @hraness/peopleblade@0.5.0.