# Host buyer-list runner Homies prepares the matching properties and message through one API. The `homies_buyer` runner adds a persistent, account-owned watch and SMTP delivery on the agent's host. Its SQLite database stores watch state, reviewed authorization, delivery attempts and confirmed listing IDs across process restarts. Use a durable local Mac/Linux host volume; Vercel function storage is ephemeral and is not suitable for this database. SQLite and POSIX process locks protect a single host. Do not put the database or its lock directory on NFS, cloud-sync storage or a volume shared by multiple hosts. Windows is not supported by this runner. The starter experience is a single natural request: > Send my buyers homes they’ll like. The assistant should infer the saved account, client search and available sender from its existing context. It asks for missing context conversationally, one simple question at a time, then creates the configuration itself. Users should not need to edit JSON, fill placeholders or paste keys into chat. A ready runner does not mean a schedule has been installed or a client email has been sent. ## Host preparation Run commands from the `homies-api` checkout with its Python environment. Save the individual Homies account key in the host secret environment as `HOMIES_API_KEY`. SMTP credentials remain in host secret environment variables; the configuration contains their variable names. `HOMIES_API_URL` can select an already verified Homies deployment; its default is `https://homies-api.vercel.app`. The assistant should use the saved sender's actual provider settings and established recipient when preparing a real watch. By default, private state lives at `~/.local/share/homies/buyer-agent.sqlite3`. The CLI restricts the dedicated Homies directory to mode `0700`; the runner secures the database. `--db PATH` selects another private, durable state file and must precede the subcommand. The runner does not need administrator permissions. This complete fictional example explains the configuration shape. It uses reserved example addresses and cannot be used as a real delivery setup. An assistant generates the real configuration after collecting the necessary context; users do not edit this sample. ```json { "search": { "country": "US", "location": "San Diego, CA", "listing_type": "sale", "beds_min": 3, "price_max": 1000000, "limit": 20 }, "buyer_name": "Demo Buyer", "agent_name": "Homies Demo Agent", "max_properties": 5, "recipient": "buyer@example.com", "smtp": { "host": "smtp.example.com", "port": 465, "tls": "implicit", "sender_email": "agent@example.com", "sender_name": "Homies Demo Agent", "username_env": "HOMIES_SMTP_USERNAME", "password_env": "HOMIES_SMTP_PASSWORD", "timeout_seconds": 30 }, "schedule": { "local_time": "08:30", "timezone": "America/Toronto", "weekdays": [0, 1, 2, 3, 4] } } ``` Weekdays use Monday `0` through Sunday `6`. Scheduling uses the supplied local time and IANA time zone. At a daylight-saving gap, it uses the first valid minute after the requested time; at a repeated time, it runs only the first occurrence. SMTP supports implicit TLS, usually port `465`, or `starttls` with the sender's provider settings. Keys and passwords must not be embedded in the configuration. Save the generated configuration privately. ## Review and authorization The host first calls `create --config` with the file the assistant prepared, then `preview` with the returned watch ID. Creating and previewing a watch do not send an email. The preview returns the configuration in `scope`, the exact email draft in `draft.email_draft`, and its `preview_hash` for review. Only after the user has authorized the displayed sender, recipient, search and recurring schedule does the host call `authorize` with that watch ID, `--preview-hash`, `--authorized-by`, and `--allow-send`. The required flag records existing permission; it is not permission generated by the assistant. A changed or stale preview must be reviewed again according to the runner's checks. `preview` and `status` intentionally return details needed for review, including customer configuration or message content. Keep their output inside the user's private session. Other CLI commands emit operational summaries, and command errors omit raw exceptions and configuration values. ## Running and stopping Once configured and authorized, the host scheduler invokes: ```sh .venv/bin/python -m homies_buyer run-due ``` Call it every minute, or at another documented polling frequency, from the checkout directory with the same private environment and database. A scheduler must be explicitly installed in the host's existing scheduling system. This guide and the CLI do not install cron entries, system services or remote automations. A run occurs when the host processes it, so timing can lag by the polling interval or a host outage. The assistant uses the returned IDs directly in subsequent commands: | Command | Purpose | | --- | --- | | `create --config` | Create a watch from a privately saved JSON file. | | `preview` | Prepare the draft and review hash for one watch. | | `authorize --preview-hash --authorized-by --allow-send` | Record the user's reviewed recurring sending scope. | | `list` / `status` | Inspect watches or detailed state for one watch. | | `pause` / `resume` | Pause or resume an existing watch. | | `cancel` | Cancel a watch. | | `suppress` | Prevent future delivery to the specified recipient. | | `run-due` | Process due watches once. | | `reconcile --outcome --evidence` | Resolve an uncertain delivery using provider evidence. | Watch commands take the returned watch ID; `suppress` takes the recipient; `reconcile` takes the outbox ID. Run any command with `--help` for its exact syntax. Resuming a watch does not substitute for establishing sending scope. ## Delivery outcomes The runner prepares a buyer list through Homies and sends through the configured host transport. No new matches should produce no email. Confirmed listing IDs are remembered so the same properties are not repeatedly sent. SMTP acceptance means **accepted for delivery**, not proof of inbox delivery or reading. If a connection fails after a send may have happened, reconcile the outbox using provider evidence before attempting another send. Use outcome `accepted_for_delivery` when the provider accepted the message, or `not_sent` only when evidence establishes that it did not. Never guess an outcome merely to unblock another attempt. Reconciliation does not automatically resume the watch; review its state before deliberately resuming it. The runner holds a per-watch OS lock until submission and receipt persistence finish. A clock lease expiring does not authorize another live sender or early reconciliation. Lock files remain on disk intentionally; their presence alone does not mean a process is active. The OS releases the lock when a process exits. An interrupted dispatch becomes uncertain when a later worker acquires the lock after the lease expires. Do not delete lock files or edit outbox state to force a retry. SMTP Message-ID is a correlation identifier, not a provider idempotency guarantee. After confirmed non-acceptance, bounded retries reuse the exact stored MIME bytes and Message-ID. Five failed attempts pause the watch. Authentication and permanent rejections require correction. Source rate limits honor Retry-After. Known-unsent payloads older than one day are discarded and refreshed, while uncertain payloads remain held until evidence resolves them. A recipient opt-out persists independently of the watch and blocks creation or reactivation of other watches for that address. To change search criteria, recipient, sender or schedule, cancel the old watch and create and review a new one. Existing permission is never silently broadened. Keep the old ledger for its audit history; each saved search has its own listing ledger. Current Homies search covers US listings. Canadian buyer matching needs an authorized Canadian listing source. This runner does not use Paperwork's showing-booking endpoint to send buyer emails and does not accept publisher terms. A connected Paperwork Gmail account is separate from the host SMTP configuration.