PTBot is a two-pass precedent transaction research bot for Warp/Oz agents. It discovers M&A transactions for a user-defined sector, geography, and date range; filters to deals with standard disclosed or computable valuation multiples; then produces a QC-checked deliverable in markdown, PDF, and Excel.
- Runs four parallel discovery scouts across press/news, regulatory filings, deal databases, and industry/analyst sources.
- Deduplicates deal candidates by target/acquirer pair.
- Filters out transactions without qualifying standard valuation multiples.
- Runs deal-aware deep-dive agents on the qualified transaction set.
- Produces a final QC-reviewed precedent transaction report.
- Generates supporting markdown, JSON metadata, PDF output, and an Excel comps workbook.
- Python 3.11+
- Taskfile (
task) for project commands - Warp/Oz CLI access for live agent orchestration
- The
attack.marketskill installed at~/.agents/skills/attack.market/
task setupThis creates .venv, installs PTBot in editable mode, and installs development dependencies.
Preview the generated pipeline configuration without running agents:
.venv/bin/ptbot \
--sector "Vertical SaaS" \
--geography "Boston" \
--start-date 2024-01-01 \
--end-date 2024-12-31 \
--config-onlyRun a full precedent transaction analysis:
.venv/bin/ptbot \
--sector "Vertical SaaS" \
--geography "Boston" \
--start-date 2024-01-01 \
--end-date 2024-12-31 \
--output-dir ./precedent-txn-outputOptional filters:
--min-multiples: minimum number of standard multiples required per included deal--deal-size-min: minimum deal size filter--deal-size-max: maximum deal size filter--timeout: per-agent timeout in seconds, defaulting to900--output-dir: output directory, defaulting to./precedent-txn-output--db-path: SQLite database path (e.g.~/.ptbot/ptbot.db). Omit to skip persistence.
When --db-path is provided, the run is recorded in a local SQLite database alongside all deal candidates and their qualified status. This enables cross-run queries and powers the sweep runner.
ptbot-sweep builds a deal database automatically by running ptbot across a configurable set of markets and annual time windows. Combinations already present in the database are detected and skipped, so the sweep can be interrupted and resumed freely.
Copy sweep.example.toml and edit the [[markets]] list:
[sweep]
years_back = 10
db_path = "~/.ptbot/ptbot.db"
output_base_dir = "./precedent-txn-output"
min_multiples = 1
timeout = 900
[[markets]]
sector = "Vertical SaaS"
geography = "United States"
[[markets]]
sector = "HealthTech"
geography = "United States".venv/bin/ptbot-sweep --config my-sweep.toml --dry-runPrints every (sector, geography, year) combination that would be executed — no agents are invoked.
.venv/bin/ptbot-sweep --config my-sweep.tomlRuns all combinations sequentially, oldest year first. Progress is printed as each run completes:
[sweep] 2 market(s) × 11 windows = 22 combinations
[sweep] run Vertical SaaS / United States 2016 ...
[sweep] done Vertical SaaS / United States 2016
[sweep] run Vertical SaaS / United States 2017 ...
...
[sweep] complete — 22 run(s), 0 skipped
On a subsequent run, completed combinations are skipped automatically:
[sweep] skip Vertical SaaS / United States 2016
[sweep] skip Vertical SaaS / United States 2017
...
[sweep] complete — 0 run(s), 22 skipped
Before each run the sweep queries the SQLite database for an existing row in the runs table whose stored params JSON matches the exact (sector, geography, start_date, end_date) combination. If a match is found the combination is skipped without calling any agents. This means:
- Interrupting a sweep mid-way and restarting resumes from the first incomplete combination.
- Adding new markets to the config only runs those new combinations.
- Re-running the same config after it fully completes is a no-op.
Each annual run writes its outputs under a slugified path:
{output_base_dir}/{sector-slug}/{geography-slug}/{year}/
final_deliverable.md
final_deliverable.pdf
precedent_comps.xlsx
supporting/
metadata/
For example: ./precedent-txn-output/vertical-saas/united-states/2023/
--config(required): path to TOML config file--db-path: override thedb_pathfrom config--dry-run: print planned runs without executing any agents
ptbot sweep:auto populates the deal database from the command line — no TOML config file needed:
# Sweep two sectors over the last 5 years using cloud agents (recommended)
.venv/bin/ptbot sweep:auto \
--sectors "FinTech,HealthTech" \
--geography "United States" \
--years 5 \
--environment <oz-env-id>
# Preview what would run without invoking any agents
.venv/bin/ptbot sweep:auto \
--sectors "SaaS,Drones,AI" \
--geography "United States" \
--dry-run
# Sweep locally (no --environment; uses local oz agents)
.venv/bin/ptbot sweep:auto \
--sectors "VerticalSaaS" \
--geography "Europe" \
--years 3Flags:
--sectors(required): comma-separated list of sectors--geography(required): geographic scope applied to all sectors--years N: years to look back (default: 5)--environment ENV_ID: Oz cloud environment — enables cloud dispatch and parallel execution--max-workers N: parallel pipeline cap (default: 4)--timeout N: per-pipeline agent timeout in seconds (default: 900)--db-path PATH: SQLite database (default:~/.ptbot/ptbot.db)--dry-run: print planned runs without invoking agents
Combinations already present in the database are skipped automatically, so it is safe to re-run.
Once the database has been populated (via --db-path or ptbot-sweep), explore it from the terminal:
# List recent pipeline runs with deal counts
.venv/bin/ptbot query runs --db-path ~/.ptbot/ptbot.db
# Search deals by sector and show only qualified ones
.venv/bin/ptbot query deals --sector "FinTech" --qualified-only
# Export all deals matching a filter to CSV
.venv/bin/ptbot query export --sector "FinTech" --output fintech-deals.csv
# Export to JSON for scripting
.venv/bin/ptbot query export --format json
# JSON output for any subcommand
.venv/bin/ptbot query runs --format json
.venv/bin/ptbot query deals --geography "United States" --format jsonFlags available on all query subcommands:
--db-path: path to the SQLite database (default:~/.ptbot/ptbot.db)--format table|json(orcsv|jsonforexport)
Additional flags:
query runs:--limit N,--since YYYY-MM-DDquery deals:--sector,--geography,--since,--qualified-only,--limit Nquery export:--sector,--geography,--qualified-only,--limit N,--output FILE
A full run writes:
final_deliverable.md: QC-reviewed markdown reportfinal_deliverable.pdf: PDF version of the final reportprecedent_comps.xlsx: IB-formatted Excel comps workbooksupporting/qualified_deals.json: filtered deal manifestsupporting/pass1_compiled_deals.md: compiled discovery scout outputsupporting/pass2_compiled_deep.md: compiled deep-dive outputsupporting/qc_report.md: QC agent outputmetadata/run_metadata.json: run parameters and agent execution metadata
task fmt
task lint
task test
task test:coverage
task build
task checktask check is the pre-commit gate and runs formatting checks, linting, type checking, tests with coverage, and package compilation.
src/ptbot/cli.py:ptbotcommand-line interfacesrc/ptbot/orchestrator.py: two-pass agent orchestration and output writingsrc/ptbot/prompt_builder.py: scout, deep-dive, QC, and config prompt generationsrc/ptbot/models.py: validated data modelssrc/ptbot/pdf.py: markdown-to-PDF generationsrc/ptbot/excel.py: Excel comps workbook generationsrc/ptbot/db.py: SQLite persistence layer (runs and deals tables)src/ptbot/sweep.py: sweep runner logic (config models, window generation, orchestration)src/ptbot/sweep_cli.py:ptbot-sweepcommand-line interfacesweep.example.toml: annotated sweep config templatetests/: unit and integration tests