Knowledge packs

KnowledgePack and its entry types, the bundled default pack, JSON parsing and serialization, overlay merging.

A knowledge pack is JSON mapping "language-independent key → reading text and school attributes". The core only judges facts; reading texts and the school-specific star attributes live here. For the concept, the format and how to write an overlay, see the knowledge pack guide; the full field reference is knowledge/SCHEMA.md in the repository.

use x_iztro::{KnowledgePack, Language, StarKey};

let pack = KnowledgePack::builtin(Language::ZhCN).expect("zh-CN has a builtin pack");
let intro = pack.star_intro(StarKey::ZiweiMaj);

KnowledgePack is re-exported at the crate root; the other types live in x_iztro::knowledge.

Types

KnowledgePack

All fields are public and directly readable and writable. The map fields are BTreeMap, so iteration order is stable and sorted by key.

FieldTypeMeaning
schemau32Format version, currently SCHEMA_VERSION (1)
idStringPack identifier; "iztro-docs" for the default pack
versionStringPack version; for the default pack, retrieval date + short source commit
languageStringLanguage code of the texts, e.g. "zh-CN"
extendsOption<String>The pack this overlay overlays; None for a standalone pack
sourceSourceOrigin and licence
starsBTreeMap<String, StarEntry>Star entries, keyed by StarKey::as_key
patternsBTreeMap<String, PatternEntry>Pattern entries, keyed by PatternKey::as_key
palacesBTreeMap<String, TextEntry>Palace entries, keyed by Palace::as_key
mutagensBTreeMap<String, TextEntry>Transformation entries, keyed by Mutagen::as_key
conceptsBTreeMap<String, ConceptEntry>Glossary entries, keyed by slug

Implements Clone, Default, PartialEq, Eq, Debug, Serialize, Deserialize.

Source

FieldTypeMeaning
nameOption<String>Source name
urlOption<String>Source URL
commitOption<String>Source revision (git commit)
licenseOption<String>Licence
authorOption<String>Author
retrieved_atOption<String>Retrieval date
adaptedOption<String>Adaptation note: how the text was edited relative to the source

StarEntry

FieldTypeMeaning
nameOption<String>Display name in this pack's language
categoryOption<String>"major" / "minor" / "adjective" / "dec" / "flow" (a flowing star, a cross-reference entry pointing at its natal minor-star counterpart)
groupOption<String>Grouping: the adjective star's category, the decorative star's group
attributesStarAttributesSchool attributes; all None when absent
introOption<String>Reading (Markdown)
combinationsBTreeMap<String, String>Reading for sharing a palace with another major star, keyed by that star

StarAttributes

Every field is Option<String>, except aliases which is Option<Vec<String>>: yin_yang (yin / yang), five_elements (wood / fire / earth / metal / water), stem (jiagui), five_elements_note, dipper, chemistry, career, duty, aliases, element_color, energy_color.

five_elements and yin_yang here are what the pack's source says, and may differ from the core StarInfo, which is value-for-value identical to iztro's. The reason is in the guide.

PatternEntry

FieldTypeMeaning
nameOption<String>Display name
quotesOption<Vec<String>>Classical quotations
conditionsOption<String>The source's prose description of the conditions
introOption<String>Reading

TextEntry / ConceptEntry

TextEntry (palaces, transformations) has name and intro; ConceptEntry (glossary) has title and intro. All are Option<String>.

SCHEMA_VERSION

pub const SCHEMA_VERSION: u32 = 1;

The highest format version this library supports. Parsing a higher schema is an error.


builtin

Purpose Get the bundled default knowledge pack.

Signature

impl KnowledgePack {
    pub fn builtin(language: Language) -> Option<&'static KnowledgePack>
}

Parameters

ParameterTypeMeaning
languageLanguageText language

Returns Option<&'static KnowledgePack>None when there is no bundled pack for that language. Only Language::ZhCN has one today. The pack is parsed once on first use and cached, so later calls are a free static reference.

Example

let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
println!("{} {} {}", pack.id, pack.version, pack.stars.len());
println!("{:?}", pack.source.license);
println!("{}", KnowledgePack::builtin(Language::EnUS).is_some());

Output

iztro-docs 2026-08-19+ec2d58b 162
Some("MIT")
false

builtin_json

Purpose Get the raw JSON of the bundled pack, unparsed.

Signature

impl KnowledgePack {
    pub fn builtin_json(language: Language) -> Option<&'static str>
}

Returns Option<&'static str>, zh-CN only, same as builtin. Use it to hand the pack to another process or write it to disk without a parse-and-serialize round trip — that is exactly what the bindings do.


from_json

Purpose Parse a pack from JSON text.

Signature

impl KnowledgePack {
    pub fn from_json(json: &str) -> Result<KnowledgePack, String>
}

Returns Result<KnowledgePack, String>. The error is a human-readable string, for three cases: JSON that does not fit the format (invalid knowledge pack: ...), a missing or zero schema (a pack must declare its format version), and a schema higher than SCHEMA_VERSION (no best-effort downgrade).

This returns String rather than IztroError: a knowledge pack is data the caller brings along, not input to a charting entry point. The bindings wrap it into each language's invalid_argument error.

Example

let pack = KnowledgePack::from_json(r#"{
    "schema": 1, "id": "mine", "version": "1", "language": "zh-CN",
    "stars": {"ziweiMaj": {"intro": "我的紫微"}}
}"#)?;
println!("{:?}", pack.star_intro(StarKey::ZiweiMaj));
println!("{:?}", KnowledgePack::from_json(r#"{"schema": 99}"#));
println!("{:?}", KnowledgePack::from_json(r#"{"id": "x"}"#));

Output

Some("我的紫微")
Err("knowledge pack schema 99 is newer than supported 1")
Err("knowledge pack must declare \"schema\" (currently 1)")

Edges and traps


to_json

Purpose Serialize to JSON (compact, no indentation).

Signature

impl KnowledgePack {
    pub fn to_json(&self) -> String
}

Returns String. Optional fields that are None and empty maps are omitted, so from_json(&pack.to_json()) equals the original pack. For indented output use serde_json::to_string_pretty(&pack).


merged

Purpose Layer overlay packs onto this one and return a new pack.

Signature

impl KnowledgePack {
    pub fn merged(&self, overlays: &[&KnowledgePack]) -> KnowledgePack
}

Parameters

ParameterTypeMeaning
overlays&[&KnowledgePack]Overlays applied in slice order; later ones win

Returns A KnowledgePack; neither this pack nor the overlays change. The rules are in the guide: section by section, key by key, an overlay's non-None fields replace the same-keyed entry's fields, attributes and combinations merge field by field, array fields are replaced wholesale.

Example

let base = KnowledgePack::builtin(Language::ZhCN).unwrap();
let overlay = KnowledgePack::from_json(r#"{
    "schema": 1, "id": "my-school", "version": "1", "language": "zh-CN", "extends": "iztro-docs",
    "stars": {"ziweiMaj": {"intro": "我的紫微", "attributes": {"aliases": ["帝座"]}}},
    "patterns": {"zi_fu_tong_gong": {"intro": "我的紫府同宫"}}
}"#)?;
let pack = base.merged(&[&overlay]);

let ziwei = pack.star(StarKey::ZiweiMaj).unwrap();
println!("{:?} {:?} {:?}", ziwei.name, ziwei.attributes.aliases, ziwei.attributes.chemistry);
println!("{:?}", pack.pattern_intro(PatternKey::ZiFuTongGong));
println!("{:?}", pack.pattern(PatternKey::ZiFuTongGong).unwrap().quotes);
println!("{} {:?}", pack.id, base.star_intro(StarKey::ZiweiMaj).map(|s| s.chars().take(5).collect::<String>()));

Output

Some("紫微") Some(["帝座"]) Some("尊贵")
Some("我的紫府同宫")
Some(["紫府同宫终身福厚。"])
my-school Some("紫微星号称")

merge

Purpose Merge one overlay into this pack in place.

Signature

impl KnowledgePack {
    pub fn merge(&mut self, overlay: &KnowledgePack)
}

merged is the non-mutating version (clone, then merge each overlay). Use merge when you already hold a mutable pack and are layering many overlays, to skip the clone.


star / pattern / palace / mutagen

Purpose Look up an entry by language-independent key.

Signature

impl KnowledgePack {
    pub fn star(&self, key: StarKey) -> Option<&StarEntry>
    pub fn pattern(&self, key: PatternKey) -> Option<&PatternEntry>
    pub fn palace(&self, palace: Palace) -> Option<&TextEntry>
    pub fn mutagen(&self, mutagen: Mutagen) -> Option<&TextEntry>
}

Returns None when the pack has no such entry. All four look the key up in the corresponding BTreeMap by as_key(), exactly as pack.stars.get(key.as_key()) would; the glossary has no dedicated method, use pack.concepts.get(slug).

Example

let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let ziwei = pack.star(StarKey::ZiweiMaj).unwrap();

println!("{:?} {:?} {:?}", ziwei.name, ziwei.category, ziwei.attributes.dipper);
println!("{:?}", ziwei.combinations.keys().collect::<Vec<_>>());
println!("{:?}", pack.palace(Palace::Soul).and_then(|e| e.name.clone()));
println!("{:?}", pack.mutagen(Mutagen::Lu).and_then(|e| e.name.clone()));
println!("{:?}", pack.concepts.get("tong-gong").and_then(|e| e.title.clone()));

Output

Some("紫微") Some("major") Some("中天星系")
["pojunMaj", "qishaMaj", "tanlangMaj", "tianfuMaj", "tianxiangMaj"]
Some("命宫")
Some("化禄")
Some("遇、加、逢、同宫、同度")

star_intro / pattern_intro

Purpose Get the reading directly, skipping one layer of Option.

Signature

impl KnowledgePack {
    pub fn star_intro(&self, key: StarKey) -> Option<&str>
    pub fn pattern_intro(&self, key: PatternKey) -> Option<&str>
}

Returns None both when the entry is missing and when it exists without a reading.

Example List the natal patterns with their readings:

let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let chart = by_solar("2000-8-16", 2, Gender::Female, true, Language::ZhCN, Config::default())?;

for hit in chart.patterns() {
    let intro = pack.pattern_intro(hit.key).unwrap_or("(not written in this pack)");
    let head: String = intro.chars().take(10).collect();
    println!("{} {}", translate_pattern(hit.key, Language::ZhCN), head);
}

Output

府相朝垣 “食禄千锺”的断语使

On this page