Most runtime policy knobs now live in ~/.finch/config.json.
That includes:
- cache TTL baselines
- hydrate batch size
- search and collection page caps
- low-yield thresholds
- duplicate frontier threshold
- pressure stop threshold
The shipped defaults in config.example.json match the current production behavior.
For collection commands, finch follows this model:
- Build a normalized request fingerprint.
- Try cache first unless
--liveis set. - Choose the healthiest cookie for the endpoint family.
- Fetch the discovery surface.
- Normalize results.
- Hydrate discovered entities through batch endpoints when needed.
- Continue pagination while the source is still productive.
- Save cache, cookie observations, and optional cursor state.
The runtime treats these as separate traffic classes:
| Family | Typical commands |
|---|---|
search |
search posts, search users |
profile |
user posts, user media, user articles, user highlights |
list |
list posts, list members |
article |
article get |
hydrate |
batch tweet/user hydration |
deep |
tweet thread and edit-history reads |
Each family gets its own cookie health and request observations.
Cookies are used as a session pool, not blind round-robin rotation.
- Better family-specific health score
- Lower recent usage for that family
- Last-good cookie pinned by saved cursor state when resuming pagination
This means:
- a search-heavy cookie does not have to carry profile traffic
- resumed pagination can stay on the same good session
- one bad cookie does not poison all families equally
finch tracks:
- success/failure counts
- recent
429s - suspicious responses
- remaining/limit headers when available
- reset timestamps
- observed latency
Discovery surfaces do not always return the richest payloads. finch therefore hydrates in batches.
| Endpoint type | Current runtime role |
|---|---|
TweetResultsByRestIds |
Tweet hydration |
UsersByRestIds |
User hydration |
finch currently uses a default hydrate batch size of 400.
Why:
- exact batch hydration is cheaper than many single-entity calls
- live tests proved much larger payloads work
400is a strong production default without pushing to the observed upper edge every time
This value is configurable through:
{
"hydration": {
"default_batch_size": 400
}
}- Collection commands can keep bonus items from a final page.
- Batch commands are exact: only requested ids should be returned.
| Tier | Purpose |
|---|---|
frontier |
First-page collection results and hot surface reads |
surface_page |
Deeper paginated surfaces |
entity |
Single entities and stable records |
derived |
Derived result sets such as people-search shaped outputs |
failure |
Thin, empty, or suspicious responses |
TTL is not just a fixed number. It is adjusted using:
- cache tier
- endpoint family
- page depth
- returned count
- requested limit
- whether the result is thin/empty
- family pressure
- response confidence
The base TTLs are configurable through:
{
"cache": {
"tier_ttl_s": { "...": 0 }
}
}The finer-grained dynamic multipliers remain internal defaults in code.
- thin or empty results get shorter TTLs
- deeper pages get longer TTLs
- high pressure raises TTL to avoid hammering X again immediately
- low-confidence payloads get shorter TTLs
- stable entities live longer than hot first-page frontiers
finch no longer uses a flat internal page cap as the main strategy.
Pagination continues while all of these are still true:
- target not reached
- cursor still exists
- frontier is not looping
- page yield is still useful
- family pressure is not too high
- hard safety cap is not exceeded
Typical stop reasons:
| Stop reason | Meaning |
|---|---|
limit_reached |
Requested target reached |
exhausted_source |
No next cursor / no more source content |
duplicate_frontier |
Same frontier is repeating |
low_yield_stop |
Consecutive pages added too little new value |
pressure_stop |
Runtime pressure says stop live paging |
cursor_missing |
Cursor could not be advanced |
All of the pagination hard caps and thresholds are configurable through:
{
"pagination": {
"search": { "...": 0 },
"collection": { "...": 0 },
"yield_rules": { "...": 0 },
"thresholds": { "...": 0 }
}
}For collection commands:
--limitis a target, not a hard cut- if the final productive page pushes the total over the target, the extra rows are kept
For exact trimming:
--strict-limitFor from: search queries:
- X search is still used for discovery
finchpost-filters top-level authors- this makes single-author and multi-author
from:queries strict even when X search ranking is loose
Collection commands can persist cursor state with:
--save-cursorSaved state includes:
- request fingerprint
- endpoint name
- cursor value
- page depth
- last-good cookie id
This makes resumed pagination more stable and less random.