---
name: pp-sendfox
description: "Operate SendFox campaigns and audiences with typed commands, local evidence and guarded plans. Trigger phrases: `preflight a SendFox campaign`, `audit SendFox audience`, `plan an inactive SendFox automation`, `use sendfox`, `run sendfox`."
author: "cathrynlavery"
license: "Apache-2.0"
argument-hint: "<command> [args] | install cli|mcp"
allowed-tools: "Read Bash"
metadata:
  openclaw:
    requires:
      bins:
        - sendfox-pp-cli
    install:
      - kind: go
        bins: [sendfox-pp-cli]
        module: github.com/mvanhorn/printing-press-library/library/marketing/sendfox/cmd/sendfox-pp-cli
---

# SendFox — Printing Press CLI

## Safety and evidence

This edition covers the documented 60-operation SendFox contract. Discover current commands with `which` and `capabilities`. Preview every write with `--dry-run`; execution requires `--yes`, and sends, schedules, activation, forms/domains or deletion additionally require `--approve-sensitive`. Do not interpret an evidence report's ready value or exit 0 as permission to act. The eight evidence reports read local JSON/YAML/SQLite only; reject live data-source requests and report missing/stale scopes explicitly. `workflow export-bundle` is strictly read-only; `workflow snapshot-save --out DIR` is the explicit local-file write. See EVIDENCE.md for the normalized snapshot schema and native-export limitations. Read-only authenticated behavior passed the publish-time live gate; account mutations, sends and delivery remain unverified.

For bulk jobs, `--preview-count` controls the API's count-only request while global `--dry-run` stays entirely local. No writes are automatically retried. The account budget is 60 requests/minute shared with every other client. Use `contacts bulk-wait` with a bounded request count to inspect progress.

MCP search/metadata/execute tools cover 60 operations with schemas; mutations preview unless confirm=true, with approve_sensitive=true additionally required for high-impact actions. Endpoint mirrors are hidden. Local workflows remain explicit tools.

## Prerequisites: Install the CLI

This skill drives the `sendfox-pp-cli` binary. **You must verify the CLI is installed before invoking any command from this skill.** If it is missing, install it first:

1. Install via the Printing Press installer. It defaults binaries to `$HOME/.local/bin` on macOS/Linux and `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows:
   ```bash
   npx -y @mvanhorn/printing-press-library install sendfox --cli-only
   ```
2. Verify: `sendfox-pp-cli --version`
3. Ensure the reported install directory is on `$PATH` for the agent/runtime that will invoke this skill.

If the `npx` install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.6 or newer). This installs into `$GOPATH/bin` (default `$HOME/go/bin`), so add that directory to `$PATH` instead:

```bash
go install github.com/mvanhorn/printing-press-library/library/marketing/sendfox/cmd/sendfox-pp-cli@latest
```

If `--version` reports "command not found" after install, the runtime cannot see the binary directory on `$PATH`. Do not proceed with skill commands until verification succeeds.

Manage the current SendFox API from a predictable CLI and compact MCP surface. Combine campaign, audience and automation evidence locally; evaluate migration readiness without changing an account.

## When to Use This CLI

Use this CLI for SendFox audience operations, campaign preparation and reports, automation definitions and deterministic local export comparisons. Inspect plans and completeness before acting.

## Anti-triggers

Do not use this CLI for:
- Do not use for webhook delivery or purchases/orders: absent from the public contract.
- Do not use a readiness report as authorization to send, activate, change DNS/forms or migrate.

## Unique Capabilities

These workflows combine supplied local evidence into auditable reports and inactive plans.

### SendFox operations
- **`workflow audience-health`** — Find duplicate, invalid, suppressed and unassigned contacts, plus honest engagement cohorts.

  _Engagement timestamps form recency cohorts; missing or incomplete activity stays unknown rather than being labeled never-engaged._

  ```bash
  sendfox-pp-cli workflow audience-health --input examples/snapshot.json --agent
  ```
- **`workflow campaign-preflight`** — Check draft content, targeting, suppression evidence and sender readiness before any send.

  _Check draft content, targeting, suppression evidence and sender readiness before any send._

  ```bash
  sendfox-pp-cli workflow campaign-preflight --input examples/snapshot.json --agent
  ```
- **`workflow campaign-review`** — Combine campaign metrics, recipient-weighted benchmarks, trends, link performance and engagement cohorts into an auditable resend plan.

  _Rates are recomputed from counters, recipient-weighted, and compared with campaign medians and timestamped trends._

  ```bash
  sendfox-pp-cli workflow campaign-review --input examples/snapshot.json --agent
  ```
- **`workflow contact-dossier`** — Join contact details, memberships, tags and available engagement into one support packet.

  _Join contact details, memberships, tags and available engagement into one support packet._

  ```bash
  sendfox-pp-cli workflow contact-dossier --input examples/snapshot.json --id 1 --agent
  ```
- **`workflow automation-plan`** — Validate a versioned automation definition and produce inactive creation steps.

  _Validate a versioned automation definition and produce inactive creation steps._

  ```bash
  sendfox-pp-cli workflow automation-plan --input examples/snapshot.json --agent
  ```
- **`workflow export-bundle`** — Produce a read-only local inventory bundle with completeness, provenance and deterministic hashes.

  _This command never writes files; use `snapshot-save` when durable history is intended._

  ```bash
  sendfox-pp-cli workflow export-bundle --input examples/snapshot.json --agent
  ```
- **`workflow growth-report`** — Calculate timestamped audience growth from one snapshot and exact observed list joins, leaves and retention from two.

  _Every metric includes its formula, window, numerator, denominator, evidence grade, completeness and warnings. Missing evidence is null, never an invented zero._

  ```bash
  sendfox-pp-cli workflow growth-report --input current.json --previous previous.json --window 30d --agent
  ```

### Migration evidence
- **`workflow migration-readiness`** — Compare local platform snapshots with suppression, mapping, delta and cutover gates.

  _Compare local platform snapshots with suppression, mapping, delta and cutover gates._

  ```bash
  sendfox-pp-cli workflow migration-readiness --input examples/snapshot.json --agent
  ```

### Durable history helper

`workflow snapshot-save` is the explicit local-write companion to `export-bundle`. It requires `--out`, writes atomically with a `0700` directory and `0600` JSON file, and returns the artifact SHA-256.

```bash
sendfox-pp-cli workflow snapshot-save --input examples/snapshot.json --out ./history --agent
```

## Command Reference

**automation_emails** — Manage automation emails

- `sendfox-pp-cli automation-emails delete` — Remove an email from an automation
- `sendfox-pp-cli automation-emails update` — Update an automation email

**automations** — Manage automations

- `sendfox-pp-cli automations create` — Create an automation
- `sendfox-pp-cli automations create-email` — Add an email to an automation
- `sendfox-pp-cli automations delete` — Soft-deletes the automation and cancels all scheduled deliverables
- `sendfox-pp-cli automations get` — Returns automation with triggers, items, and campaign stats
- `sendfox-pp-cli automations list` — List automations
- `sendfox-pp-cli automations update` — Update title, trigger, or active status. Activating reschedules stale deliverables.

**campaigns** — Manage campaigns

- `sendfox-pp-cli campaigns create` — Creates a campaign as a draft. To send it, use the send endpoint or provide scheduled_at.
- `sendfox-pp-cli campaigns delete` — Only draft campaigns (not yet sent) can be deleted. Uses soft delete.
- `sendfox-pp-cli campaigns get` — Get a specific campaign
- `sendfox-pp-cli campaigns get-stats` — Returns sent count and open/click/bounce/unsubscribe/spam counts and rates, all read from stored counters.
- `sendfox-pp-cli campaigns list` — Returns a paginated list of campaigns (100 per page)
- `sendfox-pp-cli campaigns list-engagement` — Returns the contacts in one of a sent campaign's engagement groups.
- `sendfox-pp-cli campaigns resend` — Creates a new draft with the original's content, sender, and exclusions
- `sendfox-pp-cli campaigns send` — Schedules a draft campaign for immediate sending.
- `sendfox-pp-cli campaigns update` — Only draft campaigns (not yet sent) can be updated. All fields are optional.

**contact_fields** — Manage contact fields

- `sendfox-pp-cli contact-fields create` — Creates a custom field for contacts. The `name` is auto-generated from the `label` as a slug.
- `sendfox-pp-cli contact-fields delete` — Permanently deletes the contact field
- `sendfox-pp-cli contact-fields get` — Get a specific contact field
- `sendfox-pp-cli contact-fields list` — Returns custom contact fields defined by the user (20 per page)
- `sendfox-pp-cli contact-fields update` — Updates the label and auto-regenerates the name slug.

**contact_tags** — Manage contact tags

- `sendfox-pp-cli contact-tags create` — Creates a tag. A brand color is auto-assigned when none is provided. Tag names are unique per account.
- `sendfox-pp-cli contact-tags delete` — Deletes the tag.
- `sendfox-pp-cli contact-tags get` — Get a contact tag
- `sendfox-pp-cli contact-tags list` — Lists the account's tags, newest first, each with its contact count.
- `sendfox-pp-cli contact-tags update` — Update a contact tag

**contacts** — Manage contacts

- `sendfox-pp-cli contacts attach-tag` — Idempotent. Returns the contact's tags after the change.
- `sendfox-pp-cli contacts batch-import` — Import up to 1,000 contacts in a single request. Creates new contacts or updates existing ones.
- `sendfox-pp-cli contacts create` — Create a new contact
- `sendfox-pp-cli contacts create-bulk-action` — Queues one action against every contact the filter matches, applied in chunks in the background.
- `sendfox-pp-cli contacts delete` — Soft-deletes a contact and cancels any scheduled deliverables
- `sendfox-pp-cli contacts detach-tag` — Remove a tag from a contact
- `sendfox-pp-cli contacts get` — Get a specific contact
- `sendfox-pp-cli contacts get-activity` — Returns paginated email deliverables and contact-level engagement summary
- `sendfox-pp-cli contacts get-bulk-action` — For a dry run, matched_count is the answer and nothing was modified.
- `sendfox-pp-cli contacts list` — Returns a paginated list of contacts (100 per page by default, up to 1000 via `per_page`).
- `sendfox-pp-cli contacts list-tags-for` — List a contact's tags
- `sendfox-pp-cli contacts list-unsubscribed` — List unsubscribed contacts
- `sendfox-pp-cli contacts update` — Update contact details including name, list memberships, and custom fields

**domains** — Manage domains

- `sendfox-pp-cli domains create` — Adds a new sender domain and creates the corresponding SendGrid whitelabel domain.
- `sendfox-pp-cli domains delete` — Removes the domain from SendGrid and soft-deletes locally
- `sendfox-pp-cli domains get` — Returns domain details including DNS records needed for verification
- `sendfox-pp-cli domains list` — Returns a paginated list of the user's whitelabel/sender domains
- `sendfox-pp-cli domains validate` — Triggers DNS validation for the domain via SendGrid.

**forms** — Manage forms

- `sendfox-pp-cli forms create` — Creates a subscription form linked to one or more lists. Free users are limited to 1 form.
- `sendfox-pp-cli forms delete` — Soft-deletes the form
- `sendfox-pp-cli forms get` — Get a specific form
- `sendfox-pp-cli forms list` — List forms
- `sendfox-pp-cli forms update` — Update a form

**lists** — Manage lists

- `sendfox-pp-cli lists add-contact-to` — Adds an existing contact to a list. If the contact is already in the list, no duplicate is created.
- `sendfox-pp-cli lists contacts-in` — Get contacts in a list
- `sendfox-pp-cli lists create` — Create a new contact list
- `sendfox-pp-cli lists delete` — Soft-deletes a list. Returns 409 if the list is used by forms, landing pages, or automations.
- `sendfox-pp-cli lists get` — Returns list details including average open and click rates
- `sendfox-pp-cli lists list-lists` — List contact lists
- `sendfox-pp-cli lists remove-contact-from` — Remove a contact from a list
- `sendfox-pp-cli lists update` — Update a contact list

**me** — Manage me

- `sendfox-pp-cli me` — Get current user information

**unsubscribe** — Manage unsubscribe

- `sendfox-pp-cli unsubscribe` — Unsubscribe a contact by email


### Finding the right command

When you know what you want to do but not which command does it, ask the CLI directly:

```bash
sendfox-pp-cli which "campaign statistics"
```

`which` resolves a natural-language capability query to the best matching command from this CLI's curated feature index. Exit code `0` means at least one match; exit code `2` means no confident match — fall back to `--help` or use a narrower query. `--json` (and other machine formats) keep that exit-2 contract and write `{"matches":[]}` on stdout so agents can inspect the envelope without treating a miss as success.

## Recipes

### Audience audit

```bash
sendfox-pp-cli workflow audience-health --input examples/snapshot.json --agent
```

Report hygiene issues using local snapshot evidence.

### Export inventory

```bash
sendfox-pp-cli workflow export-bundle --input examples/snapshot.json --agent --select data.counts
```

Select only resource counts from the evidence bundle.

### Migration evidence

```bash
sendfox-pp-cli workflow migration-readiness --input examples/snapshot.json --agent
```

Produce a fail-closed readiness report; missing Kit evidence remains unknown.

### Campaign preflight

```bash
sendfox-pp-cli workflow campaign-preflight --input examples/snapshot.json --agent
```

Check content, targeting and sender evidence without sending.

### Campaign review

```bash
sendfox-pp-cli workflow campaign-review --input examples/snapshot.json --agent
```

Read counters and links and produce an unscheduled resend plan.

### Contact dossier

```bash
sendfox-pp-cli workflow contact-dossier --input examples/snapshot.json --id 1 --agent
```

Join the selected synthetic contact with memberships and activity.

### Inactive automation

```bash
sendfox-pp-cli workflow automation-plan --input examples/snapshot.json --agent
```

Compile dependent creation requests with active=false.

### CSV audit

```bash
sendfox-pp-cli contacts audit-csv --file examples/contacts.csv --agent
```

Inspect malformed, duplicate and suppressed rows before any import.

### Draft request preview

```bash
sendfox-pp-cli campaigns create --title "September notes" --subject "September notes" --from-email "editor@example.com" --from-name "Example Editor" --html "<p>News</p>" --dry-run --agent
```

Validate and preview a draft request; no account request is made.

## Auth Setup

Run `sendfox-pp-cli auth setup` for the URL and steps to obtain a token (add `--launch` to open the URL):

Or set `SENDFOX_API_TOKEN` as an environment variable.

Run `sendfox-pp-cli doctor` to verify setup.

## Agent Mode

Add `--agent` to any command. Expands to: `--json --compact --no-input --no-color`.

Global format flags share one contract on promoted, novel, sync, and `--deliver` paths:

- `--json` — one JSON document on stdout (sync progress events go to stderr)
- `--compact` — keep identity/status/timestamp fields; does not change the document vs stream shape
- `--csv` / `--plain` — tabular rows (collection envelopes unwrap to the row array)
- `--quiet` — one identity value per row, no envelope

- **Pipeable** — JSON on stdout, errors on stderr
- **Filterable** — `--select` keeps a subset of fields. Dotted paths descend into nested structures; arrays traverse element-wise. Critical for keeping context small on verbose APIs:

  ```bash
  sendfox-pp-cli automations list --agent --select active,automation_items,automation_triggers
  ```
- **Previewable** — `--dry-run` shows the request without sending
- **Offline-friendly** — sync/search commands can use the local SQLite store when available
- **Non-interactive** — never prompts, every input is a flag
- **Explicit confirmation** — `--agent` does not imply `--yes`; pass `--yes` separately only after the target, arguments, and side effects are clear
- **Explicit retries** — use `--idempotent` only when an already-existing create should count as success, and use `--ignore-missing` only when a missing delete target should count as success

### Response envelope

Commands that read from the local store or the API wrap output in a provenance envelope:

```json
{
  "meta": {"source": "live" | "local", "synced_at": "...", "reason": "..."},
  "results": <data>
}
```

Parse `.results` for data and `.meta.source` to know whether it's live or local. A human-readable `N results (live)` summary is printed to stderr only when stdout is a terminal AND no machine-format flag (`--json`, `--csv`, `--compact`, `--quiet`, `--plain`, `--select`) is set — piped/agent consumers and explicit-format runs get pure JSON on stdout.

## Paths and state

Agents should treat the CLI's path resolver as part of the runtime contract:

- Use `--home <dir>` for one invocation, or set `SENDFOX_HOME=<dir>` to relocate all four path kinds under one root.
- Use per-kind env vars only when a specific kind must diverge: `SENDFOX_CONFIG_DIR`, `SENDFOX_DATA_DIR`, `SENDFOX_STATE_DIR`, `SENDFOX_CACHE_DIR`.
- Resolution order is per-kind env var, `--home`, `SENDFOX_HOME`, XDG (`XDG_CONFIG_HOME`, `XDG_DATA_HOME`, `XDG_STATE_HOME`, `XDG_CACHE_HOME`), then platform defaults.
- `config` contains settings like `config.toml` and profiles. `data` contains `credentials.toml`, credential-scoped `data-<hash>.db` files, cookies, and auth sidecars. `state` contains persisted queries, jobs, and `teach.log`. `cache` contains regenerable HTTP/cache files.
- Stored secrets live in `credentials.toml` under the data dir. Existing legacy `config.toml` secrets are read for compatibility and leave `config.toml` on the first auth write.
- Authenticated default stores are isolated by a one-way credential hash. Never treat an unscoped legacy `data.db` as belonging to the active account; run `sync` to populate the scoped store. An explicit `--db` is an operator-controlled override.
- Run `sendfox-pp-cli doctor --fail-on warn` to surface path and credential-location warnings. `agent-context` exposes a schema v4 `paths` block for agents that need the resolved dirs.
- For MCP, pass relocation through the MCP host config. The MCP binary does not inherit CLI flags:

  ```json
  {
    "mcpServers": {
      "sendfox": {
        "command": "sendfox-pp-mcp",
        "env": {
          "SENDFOX_HOME": "/srv/sendfox"
        }
      }
    }
  }
  ```

Fleet precedence: an inherited per-kind env var overrides an explicit `--home` for that kind. Use `SENDFOX_HOME` or per-kind vars as durable fleet levers, and use `--home` only for a single invocation. Relocation is not reversible by unsetting env vars; move files manually before clearing `SENDFOX_HOME`, or `doctor` will not find credentials left under the former root.

## Automatic learning

This CLI ships a self-capturing learning loop. The CLI does its own bookkeeping: every invocation is journaled locally, a failed flag followed by a corrected retry auto-derives a `flag_alias` candidate, and a `teach` on a query family without a playbook auto-synthesizes a `playbook_candidate` from the session's journal. Your job is judgment only: `recall` 