# Keeping a system current

_Peios / Using Peios / Package management_

> refresh learns what is available; upgrade moves to it; downgrade and undo walk a bad change back. The routine update cycle and the recovery commands.

Keeping a Peios system current is two commands in sequence — `refresh` to learn what is available, then `upgrade` to move to it. The other two commands here, `downgrade` and `undo`, go the other way: they walk a change back when an upgrade turns out badly.

## Refreshing repository metadata

```
peipkg refresh [repository]...
```

peipkg plans against a local, verified copy of each repository's metadata. That copy does not update itself. `peipkg refresh` is what updates it: for every configured repository — or just the ones you name — peipkg fetches the current signed descriptor and index, verifies them, and replaces the cached copy.

```
$ peipkg refresh
refreshed "official"
refreshed "internal"
```

Refresh has two properties worth knowing:

- **Repositories are independent.** If one repository is unreachable or fails verification, peipkg reports it and carries on with the rest. One bad repository never blocks a refresh of the others.
- **A failed refresh changes nothing.** If a repository cannot be refreshed, peipkg keeps the metadata it already had. It never falls back to unverified or stale-but-unchecked content. The worst a failed refresh does is leave you on yesterday's view.

What "verified" means here — signing keys, freshness floors, the handling of an unsigned repository — is the subject of [Repositories and trust](/peios/using-peios/package-management/repositories-and-trust.md).

Run `refresh` before an upgrade. An upgrade plans against whatever metadata is cached, so an upgrade without a recent refresh moves you to the newest version peipkg last heard about.

Skip it for long enough and peipkg stops waiting for you: an install, upgrade, or downgrade against a repository whose trust state has passed its **maximum trusted age** (30 days by default) refreshes that repository itself, and refuses to proceed against one that stays stale — unreachable, or frozen on an unchanging index — unless you pass `--allow-stale`. The bound and its configuration are covered in [Repositories and trust](/peios/using-peios/package-management/repositories-and-trust.md).

## Upgrading

```
peipkg upgrade [package]...
```

With no arguments, `upgrade` considers every installed package and moves each one that has a newer available version forward to it. With one or more package names, it upgrades only those — and still pulls in any new dependencies they need.

```
$ peipkg refresh && peipkg upgrade
the following changes will be made:
  upgrade    zlib 1.3.1 -> 1.3.2
  upgrade    nginx 1.27.4 -> 1.27.5
proceed? [y/N]
```

`upgrade` uses the same plan-and-confirm flow as `install` — peipkg shows the full set of changes and waits for approval — and the same options:

| Option | Effect |
|---|---|
| `--dry-run` | Print the plan and stop. A good way to preview what an upgrade would move. |
| `--yes`, `-y` | Skip the `proceed?` prompt. |
| `--no-recurse` | Confine the upgrade to the current root only — disable the cascade into nested named roots. |
| `--allow-stale` | Proceed although a repository's trust state exceeds its maximum trusted age. Warned and audited. |

By default, when named roots are configured, `upgrade` **cascades**: it reconciles the current root and every named root nested under it, each as an independent continue-on-error transaction with its own summary. `--no-recurse` disables that and upgrades the current root alone. See [Named roots](/peios/using-peios/package-management/named-roots.md) for the named-roots model.

If there is nothing to do — every package already at its newest version — peipkg says so and exits.

## Downgrading

```
peipkg downgrade <package> <version>
```

`downgrade` moves one package to a specific older version. You name the package and the exact version you want:

```
$ peipkg downgrade nginx 1.27.4
```

Older versions are not in a repository's active index — that index lists current versions only. They live in its **archive index**, which peipkg fetches on demand when you ask for a version that is not current. The package must still exist in some configured repository's archive for the downgrade to be possible.

A downgrade is treated as a deliberate move. Going backward — onto a version that may have known issues a newer one fixed — is one of the actions peipkg flags for **explicit authorisation**: beyond the routine `proceed?` prompt, peipkg asks you to authorise the specific downgrade, and `--yes` does not stand in for that answer. See [Elevated authorisation](/peios/using-peios/package-management/dependency-resolution.md) for the full set of actions that work this way.

`downgrade` accepts `--dry-run`, `--yes`, `-y`, and `--allow-stale` with the same meaning as elsewhere.

## Undoing the last change

```
peipkg undo
```

`undo` reverses the most recent committed transaction. If that transaction installed a package, `undo` removes it; if it upgraded, downgraded, or removed packages, `undo` restores each one to the version it had before.

```
$ peipkg undo
undoing transaction 47 (upgrade nginx, zlib)
the following changes will be made:
  downgrade  nginx 1.27.5 -> 1.27.4
  downgrade  zlib 1.3.2 -> 1.3.1
proceed? [y/N]
```

Be precise about what `undo` is. It is not a rollback of committed state — the previous transaction happened and stays in the history. `undo` computes the inverse of that transaction and applies it as a new transaction of its own. The history grows; it does not rewind. That new transaction can itself be undone, and so on.

Because restoring an older version is a backward move, `undo` carries the same explicit-authorisation requirement as `downgrade` for any package it walks back. It accepts `--dry-run` and `--yes`, `-y`.

To undo something other than the most recent transaction, or to see the history `undo` works against, use [`peipkg history`](/peios/using-peios/package-management/transactions-and-recovery.md) — and revert a specific package directly with `downgrade`.

## The routine cycle

For day-to-day maintenance the loop is:

```
$ peipkg refresh        # learn what is available
$ peipkg upgrade --dry-run   # preview the move
$ peipkg upgrade        # apply it
```

`downgrade` and `undo` are the recovery commands — use them when an upgrade has brought in a change you want to remove. Every one of these commands is a [transaction](/peios/using-peios/package-management/transactions-and-recovery.md), so every one of them is atomic and itself reversible.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The operation succeeded — including a dry run, a plan with nothing to do, and a declined prompt or authorisation (nothing failed). |
| `1` | The operation failed — a repository could not be refreshed, a repository's trust state exceeded its maximum age and a forced refresh could not clear it, resolution or a download or verification failed, a root in an upgrade cascade failed, there is no committed transaction to undo, or a command's arguments were wrong (`downgrade` without a package and version, an unparsable version, a malformed option). |
| `2` | A usage error before any command ran — no command, an unknown command, or a malformed global option (including a `--root` reference that does not resolve). |

Related content:

- [Installing and removing packages](/peios/using-peios/package-management/installing-and-removing.md)
- [Repositories and trust](/peios/using-peios/package-management/repositories-and-trust.md)
- [Transactions and recovery](/peios/using-peios/package-management/transactions-and-recovery.md)
- [Dependency resolution](/peios/using-peios/package-management/dependency-resolution.md)
- [Named roots](/peios/using-peios/package-management/named-roots.md)
