Skip to content

Getting started

Install

sh
go get github.com/arisros/fate

The engine has no dependencies beyond the standard library. The optional Temporal integration is a separate module — see Install for details.

A first machine

This counter has one state and mutates its context on each event:

go
package main

import (
	"context"
	"fmt"

	"github.com/arisros/fate"
)

type Ctx struct{ Count int }

type Evt interface{ isEvt() }
type Inc struct{}
type Reset struct{}

func (Inc) isEvt()   {}
func (Reset) isEvt() {}

func main() {
	m, err := fate.CreateMachine(fate.MachineConfig[Ctx, Evt]{
		ID:      "counter",
		Initial: "active",
		States: map[string]fate.StateNodeConfig[Ctx, Evt]{
			"active": {On: map[string][]fate.TransitionConfig[Ctx, Evt]{
				"Inc":   {{Actions: []fate.Action[Ctx, Evt]{fate.Assign(func(c Ctx, _ Evt) Ctx { c.Count++; return c })}}},
				"Reset": {{Target: "active", Actions: []fate.Action[Ctx, Evt]{fate.Assign(func(c Ctx, _ Evt) Ctx { c.Count = 0; return c })}}},
			}},
		},
	})
	if err != nil {
		panic(err)
	}

	a := fate.NewActor(m)
	_ = a.Start(context.Background())
	_ = a.Send(context.Background(), Inc{})
	_ = a.Send(context.Background(), Inc{})

	fmt.Println(a.Snapshot().Context.Count) // 2
}

Persist and restore

An actor's state round-trips to JSON and restores byte-for-byte:

go
blob, _ := a.Persist()
b, _ := fate.NewActorFromSnapshot[Ctx, Evt](m, blob)
fmt.Println(b.Snapshot().Context.Count) // 2 — identical

The shape of the API

  • CreateMachine validates a config and returns an immutable *Machine.
  • NewActor makes a running instance; Start runs the initial entry; Send dispatches an event.
  • Snapshot reads the current state; Subscribe observes changes; Persist and NewActorFromSnapshot round-trip to JSON.

See it run

Render the machine, or drive it live in the browser:

go
fmt.Println(fate.RenderMermaid(m.Describe(), fate.MermaidOptions{}))

Or open it in the studio — a live viewer and simulator at fate-studio.arisjirat.com.

Where to go next

  • How it works — the engine/adapter split and why it matters.
  • Concepts — the active configuration, Machine vs Actor.
  • Examples — hierarchical, parallel, history, delayed, invoked.
  • Full per-symbol reference on pkg.go.dev.

Released under the MIT License · v0.4.0 · pkg.go.dev