Guides

Knowledge packs

How reading texts and school-specific attributes are kept out of the core, what the bundled default pack contains, how to write an overlay, and how to read one from each language.

For: anyone who wants written interpretation on top of a chart

Casting a chart gives you facts: the Soul palace sits at Wu, Wuqu is in the Wealth palace carrying the Quan transformation, this chart forms 府相朝垣. The next questions — "what does Wuqu mean", "what is good about 府相朝垣" — are not facts. They are opinions, and different schools, different books and different teachers answer them differently.

x-iztro keeps the two apart. The core only judges facts (charting, horoscopes, patterns); reading texts and the school-specific star attributes live in a knowledge pack. A pack is a JSON file whose protocol is "language-independent key → text and attributes". One default pack ships inside the library so everything works out of the box; if you disagree with what it says, write an overlay pack and change those entries.

What belongs where

CoreKnowledge pack
ContentsTwelve palaces, star placement, brightness, transformations, horoscopes, pattern hitsStar readings, pattern readings, palace and transformation meanings, glossary, school-specific star attributes
NatureFacts, checkable field by field against iztroOpinions; another school means another pack
What being wrong looks likeThe chart is miscastYou disagree with the reading
How to change itYou cannot (changing it means it is no longer this algorithm)Swap the pack or write an overlay

The seam between them is the language-independent key: ziweiMaj for a star, zi_fu_tong_gong for a pattern, soulPalace for a palace, sihuaLu for a transformation. Every field the core emits carries these keys (see the key contract), so you take a key straight to the pack — no matching on translated names, and the chart language never enters into it.

What the bundled default pack contains

SectionEntriesContents
stars16214 major, 14 minor, 38 adjective, 46 decorative and 50 flowing stars — every StarKey has an entry. The major, minor, adjective and decorative ones carry the card attributes (yin-yang, five elements, dipper, chemistry, career, duty, aliases, element colour, energy colour) plus a body of text; the 14 major stars also carry readings for pairing with each other major star; the flowing-star entries (category: "flow") are cross-references pointing at their natal minor-star counterparts, with the machine-readable table served by flow_star_counterparts (Go FlowStarCounterparts)
patterns64Classical quotations, a prose description of the conditions, and the reading
palaces12What each of the twelve palaces means
mutagens4What Lu, Quan, Ke and Ji each mean
concepts49Glossary and basic concepts (same palace, the palace in question, the Body palace, six-harmony branches, the surrounded set, flying-star transformations …)

The content comes from the 学习 (Learn) pages of iztro-docs (MIT License, by Sylar Long), pinned to a source commit; the pack's source section records the origin, commit, licence and author in full. The text has been edited by x-iztro into third-person reference prose (declared in source.adapted). Text fields are Markdown.

The default pack is zh-CN only

There is no bundled pack for the other five languages: Rust's KnowledgePack::builtin returns None, Python and Go raise invalid_argument. For another language, write your own pack — or hand the Chinese entries to an LLM along with the chart and let it translate as it interprets.

The default pack adds roughly 380 KB to the wasm binary embedded in the Go package. The Rust and Python sides embed the same data.

What a pack looks like

The complete field reference is knowledge/SCHEMA.md in the repository. Every entry and every field is optional — what is missing simply was not written:

{
  "schema": 1,
  "id": "iztro-docs",
  "version": "2026-08-19+ec2d58b",
  "language": "zh-CN",
  "extends": null,
  "source": {
    "name": "iztro-docs",
    "url": "https://github.com/SylarLong/iztro-docs",
    "commit": "ec2d58bb8b2a0d243d91212a1e3c87ab866858ee",
    "license": "MIT",
    "author": "Sylar Long",
    "retrievedAt": "2026-08-19",
    "adapted": "文本由 x-iztro 在 iztro-docs 原文基础上整理改写为第三人称释义口吻……"
  },
  "stars": {
    "ziweiMaj": {
      "name": "紫微",
      "category": "major",
      "group": null,
      "attributes": {
        "yinYang": "yin",
        "fiveElements": "earth",
        "stem": "ji",
        "dipper": "中天星系",
        "chemistry": "尊贵",
        "career": "官禄主",
        "duty": "众星枢纽,长五行,孕万物",
        "aliases": ["帝王星", "老板星", "俸禄星"],
        "elementColor": "黄色",
        "energyColor": "紫光"
      },
      "intro": "紫微星号称 `帝王星`,并非指紫微坐命者能成帝王……",
      "combinations": { "tianfuMaj": "紫微星和 `天府星` 都是帝星……" }
    }
  },
  "patterns": {
    "zi_fu_tong_gong": {
      "name": "紫府同宫",
      "quotes": ["紫府同宫终身福厚。"],
      "conditions": "指紫微星和天府星同宫,这两颗星只会在寅宫和申宫同宫;其组合特质与紫微天府星曜组合一致。",
      "intro": "“终身福厚”并非定数,但紫府同宫格的人一定无法接受平凡的人生……"
    }
  },
  "palaces": { "soulPalace": { "name": "命宫", "intro": "命宫是决定星盘主人属性的宫位……" } },
  "mutagens": { "sihuaLu": { "name": "化禄", "intro": "**五行**:土;**意象**:开心、忙碌、增加、包容、多\n\n化禄星简称 `禄`……" } },
  "concepts": { "tong-gong": { "title": "遇、加、逢、同宫、同度", "intro": "指星曜在同一个宫位里面……" } }
}

Keys are always language-independent; the values above are Chinese because the bundled pack is zh-CN.

Reading a pack

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

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

println!("{:?} {:?}", ziwei.name, ziwei.attributes.aliases);
let head: String = pack.star_intro(StarKey::ZiweiMaj).unwrap().chars().take(12).collect();
println!("{head}");
Some("紫微") Some(["帝王星", "老板星", "俸禄星"])
紫微星号称 `帝王星`,

A key that is not in the pack comes back empty everywhere: None in Rust and Python, nil in Go (and an empty string from StarIntro).

Pairing it with pattern hits

The key on a pattern hit is exactly the key used in the pack's patterns section:

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 entry = pack.pattern(hit.key).unwrap();
    let quote = entry.quotes.as_ref().and_then(|q| q.first());
    println!("{} | {:?}", translate_pattern(hit.key, Language::ZhCN), quote);
}
府相朝垣 | Some("府相朝垣命必荣")

Stars work the same way: take each star's key from the chart to pack.star(key), a palace's palaceNameKey to pack.palace(key), and a transformation key to pack.mutagen(key).

Writing an overlay pack

An overlay is the same format, containing only the entries and fields you want to change, with extends naming the pack it overlays. This one replaces Ziwei's reading and aliases and swaps out the reading for 紫府同宫, leaving everything else untouched:

{
  "schema": 1,
  "id": "my-school",
  "version": "2026-08-19",
  "language": "zh-CN",
  "extends": "iztro-docs",
  "stars": {
    "ziweiMaj": {
      "intro": "紫微在我这一派看来先看格局高低,再论性情。",
      "attributes": { "aliases": ["帝座"] }
    }
  },
  "patterns": {
    "zi_fu_tong_gong": { "intro": "紫府同宫,我只把它当作起点高,不当作福厚。" }
  }
}

Merging produces a new pack:

let base = KnowledgePack::builtin(Language::ZhCN).unwrap();
let overlay = KnowledgePack::from_json(&std::fs::read_to_string("my-school.json")?)?;
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));

All three produce the same result: Ziwei keeps its name (紫微) and chemistry (尊贵) while intro and aliases come from the overlay; 紫府同宫 keeps its quotes and conditions and takes the new intro.

Merging is implemented once, in the Rust core. Python's merged and Go's Merged both call into it, so the merged result is byte-identical across the three languages instead of each side re-implementing the rules.

Merge rules

Starting from the base pack, each section (stars, patterns, palaces, mutagens, concepts) is merged key by key:

  • For an entry present in the overlay, its non-null fields replace the corresponding fields of the same-keyed base entry; fields it does not mention are kept
  • attributes and combinations merge the same way, field by field and sub-key by sub-key
  • Array fields (aliases, quotes) are replaced wholesale, never merged element by element
  • Keys the base does not have are added
  • Writing a field explicitly as null does not delete the base content (absent and null mean the same thing); to delete, replace the whole pack
  • After merging, id, version, language and source come from the overlay when non-empty, while extends stays the base's

A schema newer than this library supports is an error rather than a best-effort parse.

Why the star attributes live here

A star's five-element attribution looks like a fact but is also an opinion. iztro's own starsInfo table and the iztro-docs star cards already disagree with each other:

Stariztro starsInfoiztro-docs card
贪狼 (Tanlang)Water甲 (Jia) Wood — qi is Water
巨门 (Jumen)yin Earth癸 (Gui) Water and 己 (Ji) Earth (holding Metal and Wood)

Two data sets by the same author disagreeing is the clearest sign that these attributes are a school's reading, not a single answer. So x-iztro's core StarInfo stays value-for-value identical to iztro's (code ported from it does not change behaviour), while the card attributes go into the knowledge pack where they can be swapped.

Later

The same protocol supports loading and distributing overlay packs, and handing a pack to an LLM along with the chart. That belongs to the application layer, not to this library.

API reference

Sources and credit

Every text in the default pack comes from the 学习 (Learn) pages of iztro-docs, MIT License, by Sylar Long. The pack protocol, the editorial rewrite of the default pack and the three-language API are x-iztro's own work.

On this page