# Storage points

> A storage point is a delivery destination for run results: when a sandbox node finishes a run, its artifacts are meant to land in your GitHub repo, S3 bucket, GCS bucket, Drive folder or WebDAV server instead of staying on the node. The current engine doesn't deliver them yet. Manage them on Connect → Storage points. As of September 25, 2026, OpenEng AI isn't live yet.

A **storage point** is a delivery destination for run results — when a
sandbox node finishes a run, its artifacts can land in your GitHub repo, S3
bucket, GCS bucket, Drive folder, or WebDAV server instead of staying on the
node that produced them. Manage them on **Connect → Storage points**.

> [!WARNING] Status on September 25, 2026: OpenEng AI isn't live yet
> The Console and Web Console interfaces load, but the OpenEng AI API routes and the Broker aren't
> deployed. Nothing can be saved or published, and no AI engine can register or connect. Pro,
> Enterprise and pay-as-you-go launch in Q4 2026 and can't be purchased yet. This page describes
> OpenEng AI as it works once those services are live ([status](ai.md)).

> [!WARNING] Deliveries don't happen yet
> The current `openeng` engine build doesn't deliver run results to storage
> points: fleet execution and delivery aren't part of it, and sandbox nodes
> don't run work yet ([API keys & sandboxes](api-keys-sandboxes.md#sandboxes)).
> Once the OpenEng AI services are live ([status](ai.md)), you can create
> storage points on **Pro** or Enterprise and pick one for a config; they're
> stored and published with it, but nothing delivers to them until that ships.

*Figure: Connect → Storage points — provider cards (GitHub/S3/GCS/Drive/WebDAV) opening an editor with the key parameter, ${ENV} credential rows, and the path convention.*

## What it is, and when to use it

Without a storage point, results stay on the machine that produced them —
fine for interactive work, useless for a fleet. A storage point is for
[sandbox nodes](api-keys-sandboxes.md) and scheduled jobs whose outputs you
want collected somewhere durable.

## The five providers

Creating a storage point starts with a provider-card chooser:

| Provider | Key parameter | Typical use |
|---|---|---|
| **GitHub** | `repo` (owner/name) | Reports and artifacts as commits |
| **Amazon S3** | `bucket` | AWS object storage |
| **Google Cloud Storage** | `bucket` | Google Cloud object storage |
| **Google Drive** | `folder` | Human-browsable documents |
| **WebDAV** | `url` (the collection's endpoint URL) | Self-hosted / NAS targets |

(A sixth destination — keeping results local on the node — isn't a provider
card; it's the *none* choice on a config's storage-point setting.)

## Fields, one by one

- **Key parameter** — the provider-specific target above. Required: it is
  where deliverables land.
- **Credential** — **one or more** `${ENV_VAR}` rows (*Add variable*)
  naming the environment variables that hold the provider's secrets. A
  literal value is refused — the *delivering node* resolves every row at
  delivery time from its own environment or from the value stored for the
  config (the Web Console's **Placeholder values**); the environment wins
  ([Secrets](security.md#secrets-env-placeholders-end-to-end)). The **first row** is the `credentialEnv` the delivery consumes;
  extra rows publish as numbered siblings. Picking **Amazon S3** pre-fills
  the three standard AWS variables as separate rows —
  `${AWS_ACCESS_KEY_ID}`, `${AWS_SECRET_ACCESS_KEY}`, `${AWS_REGION}` — so
  the node's AWS SDK finds all three in its environment.
- **Path convention** — where inside the target results land, with two
  substitution tokens replaced **node-side** per run:

```text
runs/{threadId}/{nodeId}/
```

The editor shows a **live preview** with sample ids — pure computation; the
Console never contacts your storage.

The explicit **Save** in the header POSTs the document (disabled with the
reason while the key parameter is missing) and the **server mints the id**
(`stp_usr_…`). The list shows each point as a card: provider icon, key
parameter, mono id, path convention, and a config-usage chip (the configs
referencing it, else "Attach in the config composer") — plus trailing
**Edit** / **Delete** actions, delete behind a confirmation.

## Wiring it up

A storage point does nothing until referenced:

- **The config builder's Settings step → Storage point** picks one (or
  *none — results remain on the node*) for a config
  ([Configs](configs.md#the-settings-panel)). The advanced composer has the
  same setting.
- Fleet run delivery, the path that takes a run's results from the node that
  ran it to the storage point, isn't in the current engine build (see the
  warning above).

> **Note:** Honesty badge — the advanced composer labels the config-level
> storage-point setting **"Published but not yet consumed by the engine"**,
> and the current engine build has no delivery path at all (see the warning
> at the top of this page).

## Plan & tier notes

Storage points are **Pro and Enterprise** — included with both, no count
limit. Free sees the locked page with the teach line: *without one, results
stay on the node that produced them.* Pro and Enterprise launch in Q4 2026
and can't be purchased yet ([Plans & billing](account.md#ai-pricing)).

## Troubleshooting

**"That looks like a literal value — the node refuses it."** The credential
field takes an environment-variable *name* (`GITHUB_TOKEN`), not a token.
It's stored as `${GITHUB_TOKEN}` and resolved on the delivering node.

**Deliveries don't arrive.** Expected in the current release: the engine
doesn't deliver to storage points yet (see the warning at the top of this
page). Once delivery ships, check on the *node*: is the credential variable
exported in the environment `openeng` runs under, and is the key parameter
(repo/bucket/folder/url) reachable with that credential from that machine?
The Console can't test this for you — by design it never touches your
storage.

**Deleted a storage point a config still references.** The config keeps the
dangling id, and its publish validation flags it as blocking
(*Storage point "…" no longer exists.*) — pick a new one (or *none*) in the
builder's Settings step.
