automate cold mailing
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-07 22:00:54 +05:30
.github/workflows P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
docs Add architecture doc and AGENTS.md 2026-10-07 21:38:10 +05:30
src/harness P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
tests P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
.env.example P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
.gitignore P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
.python-version P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
AGENTS.md P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
pyproject.toml P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
README.md P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30
uv.lock P0: repo skeleton — uv package, SQLite schema, CLI (init/run/review/send), fetch-ladder interface, run log, Langfuse tracing, tests, CI 2026-10-07 22:00:54 +05:30

email-harness

Batch agent harness for recruiter outreach: it discovers recruiters and hiring managers for open roles, finds and verifies their email addresses, tailors a resume to each role, composes a short personalized email, and parks every message at a human approval queue before it is sent.

The design of record is docs/architecture.md — read it before changing anything. This README covers how to run what exists today.

Status — P0 skeleton

Implemented per the P0 row of architecture §11:

  • src/harness package: Python 3.12+, uv-managed with a committed lockfile, ruff + pytest.
  • SQLite schema for the full data model (§6), applied by a small numbered-SQL migration runner.
  • CLI: harness init | run | review | send.
  • Fetch-ladder interface (§7): FetchLevel L0–L6, FetchResult, LadderFetcher; L1 (httpx) implemented, L2–L6 declared as stubs that fail loudly.
  • Durable run log: idempotency keys, attempts, results, cost rows.
  • Tracing via Langfuse when keys are configured, no-op otherwise.
  • Pipeline stages S0–S7 registered as explicit no-ops (real logic lands in P1–P5).

Quickstart

uv sync
uv run harness init            # create data/harness.db and apply migrations
uv run harness run             # no-op pipeline run; writes a run row and traces
uv run harness run --key demo  # same key twice -> second run is skipped (idempotent)
uv run harness review          # list pending approvals (empty at P0)
uv run harness send            # refuses: sender lands in P4 (exit code 2)

Configuration

All variables are optional, prefixed HARNESS_, read from the environment or a local .env (see .env.example). Global CLI flags --db PATH and --log-level override the matching settings.

Variable Default Purpose
HARNESS_ENV dev Environment label (dev/test/prod).
HARNESS_DB_PATH data/harness.db SQLite database location.
HARNESS_LOG_LEVEL INFO Log level.
HARNESS_TRACING 1 Enable tracing when Langfuse keys are set.
HARNESS_LANGFUSE_PUBLIC_KEY — Langfuse public key.
HARNESS_LANGFUSE_SECRET_KEY — Langfuse secret key.
HARNESS_LANGFUSE_HOST https://cloud.langfuse.com Langfuse host (self-hosting supported).
HARNESS_FETCH_TIMEOUT_S 20 Fetch timeout (L1).
HARNESS_FETCH_USER_AGENT Chrome UA User agent for L1 fetches.

Exit codes

Code Meaning
0 Success — includes idempotent skips ("run already completed").
1 Error (e.g. deciding an approval that is not pending — fail closed).
2 Usage error, or refused / not implemented yet (e.g. send before P4).

Layout

src/harness/
  cli.py            # harness init | run | review | send
  config.py         # pydantic-settings
  db.py             # SQLite wrapper (WAL, explicit tx) + migration runner
  migrations/       # numbered .sql migrations
  runlog.py         # durable run log: idempotency, attempts, costs
  observability.py  # Langfuse tracer / no-op tracer
  pipeline.py       # stage protocol + runner
  stages/           # S0–S7 (no-ops until P1+)
  fetch/            # fetch-ladder interface + L1 implementation
tests/

Development

uv run pytest
uv run ruff check .
uv run ruff format --check .

CI (GitHub Actions, .github/workflows/ci.yml) runs the same plus an end-to-end smoke: harness init and two harness run --key ci-smoke calls, where the second must be skipped.

Roadmap

P1 jobs (S0–S1) → P2 contacts (S2–S3) → P3 tailoring (S5) → P4 outreach (S6 + sender) → P5 reply loop (S7) → P6 hardening. See docs/architecture.md §11.