Cannabis genetic identity. The same record type covers two levels of specificity, distinguished by the `kind` field: "strain" denotes a broad genetic identity (e.g., "Wedding Cake"); "cut" denotes a specific phenotype, clone, or keeper pheno (e.g., "Forum cut of GSC"). Captures intrinsic identity, structured cultivation profile, and the publisher's contextualized field assertions; subjective experience and measured outcomes live in separate record types (`org.cannadb.review`, future `org.cannadb.grow`) that reference this one. Publishing this record IS the claim — every field below is implicitly contextualized by the publisher's identity, computed by consumers from the publisher DID at display time.
tid
Timestamp-based ID
Properties
alsoKnownAs
array
of
string
Optional
Alternate names this strain or cut is known by, e.g., ["Triangle Mints #23"].
autoflower
boolean
Optional
Whether this strain or cut is autoflowering (i.e., has ruderalis influence). Orthogonal to indica/sativa lean. Also conditions the basis of `cycleTime`: full-run (germination → harvest) for autoflowers, flower-only for photoperiods.
breeder
string
at-uri
Optional
AT-URI reference to an `org.cannadb.breeder` record. Canonical when present and resolvable; `breederName` is the display fallback. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate the ref resolves to an `org.cannadb.breeder` record.)
breederName
string
Optional
Display fallback for the breeder name. Used when no `breeder` ref is available, when the ref does not resolve, or for breeders without atproto presence.
cbdDominant
boolean
Optional
Whether this is a CBD-dominant strain. Orthogonal to the indica/sativa axis (a strain can be both indica-leaning and CBD-dominant). Distinct from `cbdRange` (which is the quantitative CBD percentage); `cbdDominant` is the category signal — cannabis culture treats CBD-dominant strains as a distinct shopping category, not just a high-CBD variant.
cbdRange
ref
#cannabinoidRange
Optional
Claimed CBD percentage range. Values are integers in hundredths of a percent (e.g., 75 = 0.75%). Optional; either bound may be omitted if only one is known.
characteristics
array
of
string
Optional
Plant trait descriptors orthogonal to consumption experience. Open vocabulary; parallel to `effects`/`medicinalEffects`/`flavors` but for properties of the plant rather than the experience of consuming it. Examples: "mold resistant", "frost tolerant", "high flower-to-leaf ratio", "drought tolerant". The AppView normalizes near-duplicates at index time.
createdAt
string
datetime
Required
Client-declared timestamp when this record was originally created.
cultivationNotes
string
Optional
Markdown-formatted cultivation guidance from the publisher — overflow for context that doesn't fit the structured `cycleTime`, `height`, `yield`, `growDifficulty`, `growthOdour` fields. Things like indoor/outdoor recommendations, environmental sensitivities, training notes, and run-specific quirks belong here. Capped at 10000 graphemes (100000 bytes).
maxLength: 100000 bytesmaxGraphemes: 10000 graphemescycleTime
ref
#dayRange
Optional
Cycle time in days, expressed as a min/max range. Basis derives from `autoflower`: full-run (germination → harvest) for autoflowers, flower-only (start of 12/12 → harvest) for photoperiods. Single-value quotes set min == max. The basis is not stored separately because it derives from `autoflower`; documenting the convention here prevents downstream tools from misinterpreting the integer.
description
string
Optional
Markdown-formatted identity narrative — what this strain is, where it came from, the breeder's intent, the character. Distinct from `cultivationNotes`, which is for cultivators. Capped at 10000 graphemes (100000 bytes).
maxLength: 100000 bytesmaxGraphemes: 10000 graphemeseffects
array
of
string
Optional
Claimed recreational effect descriptors. Open vocabulary — see `flavors` for rationale. Distinct from `medicinalEffects`, which is a parallel vocabulary for therapeutic claims.
flavors
array
of
string
Optional
Claimed flavor profile descriptors. Open vocabulary — the lexicon does not enforce a closed set; the AppView normalizes near-duplicates at index time and may ship a curated suggestion list for autocomplete.
generation
string
Optional
Free-form generation marker for the strain's own generation (e.g., "F7", "BX3", "S1", "Selection"). Free-form because the vocabulary is open and breeders write whatever shorthand fits. Parent strains' generations stay inline in `parentNames` strings.
growDifficulty
string
Optional
Claimed grow difficulty. `knownValues` for forward-compat — clients should accept unknown values and fall back to generic display.
easy, intermediate, hardgrowthOdour
string
Optional
Claimed growth odour intensity. Practical for stealth growers. `knownValues` for forward-compat.
low, medium, highheight
ref
#heightRange
Optional
Plant height at maturity in centimeters, expressed as a min/max range. Conventional basis is indoor mature (the breeder's typical quote). Outdoor mature heights run substantially larger; outdoor-quoted values should be flagged in `cultivationNotes` rather than smashed into this field.
holder
string
at-uri
Optional
For cut records: AT-URI reference (typically a DID) to the holder of this specific cut. `holderName` is the display fallback.
holderName
string
Optional
Display fallback for the cut holder.
indicaSativa
integer
Optional
Indica/sativa lean on a 0–100 scale, where 0 is pure indica and 100 is pure sativa. Pure landraces sit at the extremes; modern hybrids fall between.
minimum: 0maximum: 100kind
string
Required
Level of specificity. "strain" = broad genetic identity; "cut" = a specific phenotype, clone, or keeper pheno of a strain. Open vocabulary — clients should accept unknown values gracefully and fall back to generic display.
strain, cutmedicinalEffects
array
of
string
Optional
Claimed medical/therapeutic effect descriptors. Open vocabulary; parallel to `effects` but for medicinal/therapeutic claims distinct from recreational. Examples: "insomnia relief", "appetite stimulation", "anxiety relief". The AppView normalizes near-duplicates at index time.
name
string
Required
Primary common name of the strain or cut, e.g., "Wedding Cake" or "Forum cut of GSC".
originRegion
string
Optional
Region of geographic origin, e.g., "Hindu Kush", "California".
originYear
integer
Optional
Year the strain or cut was first introduced.
parentBreederNames
array
of
string
Optional
Optional parallel array to `parentNames` capturing per-parent breeder attribution (e.g., ["Karma Genetics", ""] when the first parent's breeder is known and the second's is not). Index-aligned with `parentNames`: position N in this array attributes the breeder of the parent at position N in `parentNames`. Empty strings or missing trailing entries indicate unknown attribution. Forward-compat note: phenotype designations, generation markers, and uncertainty markers stay inline in the parent name string until evidence shows they need their own structure.
parentNames
array
of
string
Optional
Display fallbacks for parent strains. Used when refs are absent or unresolved. Phenotype designations, generation markers, and uncertainty markers may be embedded inline in the string (e.g., "Triangle Mints #23 [pheno: keeper] (F3)") — clients render them as written.
parents
array
of
string
at-uri
Optional
Genetic ancestry — AT-URI references to parent `org.cannadb.strain` records (typically 1–2 entries). `parentNames` provides display fallbacks; `parentBreederNames` provides per-parent breeder attribution as a parallel array. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate refs resolve to `org.cannadb.strain` records.)
primaryImage
blob
Optional
One representative image of the strain or cut. Accepts common web image formats; capped at 2 MB to keep PDS storage burden modest. Higher-resolution photography belongs in review or grow records.
maxSize: 2.0 MBseedAvailability
array
of
string
Optional
What variants exist for this strain name. Multi-valued because a strain often ships in multiple variants. Open vocabulary via `knownValues` so additive expansions (e.g., a future "feminized_autoflower" composite value) don't require a lexicon revision.
shortDescription
string
Optional
Single-line plain-text summary used in card meta lines, search-result excerpts, and social-share previews. Markdown is disallowed; this is a one-line summary distinct from the full markdown `description`. Capped at 250 graphemes (2000 bytes) — enforced by the lexicon to keep card meta lines and share previews short.
maxLength: 2000 bytesmaxGraphemes: 250 graphemessourceUrl
string
uri
Optional
Optional URL pointing at the canonical breeder/origin write-up for this strain — typically the breeder's product page or a strain-specific writeup. Distinct from the breeder record's `website` (the breeder's home page); this is the strain-specific page. No link-rot guarantee; informational only.
terpenes
array
of
string
Optional
Claimed dominant terpenes. Open vocabulary — see `flavors` for rationale.
thcCbdRatio
string
Optional
Claimed THC:CBD ratio expressed as a string, e.g., "1:1", "20:1".
thcRange
ref
#cannabinoidRange
Optional
Claimed THC percentage range. Values are integers in hundredths of a percent (e.g., 2450 = 24.50%). Optional; either bound may be omitted if only one is known.
versionOf
array
of
string
at-uri
Optional
Derivative or claimed relationships — AT-URI references to `org.cannadb.strain` records this record is sold as, claims to be, or is a take on. Distinct from `parents` (genetic ancestry): a pure relabel has `versionOf` but no `parents`; a derivative breeding take may have both. Includes the autoflower-take-on-a-photo pattern (an autoflower variant of "the same strain" is a `versionOf` claim even though its `parents` may differ because a ruderalis line was crossed in).
versionOfNames
array
of
string
Optional
Display fallbacks for `versionOf` references.
yield
ref
#yieldRange
Optional
Claimed yield as a min/max integer range plus a `unit` enum so the integer is unambiguous. Single-value quotes set min == max. The unit is required to interpret the integer correctly — a lexicon convention because breeders quote yield in mutually incompatible units (per-plant vs per-m², grams vs ounces) and an unlabeled integer is unsafe.
View raw schema
{
"key": "tid",
"type": "record",
"record": {
"type": "object",
"required": [
"name",
"kind",
"createdAt"
],
"properties": {
"kind": {
"type": "string",
"description": "Level of specificity. \"strain\" = broad genetic identity; \"cut\" = a specific phenotype, clone, or keeper pheno of a strain. Open vocabulary — clients should accept unknown values gracefully and fall back to generic display.",
"knownValues": [
"strain",
"cut"
]
},
"name": {
"type": "string",
"description": "Primary common name of the strain or cut, e.g., \"Wedding Cake\" or \"Forum cut of GSC\"."
},
"yield": {
"ref": "#yieldRange",
"type": "ref",
"description": "Claimed yield as a min/max integer range plus a `unit` enum so the integer is unambiguous. Single-value quotes set min == max. The unit is required to interpret the integer correctly — a lexicon convention because breeders quote yield in mutually incompatible units (per-plant vs per-m², grams vs ounces) and an unlabeled integer is unsafe."
},
"height": {
"ref": "#heightRange",
"type": "ref",
"description": "Plant height at maturity in centimeters, expressed as a min/max range. Conventional basis is indoor mature (the breeder's typical quote). Outdoor mature heights run substantially larger; outdoor-quoted values should be flagged in `cultivationNotes` rather than smashed into this field."
},
"holder": {
"type": "string",
"format": "at-uri",
"description": "For cut records: AT-URI reference (typically a DID) to the holder of this specific cut. `holderName` is the display fallback."
},
"breeder": {
"type": "string",
"format": "at-uri",
"description": "AT-URI reference to an `org.cannadb.breeder` record. Canonical when present and resolvable; `breederName` is the display fallback. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate the ref resolves to an `org.cannadb.breeder` record.)"
},
"effects": {
"type": "array",
"items": {
"type": "string",
"description": "A single recreational effect descriptor."
},
"description": "Claimed recreational effect descriptors. Open vocabulary — see `flavors` for rationale. Distinct from `medicinalEffects`, which is a parallel vocabulary for therapeutic claims."
},
"flavors": {
"type": "array",
"items": {
"type": "string",
"description": "A single flavor descriptor."
},
"description": "Claimed flavor profile descriptors. Open vocabulary — the lexicon does not enforce a closed set; the AppView normalizes near-duplicates at index time and may ship a curated suggestion list for autocomplete."
},
"parents": {
"type": "array",
"items": {
"type": "string",
"format": "at-uri",
"description": "AT-URI reference to a parent `org.cannadb.strain` record."
},
"description": "Genetic ancestry — AT-URI references to parent `org.cannadb.strain` records (typically 1–2 entries). `parentNames` provides display fallbacks; `parentBreederNames` provides per-parent breeder attribution as a parallel array. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate refs resolve to `org.cannadb.strain` records.)"
},
"cbdRange": {
"ref": "#cannabinoidRange",
"type": "ref",
"description": "Claimed CBD percentage range. Values are integers in hundredths of a percent (e.g., 75 = 0.75%). Optional; either bound may be omitted if only one is known."
},
"terpenes": {
"type": "array",
"items": {
"type": "string",
"description": "A single terpene name."
},
"description": "Claimed dominant terpenes. Open vocabulary — see `flavors` for rationale."
},
"thcRange": {
"ref": "#cannabinoidRange",
"type": "ref",
"description": "Claimed THC percentage range. Values are integers in hundredths of a percent (e.g., 2450 = 24.50%). Optional; either bound may be omitted if only one is known."
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Client-declared timestamp when this record was originally created."
},
"cycleTime": {
"ref": "#dayRange",
"type": "ref",
"description": "Cycle time in days, expressed as a min/max range. Basis derives from `autoflower`: full-run (germination → harvest) for autoflowers, flower-only (start of 12/12 → harvest) for photoperiods. Single-value quotes set min == max. The basis is not stored separately because it derives from `autoflower`; documenting the convention here prevents downstream tools from misinterpreting the integer."
},
"sourceUrl": {
"type": "string",
"format": "uri",
"description": "Optional URL pointing at the canonical breeder/origin write-up for this strain — typically the breeder's product page or a strain-specific writeup. Distinct from the breeder record's `website` (the breeder's home page); this is the strain-specific page. No link-rot guarantee; informational only."
},
"versionOf": {
"type": "array",
"items": {
"type": "string",
"format": "at-uri",
"description": "AT-URI reference to an `org.cannadb.strain` record this record claims a derivative or equivalence relationship with."
},
"description": "Derivative or claimed relationships — AT-URI references to `org.cannadb.strain` records this record is sold as, claims to be, or is a take on. Distinct from `parents` (genetic ancestry): a pure relabel has `versionOf` but no `parents`; a derivative breeding take may have both. Includes the autoflower-take-on-a-photo pattern (an autoflower variant of \"the same strain\" is a `versionOf` claim even though its `parents` may differ because a ruderalis line was crossed in)."
},
"autoflower": {
"type": "boolean",
"description": "Whether this strain or cut is autoflowering (i.e., has ruderalis influence). Orthogonal to indica/sativa lean. Also conditions the basis of `cycleTime`: full-run (germination → harvest) for autoflowers, flower-only for photoperiods."
},
"generation": {
"type": "string",
"description": "Free-form generation marker for the strain's own generation (e.g., \"F7\", \"BX3\", \"S1\", \"Selection\"). Free-form because the vocabulary is open and breeders write whatever shorthand fits. Parent strains' generations stay inline in `parentNames` strings."
},
"holderName": {
"type": "string",
"description": "Display fallback for the cut holder."
},
"originYear": {
"type": "integer",
"description": "Year the strain or cut was first introduced."
},
"alsoKnownAs": {
"type": "array",
"items": {
"type": "string",
"description": "An alternate display name for this strain or cut."
},
"description": "Alternate names this strain or cut is known by, e.g., [\"Triangle Mints #23\"]."
},
"breederName": {
"type": "string",
"description": "Display fallback for the breeder name. Used when no `breeder` ref is available, when the ref does not resolve, or for breeders without atproto presence."
},
"cbdDominant": {
"type": "boolean",
"description": "Whether this is a CBD-dominant strain. Orthogonal to the indica/sativa axis (a strain can be both indica-leaning and CBD-dominant). Distinct from `cbdRange` (which is the quantitative CBD percentage); `cbdDominant` is the category signal — cannabis culture treats CBD-dominant strains as a distinct shopping category, not just a high-CBD variant."
},
"description": {
"type": "string",
"maxLength": 100000,
"description": "Markdown-formatted identity narrative — what this strain is, where it came from, the breeder's intent, the character. Distinct from `cultivationNotes`, which is for cultivators. Capped at 10000 graphemes (100000 bytes).",
"maxGraphemes": 10000
},
"growthOdour": {
"type": "string",
"description": "Claimed growth odour intensity. Practical for stealth growers. `knownValues` for forward-compat.",
"knownValues": [
"low",
"medium",
"high"
]
},
"parentNames": {
"type": "array",
"items": {
"type": "string",
"description": "Display name of a parent strain."
},
"description": "Display fallbacks for parent strains. Used when refs are absent or unresolved. Phenotype designations, generation markers, and uncertainty markers may be embedded inline in the string (e.g., \"Triangle Mints #23 [pheno: keeper] (F3)\") — clients render them as written."
},
"thcCbdRatio": {
"type": "string",
"description": "Claimed THC:CBD ratio expressed as a string, e.g., \"1:1\", \"20:1\"."
},
"indicaSativa": {
"type": "integer",
"maximum": 100,
"minimum": 0,
"description": "Indica/sativa lean on a 0–100 scale, where 0 is pure indica and 100 is pure sativa. Pure landraces sit at the extremes; modern hybrids fall between."
},
"originRegion": {
"type": "string",
"description": "Region of geographic origin, e.g., \"Hindu Kush\", \"California\"."
},
"primaryImage": {
"type": "blob",
"accept": [
"image/png",
"image/jpeg",
"image/webp"
],
"maxSize": 2000000,
"description": "One representative image of the strain or cut. Accepts common web image formats; capped at 2 MB to keep PDS storage burden modest. Higher-resolution photography belongs in review or grow records."
},
"growDifficulty": {
"type": "string",
"description": "Claimed grow difficulty. `knownValues` for forward-compat — clients should accept unknown values and fall back to generic display.",
"knownValues": [
"easy",
"intermediate",
"hard"
]
},
"versionOfNames": {
"type": "array",
"items": {
"type": "string",
"description": "Display name of a strain this record is a version of."
},
"description": "Display fallbacks for `versionOf` references."
},
"characteristics": {
"type": "array",
"items": {
"type": "string",
"description": "A single plant characteristic descriptor."
},
"description": "Plant trait descriptors orthogonal to consumption experience. Open vocabulary; parallel to `effects`/`medicinalEffects`/`flavors` but for properties of the plant rather than the experience of consuming it. Examples: \"mold resistant\", \"frost tolerant\", \"high flower-to-leaf ratio\", \"drought tolerant\". The AppView normalizes near-duplicates at index time."
},
"cultivationNotes": {
"type": "string",
"maxLength": 100000,
"description": "Markdown-formatted cultivation guidance from the publisher — overflow for context that doesn't fit the structured `cycleTime`, `height`, `yield`, `growDifficulty`, `growthOdour` fields. Things like indoor/outdoor recommendations, environmental sensitivities, training notes, and run-specific quirks belong here. Capped at 10000 graphemes (100000 bytes).",
"maxGraphemes": 10000
},
"medicinalEffects": {
"type": "array",
"items": {
"type": "string",
"description": "A single medicinal effect descriptor."
},
"description": "Claimed medical/therapeutic effect descriptors. Open vocabulary; parallel to `effects` but for medicinal/therapeutic claims distinct from recreational. Examples: \"insomnia relief\", \"appetite stimulation\", \"anxiety relief\". The AppView normalizes near-duplicates at index time."
},
"seedAvailability": {
"type": "array",
"items": {
"type": "string",
"description": "A single seed variant identifier.",
"knownValues": [
"regular",
"feminized",
"autoflower",
"clone_only"
]
},
"description": "What variants exist for this strain name. Multi-valued because a strain often ships in multiple variants. Open vocabulary via `knownValues` so additive expansions (e.g., a future \"feminized_autoflower\" composite value) don't require a lexicon revision."
},
"shortDescription": {
"type": "string",
"maxLength": 2000,
"description": "Single-line plain-text summary used in card meta lines, search-result excerpts, and social-share previews. Markdown is disallowed; this is a one-line summary distinct from the full markdown `description`. Capped at 250 graphemes (2000 bytes) — enforced by the lexicon to keep card meta lines and share previews short.",
"maxGraphemes": 250
},
"parentBreederNames": {
"type": "array",
"items": {
"type": "string",
"description": "Display name of the breeder of the parent at the same index in `parentNames`. Empty string when unknown."
},
"description": "Optional parallel array to `parentNames` capturing per-parent breeder attribution (e.g., [\"Karma Genetics\", \"\"] when the first parent's breeder is known and the second's is not). Index-aligned with `parentNames`: position N in this array attributes the breeder of the parent at position N in `parentNames`. Empty strings or missing trailing entries indicate unknown attribution. Forward-compat note: phenotype designations, generation markers, and uncertainty markers stay inline in the parent name string until evidence shows they need their own structure."
}
}
},
"description": "Cannabis genetic identity. The same record type covers two levels of specificity, distinguished by the `kind` field: \"strain\" denotes a broad genetic identity (e.g., \"Wedding Cake\"); \"cut\" denotes a specific phenotype, clone, or keeper pheno (e.g., \"Forum cut of GSC\"). Captures intrinsic identity, structured cultivation profile, and the publisher's contextualized field assertions; subjective experience and measured outcomes live in separate record types (`org.cannadb.review`, future `org.cannadb.grow`) that reference this one. Publishing this record IS the claim — every field below is implicitly contextualized by the publisher's identity, computed by consumers from the publisher DID at display time."
}