The problem this solves
The gate is an exit code. A send pipeline that runs a verification step and continues regardless has no gate at all; the step is decoration. What CI understands is zero or non-zero, so the verification command has to compute the invalid share itself and refuse to succeed when the share passes the threshold you set. Past 5% invalid, the build fails, the send stays in the queue and someone looks at the file.
Bulk verification is a job the CLI was shaped for. It reads its key from the environment, streams results to stdout and progress to stderr, exits with codes a runner can branch on, and prints JSON when a script needs to parse it. A verify step in a pipeline is then two lines: the command, and the runner's own on-failure rule.
The output file matters as much as the exit code. A rep or a script that opens <out.csv> needs the original columns intact plus a status per row - deliverable, risky, catch-all, invalid, unknown - and a confidence value, so the deliverable rows can go straight into the sequence and the invalid ones can be fixed or dropped with the reason next to them.
How the mission runs
- Run the verification over the file. The Lead Verification Agent gives you the command: the CLI's verification call with <file.csv> as input, the column that holds the email named, and <out.csv> as the output path. Every address passes email verification in batches, and the command prints progress per batch to stderr so a long file shows movement in the CI log.
- Write status and confidence per row. <out.csv> is <file.csv> with two columns appended: status and confidence. Rows keep their order and every original column, so the file drops back into whatever produced it. Catch-all domains are labeled as such rather than counted as deliverable, which is the difference between a clean send and a bounce spike.
- Apply the threshold. A threshold flag set to 5 tells the command to compute the invalid share over all rows and exit with a non-zero code when it is exceeded, printing the share, the counts by status and the first invalid rows to the log. Below the threshold it exits 0 and the pipeline continues to the send step.
- Wire it into CI. The key is read from an environment variable set as a CI secret, minted for the pipeline alone so it can be revoked without touching any other surface. The agent shows the step for your runner, the exit codes to expect - 0 for a pass, 1 for an API or run failure, 2 for a usage error, and the non-zero code the threshold check uses - and how to keep <out.csv> as a build artifact.
The prompt
This is the exact objective the agent receives. Swap the obvious placeholders for your own domain, segment or channel and run it as-is from the console, Slack, or the API.
What comes back
The verification command with its flags, a CI step that runs it before every send, and <out.csv> as the artifact: every row from <file.csv> with status and confidence appended. When more than 5% of rows are invalid the step exits non-zero, the send is blocked, and the log shows the counts by status and the rows that failed, so the fix is a file edit rather than a bounce report the next morning. Every address verified is metered and recorded in the audit trail under the pipeline's key.
Make it yours
- Count risky and catch-all rows toward the threshold, or keep the threshold on invalid only and route catch-alls to a slower send, depending on how strict your sending domain needs to be.
- Verify only the rows added since the last run by passing a filtered file, so a daily pipeline meters the new addresses rather than the whole list every time.
- Write a second file of deliverable rows only, ready for Lemlist or Instantly, while <out.csv> keeps the full picture.
- Run the same step against list <name> instead of a CSV: the CLI reads the list rows, verifies them and writes the statuses back to the list.
Frequently asked questions
Why fail the build instead of just dropping invalid rows?
Because a file that is 20% invalid is telling you something about its source, and a silent drop hides it. Below the threshold the command still writes every status, so dropping the invalid rows is a one-line filter on <out.csv>; above it, a person should look before anything sends.
What does verification cost?
It meters per address checked, and the command prints the credits used at the end of the run. Verifying only the new rows each day keeps the cost proportional to what changed.
How long does a large file take?
Long enough that the step deserves a generous timeout in the runner. Progress prints per batch to stderr, so the CI log shows movement, and the run reports its totals by status when it finishes.
Does this touch my sending tool?
No. The command reads a file and writes a file. Loading the deliverable rows into an outreach tool is a separate, approval-gated step you can add after the gate passes.