Decision infrastructure for private market investors.
I've made over 150 investments in startups and scale-ups since 2019. What started as a learning exercise became a system — one that now consistently outperforms top-quartile venture benchmarks. Radar is the software behind that system.
I built Radar because no tool existed for how serious angels actually operate. I see mid-hundreds of opportunities a year and invest in roughly ten. I started in spreadsheets and scripts years ago, then — with Claude's help — built something coherent: software that tracks not just what I own, but how I decide, why I invested, and whether my reasoning holds up over time as results come in.
- Portfolio tracking — positions, valuations over time, cash flows, IRR (XIRR), TVPI/DPI, QSBS lot tracking, vintage-year and stage analysis
- Thesis attribution — tag every investment to the investment theses that motivated it, then measure whether thesis-driven bets actually outperform
- Deal pipeline — ingest inbound deal invites, track status changes through an append-only event log, link invites to investments when you wire
- Evaluation grading — import structured deal evaluations (markdown), then validate the rubric: does your score actually predict returns? (
eval validatecomputes Spearman correlation, per-band performance, and calibration) - Bet sizing — Kelly-criterion check sizing from your score bands and outcome distributions, with portfolio-level caps
- GP / source quality — which syndicate leads actually make you money
- Quarterly updates — investor updates as markdown files with a queryable metrics index (ARR, burn, runway, headcount over time)
Everything is CLI-first. Report functions return pure JSON, so a web UI can sit on top later.
Your investment theses, tagging rules, scoring rubric, kill criteria, GP tiers, and outcome distributions live in a lens — a directory of plain JSON files, separate from the engine. The repo ships with an empty, fully documented template; your own calibration stays in ~/.radar/, outside the repo.
node src/cli.js lens init my-lens # scaffold lenses/my-lens/ from the template
# edit lenses/my-lens/*.json — see lenses/_template/README.md for every field
# activate it: {"active_lens": "my-lens"} in .radar/config.json
node src/cli.js lens active # confirm what's loaded
node src/cli.js lens retag # apply your tagging rules to imported positionsTo keep your lens out of the repo entirely, move it to ~/.radar/lenses/<name> — user-level lenses are found by the same name lookup and take precedence.
Lenses are portable and shareable — export yours with lens export, install someone else's with lens install. The engine is open source; your judgment is the config.
Full configuration runbook — clone to fully-configured, with verify steps per stage: docs/SETUP.md
- Node.js v20+
- Python 3.9+ (analytics sidecar — Kelly solver, rubric validation; stdlib only, no pip installs)
- A database — zero-setup local embedded database (
DATABASE_URL=file:./radar.db) or any PostgreSQL / Neon connection string
git clone https://github.com/ckoglmeier/radar.git
cd radar
npm install
npm run setup-hooks # pre-commit hook: blocks sensitive files, runs the test gatecp .env.example .env # choose local embedded or Postgres (see .env.example)
node src/cli.js db:setup # run all migrations
node src/cli.js lens init my-lens # create your lens (see above)Optional config, each with a documented .example beside it (the real files are gitignored — they hold your numbers):
| File | Used by | Purpose |
|---|---|---|
src/config/bet-sizing.json |
bet-size |
Risk capital, annual budget, score→check tiers |
src/config/lead-prefixes.json |
import transactions |
Syndicate-lead names to strip when parsing SPV descriptions |
DEAL_LOG_DIR in .env |
eval import |
Path to your deal-evaluation markdown directory |
Positions and transactions come in via CSV import. The bundled importer today is the AngelList export connector (more sources planned). If your data lives elsewhere, you can adapt the connector or insert rows directly — the schema is plain SQL in src/db/migrations/.
node src/cli.js import angellist path/to/portfolio.csv # positions
node src/cli.js import transactions path/to/transactions.csv # cash-flow ledgernode src/cli.js portfolio summary
node src/cli.js portfolio list --sort multiple
node src/cli.js portfolio detail "Company Name"
node src/cli.js portfolio performance
node src/cli.js thesis performance
node src/cli.js eval validate| Command | Description |
|---|---|
portfolio summary |
Portfolio overview with key metrics (--since/--until for date windows) |
portfolio list |
All investments — sort by date, invested, multiple, name, net value |
portfolio detail <company> |
Full detail: IRR, valuation history, QSBS 5-year countdown, lot tracking |
portfolio performance |
YTD, trailing 12M, vintage-year, and quarterly cash-flow views |
portfolio treemap |
Composition by thesis, stage, vintage, or lead |
portfolio by-stage |
DPI/TVPI by stage bucket |
portfolio override <company> <status|clear> |
Sticky status override that survives re-imports |
portfolio reconcile |
Cash flows vs positions: mismatches, orphans, duplicates |
portfolio link <type> <id> <inv-id> |
Manually link an orphan cash flow or invite |
| Command | Description |
|---|---|
thesis performance |
Performance by thesis cluster, with weighted attribution |
thesis untagged |
Investments not tagged to any thesis |
thesis eras |
Era-over-era comparison (--since/--until) |
thesis stages |
DPI/TVPI by stage with barbell roll-up |
| Command | Description |
|---|---|
eval import |
Parse deal-evaluation markdown from DEAL_LOG_DIR into the DB |
eval list / eval detail <company> |
Browse graded evaluations |
eval validate |
Does your score predict returns? Correlation, band performance, calibration, misses |
eval discover |
Data-driven thesis cluster discovery from actual outcomes |
eval reconcile |
Pipeline passes that scored high — what did you walk away from? |
bet-size <company> |
Kelly-based check sizing for a graded company |
| Command | Description |
|---|---|
pipeline list / detail <slug> / events <slug> |
Inbound deal invites with full event history |
sync invites --file <json> |
Ingest invite emails (AngelList invite format today) |
gp summary / gp detail <name> |
Syndicate-lead quality: deployed, returned, performance |
| Command | Description |
|---|---|
updates new <company> -q "Q1 2026" |
Scaffold a quarterly update file (markdown is the source of truth) |
updates import / list / detail <id> / timeline <company> |
Queryable metrics index over update files |
lens active / list / init / inspect / install / export / retag |
Manage thesis frameworks |
| Command | Description |
|---|---|
db:setup / db:migrate |
Initialize schema / run pending migrations |
export:beancount [path] |
Export the portfolio as a Beancount plain-text ledger |
- Runtime: Node.js (ESM), plus a Python 3 analytics sidecar called via JSON-over-stdin (Kelly solver, statistical validation — standard library only)
- Database: Embedded PGlite (local, zero-setup) or PostgreSQL via
@neondatabase/serverless(Neon / any Postgres) - CLI:
commander+chalk - No ORM. Raw parameterized SQL. Intentional at this scale.
- Layering:
src/reports/returns pure data;src/cli/printers/formats it. A future web GUI reuses the report layer untouched.
npm test # 730+ assertions across Node + Python suites; also runs as the pre-commit gateTest suites are fully self-contained — synthetic fixtures, no external files or personal data required.
Licensed under AGPL-3.0 — anyone hosting a modified version commercially must open-source their changes back to the community.
Theses sharpen slow, each bet a question answered — the signal compounds.
— from CK's desk