# Symbolic connector bindings

`bindings.json` maps the short connection and folder names in authored
TypeScript to tenant resource keys. It lives in the SDK's work directory,
`.flow-sdk/`, beside the `<Name>.flow.ts` file.

## Project layout

```text
.flow-sdk/
  <Name>.flow.ts
  bindings.json
  connectors/
    <connector-key>.ts
  connectors-local/
    <connector-key>.ts
    descriptors/
      <connector-key>/
        index.json
        ...generated descriptor data...
```

`uip maestro registry prepare` writes `.flow-sdk/bindings.json` and prints the
import for `./connectors-local/<connector-key>.ts`, relative to the source.
The generated descriptor data lives below `connectors-local/descriptors/`; do
not import it directly. `bindings.json` is independent of that descriptor
overlay. Studio Web reads none of these files, and `uip solution pack`/`upload`
leave `.flow-sdk/` out.

## Schema

Use `schemaVersion: "1"` and a `bindings` array. Version `1` is the current
authored-file format marker. The current loader does not branch on this value,
but including it keeps the file explicit and compatible with shipped examples.

Each connector entry should carry the complete shape below. Resolution needs a
matching `name` or `id` and a `resourceKey` or `default`; the other fields keep
the resource kind and emitted binding purpose explicit.

| Field | Required for resolution | Meaning |
|---|:---:|---|
| `id` | one of `id` / `name` | Stable binding identifier; may be used as the symbolic source name. |
| `name` | one of `id` / `name` | Symbolic name normally passed to `connection` or `folder`. |
| `resource` | no | `"Connection"` for Integration Service connection and folder entries. |
| `resourceKey` | one of `resourceKey` / `default` | Tenant connection id or folder key. This value wins when both value fields exist. |
| `default` | one of `resourceKey` / `default` | Fallback when `resourceKey` is absent. Shipped examples repeat the resource key here. |
| `propertyAttribute` | no | `"ConnectionId"` for a connection or `"FolderKey"` for a folder. |

## Where both values come from

**Usually you do not fill these in at all.**
`uip maestro registry prepare <connector-key> --action <action>` discovers the connection and writes both entries into `bindings.json` for you — see [connector-params.md](connector-params.md#resolving-connection-scoped-reference-values).
Reach for the manual route below only when you are authoring bindings without
running `prepare`.

If you are doing it by hand: `uip is connections list --all-folders` returns the
connection id **and its folder key** on the same record, so one call answers both.
Always pass `--all-folders`: the default listing is your own folder only, and a
connection shared from another folder (the usual case on a team tenant) is
invisible without it — an empty or unrelated default listing is not evidence
that the connection does not exist.

```bash
uip is connections list --all-folders --output json
```

```text
{
  "Name": "dustin.metzgar",
  "Id": "c03a1967-f702-47d2-9ede-917aed159805",
  "Folder": "dustin.metzgar@uipath.com's workspace",
  "FolderKey": "b53217ce-25b2-46cd-a6b0-b73c6ba5894c",
  "ConnectorKey": "uipath-salesforce-slack",
  "State": "Enabled"
}
```

`Id` is the connection binding's `resourceKey`; **`FolderKey` is the folder
binding's**. Never fill either with a made-up GUID or with the binding's own
name. `compile` refuses two shapes, and `check` reports both first: a binding
whose `resourceKey` is its own name (`BINDING_SELF_NAME`), and a `connection:` /
`folder:` label that a `bindings.json` with entries does not declare
(`BINDING_UNDECLARED` — for example the source says `mySlack` while the file
declares `slack` and `shared`). It warns `CONNECTION_STUB` on an all-zero GUID,
an `<angle-bracket>` placeholder or any other non-GUID value, and on a label when
no `bindings.json` is loaded or it declares no entries (the run would fault at
dispatch — `'Connection' has an invalid GUID value` or a `401 Invalid
Organization or User secret`). A plausible-looking but wrong GUID still compiles
and faults at run time. Only an id read from the tenant is right.

Several connections often share one name (a team tenant can hold three Slack
connections all named `is-sandboxes`, in different folders). A name then cannot
pick one: `prepare … --connection <name>` lists each candidate with its
`--connection-id <id>` and folder — pass the id of the one in the folder you mean,
and `prepare` still writes both entries into `bindings.json`.

**Do not go looking in Orchestrator for the folder.** `uip or folders list` is a
different resource with different keys, and a folder binding wants the one the
CONNECTION lives in — which you already have. Measured on the eval corpus: an
agent that had already listed the connection went on to spend three to four
further calls on `uip or --help`, `uip or folders --help` and `folders list`,
searching for a folder matching the symbolic name in its prompt. The symbolic
name (`slack`, `shared`) is just the label you pass to `connector()`; it is never
something to search the tenant for.

Copy this two-connector, one-folder example and replace all three placeholders
with values from the connection listing above:

```json
{
  "schemaVersion": "1",
  "bindings": [
    {
      "id": "slack",
      "name": "slack",
      "resource": "Connection",
      "resourceKey": "<slack-connection-id>",
      "default": "<slack-connection-id>",
      "propertyAttribute": "ConnectionId"
    },
    {
      "id": "jira",
      "name": "jira",
      "resource": "Connection",
      "resourceKey": "<jira-connection-id>",
      "default": "<jira-connection-id>",
      "propertyAttribute": "ConnectionId"
    },
    {
      "id": "shared",
      "name": "shared",
      "resource": "Connection",
      "resourceKey": "<folder-key>",
      "default": "<folder-key>",
      "propertyAttribute": "FolderKey"
    }
  ]
}
```

Use unique `id` and `name` values. The resolver takes the first entry whose
`name` or `id` matches the authored symbol.

Give `connection:` and `folder:` different labels (`slack` / `shared`). With one
label for both, `prepare` writes one `FolderKey` entry, the connection resolves
to the folder key, and the run faults `401 Invalid Organization or User
secret`, although `check`, `compile` and `validate` pass. An emitted node whose
`connectionId` equals its `connectionFolderKey` is this collision: rename the
`folder:` label in the source and re-run `prepare`.

## Resolution and precedence

The compile commands load `--bindings <file>` when supplied. Otherwise they
load `.flow-sdk/bindings.json` under the current directory when it exists. A
workspace laid out before `.flow-sdk/` existed, with only a root-level
`./bindings.json`, keeps using that file; when both exist the `.flow-sdk/` one
wins and stderr names the ignored root file. `emitFlow()` uses the same
default unless `bindingsFile` or a `Bindings` instance is supplied.

```ts
.step('notify', connector(SendMessage, {
  channel: 'C123',
  text: 'Ready',
}, { connection: 'slack', folder: 'shared' }))
```

During emission, `connection: 'slack'` matches the entry whose `name` or `id`
is `slack`; `folder: 'shared'` is resolved the same way. For each match,
`resourceKey` wins over `default`. An unmatched symbol is emitted unchanged, so
do not treat a successful compile as proof that an invented id exists.

Only compile/emission reads the authored file. `uip maestro flow validate`,
solution resource refresh, and product debug read the emitted `.flow`, not
`.flow-sdk/bindings.json`. A compile regenerates the artifact from the authored
mapping. A later direct edit to the artifact remains in effect only until the
next compile.

## Emitted-artifact bindings

`uip maestro flow binding add` edits bindings inside an already emitted `.flow`;
it does not create or update `.flow-sdk/bindings.json`. SDK-authored Integration
Service actions and managed HTTP nodes should instead keep symbolic names in
source plus `bindings.json`, so recompilation deterministically restores the
same node detail and product bindings. Use direct artifact edits only for a
brownfield `.flow` with no source representation.
