Platform Pipelines Agents Human review Self-improvement Observability Deployment Security Use cases Compare Docs Pricing Roadmap Get early access

Sourcing and scoring

Every morning, crawl new listings from several sources, keep the ones worth a look, price them and put the profitable ones in front of an analyst. This is Millstream's reference pipeline and its end-to-end acceptance test: real estate renovation deals, though the shape fits any sourcing work.


The pipeline

flowchart LR
  T(["daily, 06:00"]) --> A[crawl source A] & B[crawl source B]
  A & B --> D{{dedupe}} --> S["score (agent)"] --> F1{{"score at least 70"}}
  F1 --> R[rentability] --> F2{{"margin at least 15%"}} --> V[/analyst review/] --> P[PDF report]
pipeline: property-sourcing
description: Daily sourcing of renovation opportunities

vars: { city: Lyon, maxPrice: 400000, minScore: 70, minMarginPct: 15 }
secrets: [sourceAToken]

triggers:
  daily: { cron: "0 6 * * *", tz: Europe/Paris }

streams:
  listings.raw: { retention: 90d, redact: [/seller/phone] }

steps:
  crawl-source-a:
    action: lab/crawl-source-a@1.2
    in: trigger.daily
    out: listings.raw
    config:
      filters: { city: "${vars.city}", maxPrice: "${vars.maxPrice}" }
      token: "${secrets.sourceAToken}"
  crawl-source-b:
    action: lab/crawl-source-b@0.9
    in: trigger.daily
    out: listings.raw
    config: { filters: { city: "${vars.city}", maxPrice: "${vars.maxPrice}" } }
  dedupe:
    action: dedupe
    in: listings.raw
    out: listings.unique
    config: { key: "item.addressNorm + ':' + string(item.surfaceM2)", window: 30d }
  score:
    action: lab/score-listing@2
    in: listings.unique
    out: listings.scored
    concurrency: 8
  keep-good:
    action: filter
    in: listings.scored
    out: listings.shortlist
    config: { expr: "item.score >= vars.minScore" }
  rentability:
    action: ./actions/rentability
    in: listings.shortlist
    out: listings.priced
  keep-profitable:
    action: filter
    in: listings.priced
    out: listings.selected
    config: { expr: "item.marginPct >= vars.minMarginPct" }
  analyst-review:
    action: review
    in: listings.selected
    out: listings.approved
    config: { inbox: analysts, timeout: 72h, onTimeout: reject, editable: [/marginPct, /notes] }
  report:
    action: lab/pdf-report@1
    in: listings.approved
    out: reports.pdf

budget: { runUsd: 25 }

What Millstream does for it

Streams and steps

The agent

The analyst

Personal data


How it learns

The M5 exit scenario ran this pipeline's fixtures through the whole loop, offline and deterministic. Analysts lowered the scores of poor listings; the insights projector found the pattern, and the improve pipeline drafted a lessons file for score. Its backtest on 46 sampled deliveries raised agreement with the reviewers from 0.58 to 1.00. In a second fixture, an agent step whose answers followed a rule was distilled into Go code: on 270 holdout items it covered 260 with agreement 1.000, and the next day cost 0.008385 USD against 0.227307 USD on the agent alone, 3.7%. A person accepted both proposals before they applied.


Figures to watch

Figure What it tells you
Intervention rate on analyst-review How much of the shortlist still needs a person
Cost per approved item What the agent spends per deal the analysts keep
waste insight on score Agent spend on listings a later filter or reviewer discarded
Edit rate and most edited pointers Where the analysts correct the pipeline, and which step to fix
Dead letters per crawler A source that changed its pages

Next

Pipelines · Self-improvement · Getting started