# Knowledge packs (/en/docs/go/knowledge)

KnowledgePack and its entry structs, the bundled default pack, JSON parsing, overlay merging and error handling.



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](/en/docs/guide/guides/knowledge-pack); the full field reference is
[`knowledge/SCHEMA.md`](https://github.com/x-haose/x-iztro/blob/main/knowledge/SCHEMA.md) in the
repository.

```go
pack, err := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
intro := pack.StarIntro(iztro.StarZiweiMaj)
```

Every lookup takes a `string`; pass the `StarXxx` / `PatternXxx` / `PalaceXxx` / `MutagenXxx`
constants. The default pack and the merge both live in the embedded wasm core; this package only
encodes and decodes JSON.

## Types [#types]

### KnowledgePack [#knowledgepack]

All fields are exported and tagged, so `encoding/json` works on them directly.

| Field      | Type                      | Meaning                                                                  |
| ---------- | ------------------------- | ------------------------------------------------------------------------ |
| `Schema`   | `int`                     | Format version, currently 1                                              |
| `ID`       | `string`                  | Pack identifier; `"iztro-docs"` for the default pack                     |
| `Version`  | `string`                  | Pack version; for the default pack, retrieval date + short source commit |
| `Language` | `string`                  | Language code of the texts, e.g. `LanguageZhCN`                          |
| `Extends`  | `string`                  | The pack this overlay overlays; empty for a standalone pack              |
| `Source`   | `KnowledgeSource`         | Origin and licence                                                       |
| `Stars`    | `map[string]StarEntry`    | Star entries, keyed by star key                                          |
| `Patterns` | `map[string]PatternEntry` | Pattern entries, keyed by pattern key                                    |
| `Palaces`  | `map[string]TextEntry`    | Palace entries, keyed by palace key                                      |
| `Mutagens` | `map[string]TextEntry`    | Transformation entries, keyed by transformation key                      |
| `Concepts` | `map[string]ConceptEntry` | Glossary entries, keyed by slug                                          |

### KnowledgeSource [#knowledgesource]

`Name`, `URL`, `Commit`, `License`, `Author`, `RetrievedAt`, `Adapted` (adaptation note), all `string`, empty when absent.

### StarEntry [#starentry]

| Field          | Type                | Meaning                                                                                                                                           |
| -------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Name`         | `string`            | Display name in this pack's language                                                                                                              |
| `Category`     | `string`            | `"major"` / `"minor"` / `"adjective"` / `"dec"` / `"flow"` (a flowing star, a cross-reference entry pointing at its natal minor-star counterpart) |
| `Group`        | `string`            | Grouping: the adjective star's category, the decorative star's group                                                                              |
| `Attributes`   | `StarAttributes`    | School attributes                                                                                                                                 |
| `Intro`        | `string`            | Reading (Markdown)                                                                                                                                |
| `Combinations` | `map[string]string` | Reading for sharing a palace with another major star, keyed by that star                                                                          |

### StarAttributes [#starattributes]

`YinYang` (`yin` / `yang`), `FiveElements` (`wood` / `fire` / `earth` / `metal` / `water`), `Stem`
(`jia`…`gui`), `FiveElementsNote`, `Dipper`, `Chemistry`, `Career`, `Duty`, `Aliases` (`[]string`),
`ElementColor`, `EnergyColor`.

<Callout type="info">
  `FiveElements` and `YinYang` are what the pack's source says, and may differ from the core star
  data, which is value-for-value identical to iztro's. The reason is in the
  [guide](/en/docs/guide/guides/knowledge-pack#why-the-star-attributes-live-here).
</Callout>

### PatternEntry [#patternentry]

`Name`, `Quotes` (`[]string`), `Conditions`, `Intro`.

### TextEntry / ConceptEntry [#textentry--conceptentry]

`TextEntry` (palaces, transformations) has `Name` and `Intro`; `ConceptEntry` (glossary) has `Title`
and `Intro`.

<Callout type="warn" title="Absent means the zero value">
  The Go side does not use pointers to separate "not written" from "written as empty". An absent field
  is the empty string or nil, so compare against the empty string to tell whether an entry carries
  text.
</Callout>

***

## BuiltinKnowledgePack [#builtinknowledgepack]

**Purpose**　Get the bundled default knowledge pack.

**Signature**

```go
func BuiltinKnowledgePack(language Language) (*KnowledgePack, error)
func BuiltinKnowledgePackContext(ctx context.Context, language Language) (*KnowledgePack, error)
```

**Parameters**

| Parameter  | Type              | Meaning                                                   |
| ---------- | ----------------- | --------------------------------------------------------- |
| `ctx`      | `context.Context` | Context variant only; cancels waiting for a wasm instance |
| `language` | `Language`        | Text language                                             |

**Returns**　`(*KnowledgePack, error)`. Languages without a bundled pack return an error, matchable
with `errors.Is(err, iztro.ErrInvalidArgument)`. Only `LanguageZhCN` has one today.

**Example**

```go
pack, err := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
if err != nil {
    log.Fatal(err)
}

fmt.Println(pack.ID, pack.Version, pack.Language, pack.Source.License)
fmt.Println(len(pack.Stars), len(pack.Patterns), len(pack.Palaces), len(pack.Mutagens), len(pack.Concepts))

_, err = iztro.BuiltinKnowledgePack(iztro.LanguageEnUS)
fmt.Println(err, errors.Is(err, iztro.ErrInvalidArgument))
```

**Output**

```text
iztro-docs 2026-08-19+ec2d58b zh-CN MIT
162 64 12 4 49
iztro: no builtin knowledge pack for language 'en-US' true
```

***

## ParseKnowledgePack [#parseknowledgepack]

**Purpose**　Parse a pack from JSON text.

**Signature**

```go
func ParseKnowledgePack(data []byte) (*KnowledgePack, error)
```

**Returns**　`(*KnowledgePack, error)`. Invalid JSON, a missing or zero `schema`, and a `schema`
newer than this library supports all return an `ErrInvalidArgument`-class error — the same
semantics as the Rust core's parser (`KnowledgePack::from_json`).

Serializing is plain `encoding/json`:

```go
data, err := json.Marshal(pack)
```

**Example**

```go
overlay, err := iztro.ParseKnowledgePack([]byte(`{"schema":1,"id":"my-school","version":"1",
    "language":"zh-CN","extends":"iztro-docs",
    "stars":{"ziweiMaj":{"intro":"我的紫微","attributes":{"aliases":["帝座"]}}},
    "patterns":{"zi_fu_tong_gong":{"intro":"我的紫府同宫"}}}`))
if err != nil {
    log.Fatal(err)
}
fmt.Println(overlay.ID, overlay.Extends)

_, err = iztro.ParseKnowledgePack([]byte("nope"))
fmt.Println(err)
_, err = iztro.ParseKnowledgePack([]byte(`{"schema":99}`))
fmt.Println(err)
```

**Output**

```text
my-school iztro-docs
iztro: invalid knowledge pack: invalid character 'o' in literal null (expecting 'u')
iztro: knowledge pack schema 99 is newer than supported 1
```

***

## Merged [#merged]

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

**Signature**

```go
func (p *KnowledgePack) Merged(overlays ...*KnowledgePack) (*KnowledgePack, error)
func (p *KnowledgePack) MergedContext(ctx context.Context, overlays ...*KnowledgePack) (*KnowledgePack, error)
```

**Parameters**

| Parameter  | Type                | Meaning                                                   |
| ---------- | ------------------- | --------------------------------------------------------- |
| `ctx`      | `context.Context`   | Context variant only; cancels waiting for a wasm instance |
| `overlays` | `...*KnowledgePack` | Overlays applied in argument order; later ones win        |

**Returns**　A new `*KnowledgePack`; neither this pack nor the overlays change. A nil receiver, a
nil overlay, or a pack whose `schema` is invalid (hand-built structs are validated by the core
here) all return an `ErrInvalidArgument`-class error.

The rules are in the [guide](/en/docs/guide/guides/knowledge-pack#merge-rules): section by section,
key by key, an overlay's non-empty fields replace the same-keyed entry's fields, `Attributes` and
`Combinations` merge field by field, array fields are replaced wholesale. The merge itself runs in
the wasm core, so all three languages agree.

**Example**

```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
merged, err := pack.Merged(overlay)
if err != nil {
    log.Fatal(err)
}

zi := merged.Star(iztro.StarZiweiMaj)
fmt.Println(merged.ID, zi.Name, zi.Attributes.Aliases, zi.Attributes.Chemistry, zi.Intro)
fmt.Println(merged.PatternIntro(iztro.PatternZiFuTongGong),
    merged.Pattern(iztro.PatternZiFuTongGong).Quotes)
fmt.Println(string([]rune(pack.StarIntro(iztro.StarZiweiMaj))[:5]))

_, err = pack.Merged(nil)
fmt.Println(err)
```

**Output**

```text
my-school 紫微 [帝座] 尊贵 我的紫微
我的紫府同宫 [紫府同宫终身福厚。]
紫微星号称
iztro: mergeKnowledgePacks: nil overlay pack
```

***

## Star / Pattern / Palace / Mutagen / Concept [#star--pattern--palace--mutagen--concept]

**Purpose**　Look up an entry by language-independent key.

**Signature**

```go
func (p *KnowledgePack) Star(starKey string) *StarEntry
func (p *KnowledgePack) Pattern(patternKey string) *PatternEntry
func (p *KnowledgePack) Palace(palaceKey string) *TextEntry
func (p *KnowledgePack) Mutagen(mutagenKey string) *TextEntry
func (p *KnowledgePack) Concept(slug string) *ConceptEntry
```

**Returns**　`nil` when the pack has no such entry, and `nil` for a nil receiver rather than a
panic. The pointer is to a copy of the entry, so writing through it does not change the pack.

**Example**

```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
zi := pack.Star(iztro.StarZiweiMaj)

fmt.Println(zi.Name, zi.Category, zi.Attributes.Dipper, zi.Attributes.Aliases)
fmt.Println(zi.Combinations[iztro.StarTianfuMaj] != "")
fmt.Println(pack.Palace(iztro.PalaceSoul).Name, pack.Mutagen(iztro.MutagenLu).Name)
fmt.Println(pack.Concept("tong-gong").Title)
fmt.Println(pack.Star("nope") == nil)
```

**Output**

```text
紫微 major 中天星系 [帝王星 老板星 俸禄星]
true
命宫 化禄
遇、加、逢、同宫、同度
true
```

***

## StarIntro / PatternIntro [#starintro--patternintro]

**Purpose**　Get the reading text directly.

**Signature**

```go
func (p *KnowledgePack) StarIntro(starKey string) string
func (p *KnowledgePack) PatternIntro(patternKey string) string
```

**Returns**　The empty string both when the entry is missing and when it exists without a reading.

**Example**　List the natal patterns with their quotations:

```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)
hits, _ := chart.Patterns(nil)

for _, hit := range hits {
    fmt.Println(hit.Name, "|", pack.Pattern(hit.Key).Quotes[0])
    fmt.Println(string([]rune(pack.PatternIntro(hit.Key))[:10]))
}
```

**Output**

```text
府相朝垣 | 府相朝垣命必荣
“食禄千锺”的断语使
```

***

## TextOptions [#textoptions]

**Purpose**　Output options for the `ToTextWith` family (`ToTextWith` / `PalaceToTextWith` /
`SurroundedPalacesToTextWith` / `PatternsToTextWith`, and the same-named methods on `Horoscope`):
the source of readings and the pattern criteria. The zero value emits the chart facts only under
the default criteria, byte-identical to the method without `With`.

**Definition**

```go
type TextOptions struct {
    Knowledge     Knowledge
    PatternConfig *PatternConfig
}
```

**Fields**

| Field           | Type                                                       | Description                                                                                                                                                                                                                                                                                         |
| --------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Knowledge`     | [`Knowledge`](#knowledge--builtinknowledge--knowledgefrom) | Source of readings; the zero value adds none. When given, each palace's star readings follow that palace's fact lines, the pattern readings follow the pattern list, and the natal text closes with `## Mutagen Notes` — see [Text with readings](/en/docs/guide/guides/to-text#text-with-readings) |
| `PatternConfig` | [`*PatternConfig`](/en/docs/go/patterns#patternconfig)     | Pattern criteria, the same argument as `Patterns(config)`; acts on both the text's pattern section and the pattern readings. `nil` takes the core default                                                                                                                                           |

**Example** (on a zh-CN chart, since the bundled pack is Chinese)

```go
text, _ := chart.ToTextWith(iztro.TextOptions{Knowledge: iztro.BuiltinKnowledge()})
same, _ := chart.ToTextWith(iztro.TextOptions{})
plain, _ := chart.ToText()

fmt.Println(same == plain, utf8.RuneCountInString(plain), utf8.RuneCountInString(text))

cfg := iztro.PatternConfig{BrightnessSource: iztro.BrightnessSourcePositional}
byPosition, _ := chart.ToTextWith(iztro.TextOptions{Knowledge: iztro.BuiltinKnowledge(), PatternConfig: &cfg})
```

**Output**

```text
true 3389 20767
```

***

## Knowledge / BuiltinKnowledge / KnowledgeFrom [#knowledge--builtinknowledge--knowledgefrom]

**Purpose**　The value of the `Knowledge` field of [`TextOptions`](#textoptions): the source of
readings for the `ToTextWith` family.

**Signature**

```go
type Knowledge struct { /* unexported */ }

func BuiltinKnowledge() Knowledge
func KnowledgeFrom(pack *KnowledgePack) Knowledge
```

**Values**

| Value                      | Meaning                                                                                                                                                                                |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BuiltinKnowledge()`       | The bundled default pack for the chart language; when that language has no bundled pack (only zh-CN has one) the method returns `ErrInvalidArgument` rather than silently falling back |
| `KnowledgeFrom(pack)`      | The given pack (custom, or the result of `Merged`); a `nil` `pack` equals the zero value                                                                                               |
| `Knowledge{}` (zero value) | No readings; the output of `TextOptions{}` is byte-identical to the method without `With`                                                                                              |

**Example**

```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
data, _ := os.ReadFile("my-school.json")
overlay, _ := iztro.ParseKnowledgePack(data)
mine, _ := pack.Merged(overlay)

text, _ := chart.ToTextWith(iztro.TextOptions{Knowledge: iztro.KnowledgeFrom(mine)})
```

***

## ForAstrolabe / ForHoroscope [#forastrolabe--forhoroscope]

**Purpose**　Pick by chart: cut a sub-pack holding only the entries relevant to this chart.

**Signature**

```go
func (p *KnowledgePack) ForAstrolabe(chart *Astrolabe, config *PatternConfig) (*KnowledgePack, error)
func (p *KnowledgePack) ForAstrolabeContext(ctx context.Context, chart *Astrolabe, config *PatternConfig) (*KnowledgePack, error)
func (p *KnowledgePack) ForHoroscope(horoscope *Horoscope, config *PatternConfig) (*KnowledgePack, error)
func (p *KnowledgePack) ForHoroscopeContext(ctx context.Context, horoscope *Horoscope, config *PatternConfig) (*KnowledgePack, error)
```

**Parameters**

| Parameter   | Type              | Description                                                                                                            |
| ----------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ctx`       | `context.Context` | `Context` variants only; cancels waiting for a wasm instance                                                           |
| `chart`     | `*Astrolabe`      | The chart to select by; a re-anchored chart selects by its re-anchored layout                                          |
| `horoscope` | `*Horoscope`      | A horoscope from `chart.Horoscope(...)`; the natal part is selected along with it                                      |
| `config`    | `*PatternConfig`  | Pattern criteria, the same argument as [`Patterns(config)`](/en/docs/go/patterns#patternconfig); `nil` for the default |

**Returns**　`(*KnowledgePack, error)`. A standard pack with the metadata carried over: `Stars`
holds the stars on the chart (major, minor, adjective and the four groups of twelve gods; the 14
major stars' `Combinations` keep only partners that actually share the palace), `Patterns` the hits
under the `config` criteria, `Mutagens` all four entries, `Palaces` and `Concepts` empty.
`ForHoroscope` adds each scope's flowing stars and the patterns hit from the decadal down to the
hourly perspective. Pair the sub-pack with `Patterns(config)` / `PatternsToTextWith` under the same
criteria: different criteria hit different sets, and the readings would then miss or over-include
entries. Selection reads the pack as it currently is (the whole pack is sent to the core), so
entries edited in place make it into the sub-pack. A `nil` receiver or argument, or a horoscope not
obtained from `Astrolabe.Horoscope`, returns `ErrInvalidArgument`. The selection rule is on
[Picking by chart](/en/docs/guide/guides/knowledge-pack#picking-by-chart).

**Example**

```go
pack, _ := iztro.BuiltinKnowledgePack(iztro.LanguageZhCN)
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)

sub, _ := pack.ForAstrolabe(chart, nil)
fmt.Println(len(sub.Stars), len(sub.Patterns), len(sub.Mutagens), len(sub.Palaces))
for k := range sub.Stars[iztro.StarWuquMaj].Combinations {
    fmt.Println(k)
}

h, _ := chart.Horoscope("2025-1-1", 0)
sub, _ = pack.ForHoroscope(h, nil)
fmt.Println(len(sub.Stars), len(sub.Patterns))
```

**Output**

```text
108 1 4 0
tianxiangMaj
158 16
```

Wuqu shares its palace with Tianxiang on this chart, so Wuqu's `Combinations` in the sub-pack keeps
only the Tianxiang entry.

***

## Knowledge.ForAstrolabe / Knowledge.ForHoroscope [#knowledgeforastrolabe--knowledgeforhoroscope]

**Purpose**　Pick by chart through a `Knowledge` sentinel. With `BuiltinKnowledge()` the core reads
the bundled pack directly, so there is no need to fetch the whole pack with `BuiltinKnowledgePack`
and send it back; with `KnowledgeFrom(pack)` it equals the `pack.ForAstrolabe` family.

**Signature**

```go
func (k Knowledge) ForAstrolabe(chart *Astrolabe, config *PatternConfig) (*KnowledgePack, error)
func (k Knowledge) ForAstrolabeContext(ctx context.Context, chart *Astrolabe, config *PatternConfig) (*KnowledgePack, error)
func (k Knowledge) ForHoroscope(horoscope *Horoscope, config *PatternConfig) (*KnowledgePack, error)
func (k Knowledge) ForHoroscopeContext(ctx context.Context, horoscope *Horoscope, config *PatternConfig) (*KnowledgePack, error)
```

**Parameters**　The same as the `(*KnowledgePack).ForAstrolabe` family.

**Returns**　As above. The zero value `Knowledge{}` has no source of material and returns
`ErrInvalidArgument`; `BuiltinKnowledge()` also returns `ErrInvalidArgument` for a chart language
without a bundled pack.

**Example**

```go
chart, _ := iztro.BySolar("2000-8-16", 2, iztro.GenderFemale, true, iztro.LanguageZhCN, nil)

sub, _ := iztro.BuiltinKnowledge().ForAstrolabe(chart, nil)
fmt.Println(len(sub.Stars), len(sub.Patterns))
```

**Output**

```text
108 1
```
