# Buddy & hatch

> The avatar at the heart of Hatched — how it's created, what hatch means, and how it grows.

Source: https://docs.hatched.live/docs/concepts/buddy-and-hatch

A **buddy** is the persistent companion a user gets when they join your
Hatched programme. Everything else — skills, coins, streaks, badges — hangs
off the buddy.

## Egg and hatch

Before a buddy exists, there is an **egg**. Creating an egg is the first
write you make to the Hatched API:

```ts
const egg = await hatched.eggs.create({
  userId: 'user_42',
});
```

The egg is pinned to the current [config version](/docs/concepts/config-versions)
on the customer (set during onboarding via `apply-preset`, or via the
Dashboard) and carries any audience tags you passed. It doesn't render a
visible buddy yet — it's a placeholder with pending image generation.
Move the egg from `waiting` to `ready` once your own onboarding gate is
complete; only ready eggs can hatch.

**Hatch** is the ceremony that turns an egg into a buddy:

```ts
await hatched.eggs.updateStatus(egg.eggId, 'ready');
const op = await hatched.eggs.hatch(egg.eggId);
const buddy = await hatched.operations.wait(op.operationId);
```

Hatching is asynchronous because image generation takes 5–20 seconds. You
get an operation id back; poll it with `operations.wait` or listen for the
`buddy.hatched` [webhook](/docs/concepts/webhooks).

## One user, possibly several buddies

By default there is one buddy per (customer, external_user_id) pair. When
[audiences](/docs/concepts/audiences) are in play, a single user can have
one buddy per audience — useful when the same person plays two roles
(student and teacher, for instance).

## What a buddy carries

A buddy is not just a picture. It holds:

- a **config_version_id** — which rulebook it lives under
- a **skills** map — each skill with value and level
- **coins** and any **token** balances
- a list of awarded **badges**
- a set of **streak** counters
- an **evolution stage**, current `image_url`, and bare `base_image_url`
- equipped **marketplace items**
- a **progression** summary for XP, badges, items, and streak counters
- an **appearance** block for pending or failed item compositing
- an audience tag (if configured)

The widget reads this shape directly; your backend can mirror it via
webhooks if you need your own source of truth for UX.

## Appearance state

`buddy.appearance` separates the desired outfit from the image that is
currently safe to display:

- `ready` — `image_url` includes the rendered equipped items.
- `pending` — a new composite is being generated.
- `awaiting_credits` — the composite will retry after image credits are
  available.
- `failed` — the render needs operator action or a retry.

Use `desired_equipped_item_ids` to know what the user wants equipped and
`rendered_equipped_item_ids` to know what is visible in `image_url`. If a
failed appearance has `error.code === 'needs_rerender'`, regenerate the bare
stage with `buddies.rerenderAppearance(buddyId)`, wait for `ready`, then
re-equip the items.

## Lifecycle

Buddies are long-lived. They don't expire on their own — they evolve. When
you update the rule set, existing buddies stay pinned to their old config
version; you migrate them explicitly when you're ready.

## Related

- [Evolution](/docs/concepts/evolution) — how the buddy changes over time.
- [Compositing & stages](/docs/concepts/compositing-and-stages) — the full `appearance` state machine.
- [Config versions](/docs/concepts/config-versions) — the rulebook a buddy is pinned to.
- [Getting started](/docs/guides/getting-started) — create and hatch your first buddy.
