What comes from where
A species page is assembled from public sources, each named on the page where its data appears, with the licence it came under. The name and its synonyms, family and order come from the GBIF Backbone Taxonomy; a name the backbone holds as a synonym is followed to the species it accepts (and an accepted subspecies or variety one step further, to its species), and the page says which name was asked for. The native range comes from the World Checklist of Vascular Plants at Kew, read from Kew's files; a name WCVP lists more than once (a homonym) is told apart by authorship, and when authorship does not decide, the page says the name is unresolved and attaches no range. Regions where WCVP records the plant as extinct are shown labelled as such and are never part of the range records are tested against. Where WCVP has no entry the app falls back to national checklists and says so, at country level only. Kew's own one-line descriptions of a species, its life form and climate class, are quoted on the page and credited to WCVP, RBG Kew; nothing is derived from them. Occurrence records come from GBIF. Monthly climate normals come from CHELSA V2.1 (1981–2010, 30 arc-second), packed to a 0.05° grid: day and night temperature, rainfall, solar radiation, relative humidity, vapour-pressure deficit and wind. Elevation comes from ETOPO 2022 on the same grid. Daily temperature extremes come from NASA POWER (1981 onward). Photographs come first from the media that GBIF's occurrence download carries (research-grade iNaturalist observations reach GBIF this way, and so do other observation datasets), then from iNaturalist directly for the cultivated set and for species the download gave few of, then from Wikimedia Commons; every photograph is restricted by its own licence to CC0, CC BY and CC BY-SA, whatever dataset it came through, and each carries its author and licence. The summary is the opening of Wikipedia's article, four sentences at most, quoted as written, kept visibly separate and credited, with a link where more followed. Recent literature comes from OpenAlex.
Nothing on a species page is written by a person or a language model. The cultivation sheet and the "In short" paragraph are figures with their sources and the readings two fixed rules make of them, and each row says which figure it rests on. No row says what a plant does, wants or tolerates, or what to do to it.
A refusal is not an absence
Sources rate-limit, time out and go down. When one does, the page says "not checked" for that section rather than showing an empty list, because "we could not ask" and "there is nothing" are different facts and a grower reading the page needs to know which. The corpus build keeps what a source gave last time when it refuses this time, and records the date it was carried from. What is carried is exact: literature, the summary and photographs, each per source, so a refused iNaturalist does not discard this build's Commons photographs; and the range, the records, the map marker and the climate as one snapshot when the occurrence or distribution source refuses, never piecemeal, because a range from one build and records from another would be a page no build made. The same rule applies in the other direction: a species with no habitat climate on file gets no derived climate rows, and a hybrid gets none at all, since it has no habitat.
Which records count
A species' records on GBIF include herbarium sheets with rounded coordinates, garden plants, and specimens filed under the wrong country. The app takes every georeferenced record with no flagged geospatial issue, drops living specimens (something somebody planted) and records marked introduced or managed, and tests each against the native range from WCVP, discarding records outside it. The range has to be WCVP's, with native status stated: a national checklist that only reports a plant present in a country cannot tell a wild record from a garden one, so for a name WCVP does not carry the page shows the records on a map, says the range is unverified, and derives no marker, no climate and no sheet from them. Restricted-licence records (CC BY-NC) inform the marker and the climate like any other; only openly licensed records are published on the map, in the data, or as the marker itself. Three agreeing records are enough for a narrow endemic; under a dozen the page says the evidence is thin.
The map marker
The marker on the map is where the records are densest, and it decides nothing else. Records are binned at 1°, and the bin with most neighbours wins if it holds at least half the records or twice the runner-up; if no bin dominates at 1° the test repeats at 2° and 4°, and the densest 4° block stands when none dominates even there. Inside the winning cluster the densest 1° population is found again, and the marker is the openly licensed record nearest its middle, so the pin is somewhere the plant has been seen. When no openly licensed record lies in the population, the marker is the centre of the nearest tenth-of-a-degree cell instead, so that a restricted record's coordinates are never published; the page says which kind of point it is. The climate is not read at the marker.
The climate envelope
The habitat climate is read across every in-range record, not at one point. Each record placed to within 10 km (or with no stated uncertainty; the vaguer ones stay on the map and off the climate) names one 0.05° cell of the packed CHELSA grid, and each distinct cell is read once, so a site visited a hundred times is one cell of climate and not a hundred votes. A cell at sea or on ice, where the grid has no land climate, is dropped and counted. Three land cells are the minimum; fewer, and the page says so and derives nothing. For each month and each variable the app takes the median across those cells, which is the year the sheet reads, and the 10th and 90th percentiles, which are the span the species is recorded in; the page draws both, the median as a line and the span as a band around it, on a climograph (temperature over rain, one twelve-month axis, its legend saying the band is across habitat cells and not across years), and prints them in a table beneath, stating how many cells and records the envelope rests on. The chart shades the three months around the coldest mean night as the cold quarter, which is a marker for the eye and not a rule the sheet uses. The rain total across cells is the 10th and 90th percentile of each cell's own annual total, never a sum of monthly percentiles, which would be a year no cell has. Radiation is CHELSA's daily-mean shortwave flux, taken to a daily total by the 86,400 seconds in a day and converted to a daily light integral (PAR taken as 45% of shortwave at 4.6 µmol per joule, so 1 MJ/m²/day ≈ 2.07 mol/m²/day), because that is the unit a grower can compare with a window or a lamp.
Extremes need daily data, which CHELSA does not give, and one series, so they are read at one cell: the typical cell, the one whose coldest month's mean night is nearest the median of that figure across the envelope (monthly means are what the grid holds; the coldest single night is a POWER figure and is read there afterwards). The position printed for that cell is the cell's centre, never a record's coordinate. The app fetches the NASA POWER daily series for that cell's 0.5° POWER cell and reduces it: the absolute minimum, the 1st-percentile night, the 99th-percentile day, and frost nights as a count over the whole record, so one frost in forty years is printed as one night, not rounded away. POWER's cell elevation and the grid cell's ETOPO elevation differ, so the series is lapse-corrected at 6.5 °C per 1,000 m of the difference, and the page says by how much; when the grid cell's mean elevation is below sea level (a coastal cell averaged with sea floor), or when no elevation is on file for either cell, no correction is applied, and the page says which. A series is used only if it covers twenty years at 95% completeness.
What the rules read
Two fixed rules read the median year, and the sheet labels every sentence they produce as a reading. The rain rule: the wet season is the smallest set of months that carries 70% of the year's rain; a wet season whose mean is more than half a degree below the year's is called a winter growing season, more than half a degree above a summer one, and within that band neither. Eight or more wet months is no season. A temperature curve that moves less than 4 °C between its warmest and coldest month is flat, and then the rule infers no growing season even from a sharp rainy season; the page says the rain is sharp and that nothing is inferred from it, which is a different statement from "no season". Under 120 mm a year there is no rainy season to read at all, and the temperature rule names the cooler six months instead, provided they are at least a degree cooler than the other six; a flat year names nothing. A season that falls in two runs of months is printed as two runs. None of this says when the plant grows.
Wherever habitat months are printed the page names the hemisphere they belong to and, where the temperature curve gives a season to reverse (not a flat year, not a habitat within 10° of the equator), gives them shifted six months for a collection in the other one, because a Namaqualand plant whose rain falls in May to August has that season in a northern greenhouse from November to February, and the difference is the whole point. The label line and the sheet format a season through one function, so they cannot disagree.
The cold floor
The floor on a sheet names the quantity it is: the 1st-percentile night at the typical cell from NASA POWER, or, when no extremes are on file, the coldest month's mean night in the median year from CHELSA, named as such. Where the archetype table has a conventional minimum for the plant's group and that figure is higher, the floor is the table's figure, and the same sentence says so and gives both numbers. It is a figure about a place, not a tested survival limit for a plant in a pot, and the page says so.
Archetypes
The app keeps a small table of care archetypes (cactus or succulent, bulb or caudex, tropical foliage, orchid, epiphyte, fern, carnivore, temperate) resolved species → genus → family, and the page says which archetype and why it was chosen. The table supplies at most one figure, a conventional group minimum for the cold floor, and no prose; four of the eight groups (cactus or succulent, bulb or caudex, carnivore, temperate) span too much for one minimum and carry none, and the page says so for them. Where a family splits between archetypes and the genus is not on the table, the app guesses nothing.
The note in short
The paragraph at the top of the cultivation section is the sheet's rows in one-sentence form: each row is written with its own short form by the same rule at the same moment, and the note is those sentences in card order and nothing else. There is no second rule that could disagree with a card. It lists the rows each sentence came from. It is not written by a person or a model, and the page says so.
The same discipline holds on a plant's own page, where its habitat figures sit beside the bench it lives on: for each compared figure the page shows the habitat median with its 10th–90th span and the bench's setting side by side, and gives no verdict, because the sky over a habitat and a climate percentile are facts about places, not measured tolerances of a plant in a pot. The papers listed on a species page are works whose title or abstract names the species, most cited first; they are a pointer to the literature, and nothing on the page is drawn from them.
Similar habitat climate
A species page ends with the six species whose habitat climate is nearest its own. The distance is one number: the root of the mean squared difference, month by month, in mean day and mean night temperature, plus the difference in rain on a log scale weighted so that a factor of 2.7 in a month's rain counts as three degrees. Months are compared in calendar order, so a habitat with the same seasons six months apart is far, not near: on a bench in one hemisphere, two such plants want opposite halves of the year. Nothing else enters, not range, not family, not photographs, and the list is computed once when the index is built, from the same envelopes the pages show. It is a statement about climates, not about plants: two species from alike climates can want different things in a pot, and the page says which figures were compared.
Your collection
Everything you record lives in your browser's storage on your device as an append-only log of field-level changes, each stamped with a hybrid logical clock. State is a fold over the log; two devices merge by taking the union of their logs, and for each field the latest change wins. That one rule is what backup restore, the v2 import and sync all use, which is why restoring an old backup over a newer collection loses nothing and why a sync interrupted halfway simply resumes. Sync encrypts every batch on the device with a key only you hold; the server stores ciphertext and cannot read a plant name. The formats page has the details.
What the site knows about you
There are no accounts, no analytics and no tracking. Species pages are served from a static corpus; your collection never leaves your device unless you turn on sync, and then it leaves encrypted. Your browser does talk to outside image hosts, and you should know which: photographs on species pages load from iNaturalist's image host (inaturalist-open-data.s3.amazonaws.com), Wikimedia Commons (upload.wikimedia.org) and, for photographs that reached GBIF from other observation datasets, GBIF's image cache (api.gbif.org), each of which sees your address like any image host; and the species picker sends the name you are typing to this site's own /api/names, which asks api.gbif.org from the server, so that host sees the server's address and not yours. The frost watch asks MET Norway and, in the US, the National Weather Service from the server, never from your browser.
The source
Cultifolio is open source: the app under AGPL-3.0, the corpus tooling under MIT. Everything described on this page can be checked, run and rebuilt from github.com/zomethingje-eng/cultifolio, including the scripts that build a species corpus from the sources above. Problems and corrections are welcome there.