Skip to main content
Prefix a permit tag with - to find properties that have no permit of that type on record. Because a property can look permit-free due to data coverage rather than reality, every absence answer carries trust metadata scoring how far to believe it.
You can combine absence with presence — --permit-tags "roofing,-solar" finds properties with a roofing permit but no solar permit.
Properties are in beta, and the absence-trust surface in particular may still change in response to how it’s used in practice.

How —permit-from Changes the Meaning

Once any positive filter is present, the exclusion reverts to “never” — a property record carries only one date per work type, so per-filter dates can’t be composed.
There is no --permit-to. “No roofing between 2018 and 2021” and “no solar before 2020” are not expressible, because a permit inside a closed window is hidden by a later one. Only “ever” and “since date D” work. Use shovels permits search for windows.

Reading the Per-Row trust Object

Each absence row carries a trust object:
For lead generation, filter to rows with coverage_tier == "high", an empty flags array, a data_horizon at or after your --permit-from, and trust_jurisdiction_basis == "own":

meta.trust_summaries Is an Array, One Entry Per API Page

This is the one place CLI output differs structurally from the REST API. The API returns a single trust_summary per page, scoped to that page’s rows. The CLI’s --limit merges pages — so it collects each page’s summary into a meta.trust_summaries array rather than combining them:
205 records came back as three API pages (100 + 100 + 5), so there are three summaries.
The CLI does not aggregate these, and you shouldn’t average them either. Each rate is row-weighted over its own page, so a plain mean across pages of unequal size is wrong. The CLI has no basis on which to re-derive a correct merged figure, so it hands you the raw per-page values instead of inventing one.
Read the worst page rather than the average when you need one number to act on:
An index in the array is not a page number: pages that carry no summary contribute no entry.

Presence-Only Searches Carry No Trust Surface

Drop the - and both the row-level trust object and meta.trust_summaries disappear entirely:
The key is omitted rather than returned empty, so in a script test for presence before reading it:

What Suppression Does to Your Result

Where coverage for a work type in an area is too thin to answer honestly, those properties are dropped from the result entirely rather than returned as false negatives. suppressed_scopes reports how many scopes were removed. This means an absence search can legitimately return fewer rows — or zero rows — in a low-coverage area, while the same query returns plenty in a well-covered one. That’s suppression working, not a bug.
Shovels knows permits, not installations. “No solar permit on record” is not the same claim as “no solar panels” — unpermitted work exists. Trust fields quantify data coverage, not construction reality.