> For the complete documentation index, see [llms.txt](https://docs.pandium.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pandium.com/getting-started/anatomy-of-an-integration/pandium.yaml-spec/migrating-to-manifest-version-1.0.md).

# Migrating to Manifest Version 1.0

Move an existing integration from PANDIUM.yaml manifest version 0.4 to version 1.0, where tenant metadata replaces saved stdout as the store for values an integration discovers at runtime.

{% hint style="warning" %}
**Manifest versions below 1.0 are deprecated.** They still build and run, and no sunset date has been set, but they may miss out on new features. Plan on moving existing integrations to `1.0`.
{% endhint %}

Manifest version `1.0` introduces [tenant metadata](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/tenant-metadata.md): a validated, schema-backed store for the values an integration discovers at runtime. On `0.4` those values lived in the saved stdout of the last run. On `1.0` they live in tenant metadata, and [dynamic configurations](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/dynamic-configurations.md) and [dependent selectors](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/dependent-selector-configurations.md) read their options from there.

Nothing is upgraded for you, and nothing breaks the day you don't migrate: an integration left on `0.4` keeps building and running as it does today. What it does not get is anything added to the platform from here on, since `1.0` is the only manifest version under active development. Migrating also buys you schema validation on the values your integration stores, and config options sourced from metadata rather than from a saved stdout file.

Most migrations are small. If your integration has no `metadata_schema`, no dynamic configs, and never reads the prior run's stdout, it is a one-line change.

## What changes

|                                  | `0.4`                                                        | `1.0`                                                                                              |
| -------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| Runtime values stored in         | Last run's stdout, saved to a file                           | Tenant metadata, validated against `metadata_schema`                                               |
| Dynamic config options           | `$ref: '#/definitions/<name>'`, filled from init-sync stdout | `$ref: '#/metadata/<key>'`, resolved from tenant metadata                                          |
| Dependent selector options       | `optionsMapPath: '#/definitions/<name>'`                     | `optionsMapPath: '#/metadata/<key>'`                                                               |
| Undeclared keys in stdout        | Allowed                                                      | Rejected, unless you set `additionalProperties: true` yourself                                     |
| Required metadata keys           | n/a                                                          | Must declare a `default`, or the build fails                                                       |
| Reading prior run output in code | `PAN_CTX_LAST_RUN_STD_OUT`                                   | `PAN_CTX_TENANT_METADATA_FILE`                                                                     |
| Rerun context                    | Metadata as it was when the original run started             | Chosen per rerun: the original run's metadata, the tenant's current metadata, or a custom document |

What does **not** change: your `base`, `build` and `run` mappings; your `configs` `uischema`; static configs; connectors; run triggers; and the fact that an integration publishes values by printing a single JSON object to stdout.

## 1. Bump the version

```yaml
version: 1.0
```

Anything outside `0.4` to `1.0` fails the build with `Wrong version in Pandium file, must be version 0.4 to 1.0`.

If your integration has no `metadata_schema`, no dynamic configs, and never reads `PAN_CTX_LAST_RUN_STD_OUT` or `PAN_CTX_LAST_SUCCESSFUL_RUN_STD_OUT`, you are done. Otherwise, steps 2 to 4 apply to integrations with a `metadata_schema` or dynamic configs, and step 5 applies to any integration that reads the prior run's stdout. Step 6 applies to everyone who reruns.

## 2. Declare a `metadata_schema`

Every value your integration wants to persist between runs must be declared as a property of `metadata_schema.schema`. See [Tenant Metadata](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/tenant-metadata.md) for the full shape.

Three rules apply on `1.0` that did not apply before, all enforced when the release builds:

* Undeclared keys are rejected by default
* Every `required` key needs a valid `default`
* `pandium` is a reserved property name

**Undeclared keys are rejected by default.** If you don't write an `additionalProperties` value yourself, Pandium sets `additionalProperties: false` on your schema. A run whose stdout introduces a key you didn't declare fails with the status **Failed (Metadata Validation)**, and the tenant's metadata is left untouched. This is the change most likely to break an integration that prints a large stdout object, so either declare every key you print, or opt back into the older permissive behavior:

```yaml
metadata_schema:
  schema:
    type: object
    additionalProperties: true
    properties:
      warehouse_location:
        type: string
```

An explicit value is never overwritten, `true` or `false`.

**Every `required` key needs a valid `default`.** At build time Pandium collects the defaults declared across your schema and validates that collection against the schema itself. A required key with no default fails the build:

```
metadata_schema is invalid: metadata_schema's default values do not satisfy its own schema:
- : required but has no valid default value: api_key
```

The rule exists so a tenant's metadata is complete and valid from the moment the tenant is created, before any run has happened. Either give the key a default, or drop it from `required`. Defaults are also checked against their own type and constraints, so a `default: "yes"` under `type: boolean` fails the same way. Every default problem is reported together in one build, so you don't fix them one build at a time.

**`pandium` is a reserved property name.** Declaring a top-level property called `pandium` (in any casing) fails the build with `"pandium" is a reserved property name and cannot be declared in metadata_schema`. Pandium adds this key to your schema for its own use. Rename your property.

## 3. Move dynamic config options into metadata

On `0.4`, a dynamic config points at a `definitions` entry, and Pandium fills that entry from the saved stdout of the tenant's last init sync. On `1.0`, the config points directly at a metadata key.

Before:

```yaml
configs:
  schema:
    definitions:
      audiences:
        enum:
          - placeholder
    properties:
      mailchimp_audience:
        $ref: '#/definitions/audiences'
        type: string
```

After:

```yaml
configs:
  schema:
    properties:
      mailchimp_audience:
        $ref: '#/metadata/audiences'

metadata_schema:
  schema:
    type: object
    properties:
      audiences:
        type: array
        items:
          type: string
```

The `definitions` entry and its `placeholder` are no longer needed for that field; the metadata key replaces both. Keep `definitions` for any genuinely static option lists that are the same for every tenant; those are unchanged on `1.0`.

Your init sync code does not have to change. It still prints one JSON object whose keys match the names Pandium resolves against, and those names are now metadata property names rather than definition names. If you kept the same names, the code is already correct.

An array of strings resolves to an enum. An array of `{const, title}` objects resolves to a `oneOf`.

## 4. Repoint dependent selectors

A [dependent selector](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/dependent-selector-configurations.md) changes only in where its option map comes from. `parentField` still points at a config property.

Before:

```yaml
      food_item:
        type: string
        optionsMapPath: '#/definitions/food_items_map'
        parentField: '#/properties/food_type'
```

After:

```yaml
      food_item:
        type: string
        optionsMapPath: '#/metadata/food_items_map'
        parentField: '#/properties/food_type'
```

Declare `food_items_map` in `metadata_schema.schema.properties` as an object, and keep printing the same parent-to-children map from your init sync.

## 5. Stop reading the prior run's stdout

On `1.0` Pandium no longer tracks a stdout file on the tenant, so these environment variables are no longer set in a run:

* `PAN_CTX_LAST_RUN_STD_OUT`
* `PAN_CTX_LAST_SUCCESSFUL_RUN_STD_OUT`

Anything that read them should read tenant metadata instead. Pandium writes the tenant's current metadata to a JSON file and puts its path in `PAN_CTX_TENANT_METADATA_FILE`:

```python
def load_metadata():
    path = os.getenv('PAN_CTX_TENANT_METADATA_FILE')
    if not path:
        return {}
    try:
        with open(path) as file:
            return json.load(file)
    except FileNotFoundError:
        return {}
```

The rest of the run context is unchanged.

## 6. Expect the new rerun behavior

On `0.4`, every rerun restored the metadata snapshot taken when the original run started, so a rerun saw exactly what the original run saw. A custom rerun could also supply a replacement stdout file.

On `1.0`, the metadata a rerun receives depends on the rerun type you choose:

* **Original configuration**: the metadata the original run received, restored from that run's snapshot. If the original run has no snapshot, the tenant's current metadata is used instead.
* **Current configuration**: the tenant's current metadata. If metadata changed after the original run, the rerun sees the newer values.
* **Custom configuration**: a JSON object you supply, which **replaces** the tenant's metadata for that run rather than merging into it. Any key you leave out is absent from the run. It must be a valid JSON object and satisfy `metadata_schema`, or the rerun is rejected with a `422` and no run is created. The `stdout` override is no longer accepted on `1.0`.

Whichever type you choose, the rerun's own stdout is validated and merged into the tenant's metadata like any other run, unless you opt out of saving the result. A custom rerun that saves its result also writes the supplied document to the tenant's metadata before the run starts.

## 7. Roll it out

1. Run the init sync locally with the [Pandium CLI](/getting-started/pandium-integration-development-kit-idk/pandium-cli.md) (`pandium local run --mode init <tenant_id>`) to check that your code reads `PAN_CTX_TENANT_METADATA_FILE` and prints the keys you expect. A local run exercises the code only; stdout is validated against `metadata_schema` when a run happens on the platform.
2. Run `pandium local preview-configs` to check the config form. For a `1.0` manifest the preview resolves `#/metadata/` references and `optionsMapPath` maps the way the platform does, using sample values generated from `metadata_schema`.
3. Build the release. Any `metadata_schema` problem fails the build, so a broken schema never reaches a tenant.
4. Point a test tenant at the new release before moving the default channel. A tenant on the `Default` or `Latest` release channel picks up the new manifest as soon as that release becomes its current one.
5. Metadata is not populated from a tenant's saved `0.4` stdout. A tenant whose previous release already had a `metadata_schema` keeps the metadata it has. A tenant that only used `definitions` starts with the new schema's defaults, and gets its option lists the first time an init sync runs against the new release.
6. Until a run has written a value for a metadata key that a config references, that field renders in an unsynced state with its options disabled. For a tenant connecting through the In-App Marketplace this resolves on its own: Pandium runs an init sync before showing the Connection Settings form. For an existing tenant, run an init sync once against the new release.

You can also seed or correct metadata directly through the API rather than waiting for a run. `PATCH` merges, `PUT` replaces, and `POST .../metadata/reset` restores the release's schema defaults. See [Tenant Metadata](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/tenant-metadata.md#updating-and-reviewing-tenant-metadata-using-the-pandium-api).

## Troubleshooting

| Symptom                                                                           | Cause                                                                                                                                                                         |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Build fails: `required but has no valid default value: <key>`                     | A `required` metadata key has no `default`. Add one or drop the key from `required`.                                                                                          |
| Build fails: `metadata_schema's default values do not satisfy its own schema`     | A declared `default` doesn't match its property's own type or constraints.                                                                                                    |
| Build fails: `"pandium" is a reserved property name`                              | Rename the top-level `pandium` property in `metadata_schema`.                                                                                                                 |
| Build fails: `Wrong version in Pandium file`                                      | `version` is outside `0.4`–`1.0`.                                                                                                                                             |
| Runs end in **Failed (Metadata Validation)**                                      | The run's stdout doesn't satisfy `metadata_schema`, most often an undeclared key now that `additionalProperties: false` is the default. The tenant's metadata is not updated. |
| A config dropdown is empty and disabled                                           | No run has written metadata for the key it references yet. Run an init sync, or set the value through the metadata API.                                                       |
| A config dropdown is empty, or still shows its `placeholder`, after the migration | The field still points at `#/definitions/`, or the metadata key it points at isn't declared in `metadata_schema.schema.properties`.                                           |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.pandium.com/getting-started/anatomy-of-an-integration/pandium.yaml-spec/migrating-to-manifest-version-1.0.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
