Getting started

Chronicler transfers state between an explicit recording schema and an object graph your runtime already owns. A type implements IRecordable, then records its fields in a deliberate order through RecordData(...).

1. Install a package

The standard package is the best starting point:

dotnet add package Chronicler.Core

It targets netstandard2.1 and net8.0 and includes both built-in transports. Choose Chronicler.Core.Lean when you want the same core recording model and JSON support without the MemoryPack dependency or transport.

2. Define the schema

Use RecordValues for leaf values and RecordDeep for an owned nested object:

using Chronicler;

public sealed class PlayerSnapshot : IRecordable
{
    public int Health = 100;
    public int Mana = 50;
    public WeaponSnapshot Weapon = new();

    public void RecordData(IChronicler chronicler)
    {
        RecordValues.Look(chronicler, ref Health, "health", 100);
        RecordValues.Look(chronicler, ref Mana, "mana", 50);
        RecordDeep.Look(chronicler, ref Weapon, "weapon");
    }
}

public sealed class WeaponSnapshot : IRecordable
{
    public int Ammo = 30;

    public void RecordData(IChronicler chronicler)
    {
        RecordValues.Look(chronicler, ref Ammo, "ammo", 30);
    }
}

The names, call order, and declared defaults are part of the schema. Keep them stable unless you intend to change the serialized contract.

3. Save and restore JSON

Serialize(IRecordable, bool) returns a JSON string. Populate(...) applies that state to an existing object:

PlayerSnapshot source = new()
{
    Health = 72,
    Mana = 18,
    Weapon = new WeaponSnapshot { Ammo = 7 }
};

string json = JsonRecordSerializer.Serialize(source, writeIndented: true);

PlayerSnapshot restored = new();
JsonRecordSerializer.Populate(restored, json);

restored.Weapon already exists because the host constructed the runtime shell. Chronicler populates that owned object; it does not act as a general-purpose object graph factory.

4. Choose another transport when needed

The standard package exposes MemoryPackRecordSerializer over the same RecordData(...) schema:

byte[] payload = MemoryPackRecordSerializer.Serialize(source);

PlayerSnapshot restored = new();
MemoryPackRecordSerializer.Populate(restored, payload);

The Lean package intentionally does not contain this type.

5. Use the right recording lane

State kind Helper
Leaf data, enums, and small serializable values RecordValues
Owned class state already present in the shell RecordDeep
Owned recordable struct state RecordDeepStruct
Optional recordable struct state RecordNullableDeep
Runtime-owned or external identity RecordLinks

Always pass the canonical declared default to RecordValues.Look(...). If an entry is absent during loading, Chronicler applies that value instead of keeping whatever happened to be in the target object.

Next steps