> ## Documentation Index
> Fetch the complete documentation index at: https://grounds-docs-platform-architecture.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Pushes

> The lifecycle of a push — from upload to running pod.

A **push** represents one attempt to ship a JAR to a target. Each `grounds push` (or portal-initiated build) creates one Push row that you can inspect, retry, and tail logs from.

## States

A push moves through a small state machine. Forge persists the current state on the row and emits SSE events on transitions.

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: upload
    pending --> building
    building --> build_succeeded
    building --> build_failed
    build_succeeded --> deploying
    deploying --> deploy_failed
    deploying --> ready

    build_failed --> [*]
    deploy_failed --> [*]
    ready --> [*]

    note right of build_failed
      Terminal, retryable
    end note

    note right of deploy_failed
      Terminal, retryable
    end note

    note right of ready
      Terminal happy path
    end note
```

| State             | Meaning                                                             |
| ----------------- | ------------------------------------------------------------------- |
| `pending`         | Manifest + JAR uploaded, build job not yet started.                 |
| `building`        | Kaniko is producing the OCI image from your JAR + base image.       |
| `build_failed`    | Build error. JAR is still on the server; **retry** is supported.    |
| `build_succeeded` | Image pushed to the in-cluster registry; deployment hasn't started. |
| `deploying`       | Kubernetes is reconciling the new image.                            |
| `deploy_failed`   | Deployment failed (bad image pull, resource limits, crashloop).     |
| `ready`           | Pod is up and serving. Terminal happy-path state.                   |

`build_failed` and `deploy_failed` are terminal but **retryable**: forge keeps your JAR and manifest, so a retry doesn't re-upload.

## Identity & idempotency

Each push has:

* A UUID (`id`) you'll see referenced everywhere — CLI output, portal URLs, log streams.
* A **content hash** computed over the JAR + manifest. If you push the exact same bytes twice, forge re-uses the previous build instead of rebuilding from scratch.

## Tailing logs

Two log streams per push:

```bash theme={null}
grounds logs <pushId>                   # build logs (kaniko)
grounds logs deployment <name>          # runtime logs (the pod)
```

Both are SSE streams that follow until a terminal state, then close. Add `--no-follow` to get a snapshot and exit.

## Retrying

A failed build or failed deploy can be retried without re-uploading:

```bash theme={null}
grounds push retry <pushId>
```

This creates a **new** push row that re-uses the server-stored JAR and manifest, then re-runs the pipeline from `pending`. The original failed push is preserved for history.

## Listing

```bash theme={null}
grounds push list                       # last 20 pushes in current project
grounds push list --target=staging      # filter by target
grounds push list --status=ready        # filter by terminal state
```

In the portal, the project's **Pushes** page shows the same list with status badges and clickable detail pages.

## Rolling back

If a successful push introduced a bug and you need the previous image back, open the app's **Pushes** tab in the portal and click **Roll back** on the prior push. Forge re-deploys that push's already-built image without re-running kaniko, so the rollback lands in seconds. The rollback creates a fresh push row pointing at the same `imageTag`, so the audit log records the action.

## Promoting a staging push

For pushes that targeted `staging` and reached `ready`, the portal's **Pushes** tab also shows a **Promote** action. Promote copies the built image into a new push targeting `dev` — no rebuild, no kaniko run. Use it to ship the exact artifact you just verified in a preview env, instead of re-running the build pipeline and risking a different image (e.g., upstream base-image drift).

## What survives a push

* The previous deployment for `dev` is **replaced**. State (world chunks, plugin data files) survives because the volume is attached at the namespace level — but anything in-memory is lost.
* For `staging`, each push creates a new preview env, so nothing survives across pushes; that's the point.
