---
sidebar_position: 12
title: Update behavior
---

# Update behavior

CloudFormation tells you, per property, whether a change updates the resource in
place or replaces it. Zibby's declaration model has the same question and four
answers. Every properties table in this section carries the column.

| Class | What happens on the next deploy |
|---|---|
| **Re-applied** | the platform re-runs the action — provision the store, register the sidecar, attach the endpoint, bind the server. Idempotent: nothing is duplicated and nothing working is broken |
| **Seeded once** | written on the **first** install only. Whatever the operator set afterwards survives every Update |
| **Card only** | reaches the catalog card and nothing else. A deployed agent never consumes it, so changing it never offers an Update |
| **Frozen** | baked into the deployed agent when it was installed. Changing it needs a re-deploy |

---

## Seeded once — the list

These are written on a fresh install and never again:

- [`selections`](./deploy-time-config.md#selections) — a value already set is kept, and the deploy tells you so
- [`defaultSchedule`](./deploy-time-config.md#defaultschedule) — **any** existing schedule blocks the seed, including a paused one
- [`deployInput`](./deploy-time-config.md#deployinput) values
- [`maxRuntimeMinutes`](./catalog-metadata.md)
- `defaultSlug` — an agent's name is fixed at first install

The rule behind all of them: **the platform never overwrites a decision you
made.** If your agent needs an operator to change something, say so in the
release notes; do not try to write it for them.

---

## Frozen — why a published fix does not reach a deployed agent

:::danger This is the one that surprises people
When you deploy an agent, the platform stores **that version's source** —
including its `package.json` and every version range in it — against the agent.
That copy is what runs, forever, until somebody re-deploys.

So publishing a fixed package **does not reach an agent that is already
running**. An agent installed against `^0.1.x` can never pick up a `0.2.x`. It
does not error; the runs simply keep failing the same way.
:::

**The fix is always a re-deploy** — take the Update on the agent's page, or
deploy the card again. There is no other route.

The same is true of the agent's `deps`, and of anything else that travels inside
the source bundle.

---

## What lights the "Update available" badge

Two independent signals, either of which is enough:

1. **The template's files changed** — a checksum over your template directory.
2. **The declaration changed** — a per-template signature over your
   `spec` block, minus the fields listed as *Card only*.

The second exists because your `spec` block lives **outside** the
template directory, so a metadata-only change (a sidecar version pin, a new
`selections` picker) moves no source byte and the first signal cannot see it.

The rule the badge states, and the one to test your own field against:

> **Re-installing this agent from the current template would change this agent.**

A field is excluded from the signal only when updating provably changes nothing
for somebody already running it — tags, taglines, icons, capability bullets,
sample trigger bodies, and the release notes themselves. (Notes *describing* an
update cannot be the reason to offer one.)

:::tip Why your card is not showing an update
Two common causes:

- You changed only a *Card only* field. That is working as designed — the card
  updated, nobody was offered a re-install.
- You added a new declared field to a template but the platform is not tracking
  it yet. A field that is copied but not tracked only ever lands on rows written
  for some other reason.
:::

---

## Idempotency, in practice

Everything in the *Re-applied* class is safe to run repeatedly:

| Action | On re-deploy |
|---|---|
| Store provisioning | the same store is re-used; a store you re-pointed by hand stays re-pointed |
| Sidecar registration | the same image, unless the pinned version or checksum moved |
| `requires` attachment | an existing link is kept; a stale one is replaced; one you added by hand is adopted |
| `remoteMcp` binding | matched by URL and left byte-for-byte, which is what keeps an OAuth grant alive |
| Member agents | re-deployed in place; the bindings do not churn |

And one thing that is not idempotent, by nature: **renaming**. A renamed store
is a new store; a renamed `slug` is a new agent. Nothing migrates the old one.

## See also

- [The declaration model](./index.md)
- [Catalog metadata](./catalog-metadata.md) — release-notes rules
