Pass an ID, not the data
One agent seals a list and passes on its ID. Another agent reads the report and requests the delivery; a service picks the file up with a grant and checks the signature before it trusts a byte.
Open source · self-hosted · alpha
Padhoc moves data from one agent to another, and from agents into the systems they work with: your e-mail platform, your CRM, an ad account. You host it, so you decide what an agent may do with every file. Rows never enter the model.
Reports carry counts, distributions and five masked examples. Below 100 rows the agent gets only the count, and no query can be pointed at one person's address. To move a file, it passes on an ID.
get_snapshot{
"number": 1042,
"status": "sealed",
"purpose": "marketing",
"key": { "column": "email", "type": "email" },
"rows": { "count": 2104, "invalid": 0, "duplicates": 0 },
"fingerprint": "sha256:9f3a1c07e2b4…",
"report": {
"distributions": {
"city": { "values": [
{ "value": "Amsterdam", "count": 688 },
{ "value": "Rotterdam", "count": 541 },
…
] }
},
"examples": [{ "email": "j***@example.org", "city": "Amsterdam" }, …]
}
}
Abridged. No rows, no download links
You pick the route per destination. On every route the model sees identifiers and counts, never rows.
One agent seals a list and passes on its ID. Another agent reads the report and requests the delivery; a service picks the file up with a grant and checks the signature before it trusts a byte.
After approval, Padhoc gives Brevo a link to the file or drops it in your bucket. Platforms that pull on a schedule, like Google's Data Manager, read the latest approved file from a feed address.
After approval the agent gets a single-use grant. Its sandbox redeems it and calls the platform's API, for Meta, Klaviyo or ActiveCampaign. The model sees the grant and the counts.
Browser use covers the one-time setup in a platform's interface, such as linking an ad account. When an upload happens there, the file goes from disk to the upload field, not through the model.
Your agent talks to Padhoc over MCP: point any MCP client at /mcp with an agent token. This is the whole session for one list, from the request to Brevo's answer. Each step lands in the audit log.
padhoc · /mcpThe agent reads the catalog and previews a query. Padhoc checks the SQL, runs it read-only and answers with counts and masked examples. Nothing is stored.
Build an audience of active Dutch customers in the gold tier and deliver it to Brevo as ‘October newsletter’.
describe_sourcesource: "demo-store"preview_querysource: "demo-store", purpose: "marketing"SELECT email, first_name, city
FROM marketing_contacts
WHERE {{segment:active_customer}}
AND {{segment:gold_tier}}
AND country = 'NL'
2,104 customers match, most of them in Amsterdam, Rotterdam and Utrecht. I'll seal this query.
The same query becomes a snapshot: read once, written as Parquet and signed. Change one byte and the fingerprint changes.
create_snapshotthe same source, purpose and queryget_snapshotsnapshot_id: "1042"The agent asks for a delivery under a list name. Padhoc renders the file Brevo takes, and a logged-in person approves that exact file, or a rule a person set does. No tool can approve.
deliver_snapshotsnapshot_id: "1042", destination: "brevo", list_name: "October newsletter"Snapshot #1042 is sealed and signed. The delivery to Brevo is waiting for your approval in Padhoc.
A person approves #1042 for BrevoIn the Padhoc console, outside this chat
Padhoc hands Brevo the approved file and records Brevo's answer. The agent only reads the outcome.
get_deliverydelivery_id: "0b6c4e1a-…"Done. Brevo has a new list, “padhoc-1042-October newsletter”, with 2,104 contacts.
Padhoc runs on your infrastructure, so the rules are yours. They hold whatever the agent is told, because they live in the system and not in the prompt.
The views are the policy: consent filters and allowed columns live there, so a query can't forget them.
One SELECT on released datasets, token scopes per source and purpose, and human approval unless you set an auto-approval rule.
Files are never overwritten and every byte is in the fingerprint. The data expires; the proof of who was on the list stays.
E-mail audiences come first. The same handoff works for any list of people or records that feeds a decision.
One agent builds the list and another acts on it. They pass a snapshot ID between them, and the data stays put.
any keyYour agent builds an audience and hands it to Brevo or Resend as a fresh list, with proof of who was on it and why.
key: emailYour agent saves a segment and refreshes it on its own schedule. Every refresh is a sealed file; a rule you set lets small changes through and sends the rest to a person.
any keyHand Meta or Google a hashed audience once it is approved, so you can show later which list fed which campaign.
key: email, phoneAsk how big a segment is, how it splits by country or tier, and how it overlaps with another. No row leaves the database.
counts onlySplit an audience with a fixed rule and seal both halves. Months later you still know who got the campaign and who did not.
key: idShare the minimum dataset through a grant that expires, with a log of who fetched it and when.
any keyOutage, recall, price change or data breach: record exactly who was affected at the moment you sent the notice.
key: email, phoneHand finance a frozen, approved list of accounts, so the list that was approved is the list that gets paid.
key: idRerun an analysis or a model evaluation on exactly the same rows, with a fingerprint to prove it.
key: idAgent-carried deliveries with single-use grants, files rendered per destination and hashed for ad platforms, skills for Meta, Klaviyo and ActiveCampaign, and delta files for platforms with add and remove APIs.
Run Padhoc next to your data, in PostgreSQL or behind Trino in your lakehouse: one Docker Compose stack with the API, the console, the MCP server, a worker, Postgres and S3-compatible storage. Keys stay in your environment, and only approved files leave it. A demo database is included.
pip install padhoc
npm i @padhoc/sdk
# clone and start the stack git clone https://github.com/padhoc/padhoc && cd padhoc docker compose -f deploy/docker-compose.yml up -d --build # create the first admin, then seed the demo workspace docker compose -f deploy/docker-compose.yml logs api | grep -A2 "one-time link" docker compose -f deploy/docker-compose.yml run --rm seed open http://localhost:8000
Run the demo store, let your agent build a list, approve it, and watch it move