> ## Documentation Index
> Fetch the complete documentation index at: https://docs.allgoodhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orchestration

> Policies clean up and decide, Smart Relationships match what has no clean key, and plans run campaigns — each one logging every decision with its reason.

Orchestration is the part of allGood that acts on your data. Three pieces do the work:

* **[Policies](#policies)** clean up and decide: normalize a job title, pick a time zone, choose a trusted value when two systems disagree.
* **[Smart Relationships](#smart-relationships)** connect records that have no clean key, like a lead to the account it belongs to.
* **[Plans](#plans)** run campaigns: a person moves through states, and each state sends what it sends.

All three write to the same [decision log](https://docs.allgoodhq.com/mk/data/architecture.md#anatomy-of-a-record) as everything else in allGood. Every change carries the inputs it was based on and a reason in plain language. That is the payoff: "why did this person get this email?" has one answer you can read, not a search across hundreds of smart campaigns.

## Overview

In Marketo, the logic lives in the campaigns. Every smart campaign carries its own cleanup, routing and suppression, and nobody can say what is happening to one person without opening all of them. allGood splits the jobs. Policies decide once, every campaign reads the result, and campaigns stay simple.

```mermaid theme={null}
flowchart LR
    S["Your data<br/>(CRM, forms, uploads, activity)"] --> P["Policies<br/>clean up and decide"]
    S --> SR["Smart Relationships<br/>match without a key"]
    SR --> P
    P --> PL["Plans<br/>run the campaign"]
    PL --> A["Email sent,<br/>Salesforce updated"]
```

A few things are true of all three:

* **They only ever write decisions.** Nothing edits a record directly. A decision says what changed, what it was based on, and why. You read it on the person's page, on each policy or plan's **Decisions** tab, and in your warehouse through the [outbound share](https://docs.allgoodhq.com/ops/snowflake/outbound-sharing.md).
* **They re-run only when their inputs change.** Each one declares what it reads. Change a field it reads and it wakes; change anything else and it does not. You never schedule a batch.
* **They decide; they do not send.** Sending email and updating Salesforce happen afterwards, through channels. See [Data Sharing](https://docs.allgoodhq.com/mk/data/sharing.md).
* **They are versioned.** You edit a draft and publish it. The published version is the one that runs, and publishing a change re-decides everyone against it.

Everything on this page lives under **Marketing Kernel → Orchestration**: policies and plans under **Config**, Smart Relationships under **Database → Relationships**, and a **Graph** that shows what reads what.

## Policies

Use a policy when you want one trusted answer about each person or company, kept current automatically. Typical jobs: map free-text titles onto job levels, work out a time zone from partial data, assign a territory from a messy company name, pick the right value when Salesforce and Marketo disagree, or flag a lead as sales-engaged. Once a policy has run, you build segments and plans on the clean field it wrote, and you stop re-implementing the rule in every campaign.

A policy reads a few fields, decides, and writes the answer to a field on the person or company, usually in **Smart Fields**. You configure it on three tabs:

| Tab | What you set | Job Level example |
| - | - | - |
| **Inputs & Outputs** | The record fields it reads, and the field it may write. It can read a related record too, via a relationship or a Smart Relationship, such as the person's account | Reads `person_forms.title` (what they typed) and `sfdc_contact.Title` (the CRM). Writes `job_level` |
| **Gate** | Who it runs on. Preview who passes before you publish | Either title exists |
| **Cascade** | How it decides: a formula, an agent with a prompt, or a formula first and the agent for whatever is left | A formula maps exact C-level titles to CxO; the agent sorts the rest into VP/Director, Manager or Individual Contributor, and its answer is restricted to those values |

That formula-then-agent shape is the usual one. The formula handles the obvious cases for free, and the agent only sees the hard ones. Agent cost is bounded further by caching: everyone with the same inputs shares one decision, so ten thousand "Software Engineer" titles cost one call.

**Where you see the result.** On a person's page, each Smart Field shows the decision that set it: the inputs and the agent's one-sentence reason. The policy's **Decisions** tab lists everything it decided; **Runs** shows when it ran. A **Tests** tab lets you pin example inputs with the answers you expect, so you can change a prompt and check it still classifies them the same way.

Policies chain. A job-level policy feeds a routing policy, and the routing policy's field can trigger a plan, so one chain of decisions runs from "the CRM said VP Engineering" to "this person was handed to sales".

## Smart Relationships

Use a Smart Relationship when two things belong together but nothing joins them exactly. The classic case is lead-to-account: the lead wrote "Acme Corp." and the account is "ACME Corporation, Inc.", or the lead wrote "GSK" and the account is "GlaxoSmithKline plc". An ordinary [relationship](https://docs.allgoodhq.com/mk/data/architecture.md#relationships) needs an exact match on a field. A Smart Relationship uses rules for the clear cases and an agent for the rest, and explains every pick.

You set it up on the **Setup** tab under **Orchestration → Database → Relationships**:

| Section | What you set | Lead to Account example |
| - | - | - |
| **Query side** | The entity type being matched, and the fields to match on. Each one gets at most one match | Person: `companyName`, `email` |
| **Corpus side** | The pool to match into, and its fields | Company: `name`, `domain` |
| **Conditions** | **Necessary**: every match must satisfy these. **Sufficient**: any one of these is a match outright, no agent needed | Necessary: the person has a company name. Sufficient: the names match ignoring case, or the email domain equals the account's web domain |
| **Agent** | The model, and your matching **Rules** in English, strongest first | Prefer an exact domain match; then an exact name; expand acronyms; then the closest spelling |

**How it plays out.** A person submits a form as "BPL" with a personal email. No sufficient condition holds, so the agent takes it: it searches your accounts for "BPL", finds nothing close, expands the acronym, searches "Brightpath Logistics", and picks Brightpath Logistics, Inc. Its decision reads: *Searched "BPL", then "Brightpath Logistics"; picked Brightpath Logistics, Inc. (brightpath.com). The email domain is personal, so the name rule decided it.* A no-match is recorded too, with its own reason, so the agent does not retry the same hopeless input every time it runs. The agent can only pick an account its search actually returned.

**Where you see the result.** The match shows up like any relationship: the person on the account's page, the account on the person's. The reason sits on the relationship and in the **Decisions** tab. **Analytics** shows the match rate, how many people are still undecided, and how many evaluations the cache saved.

**Using the match.** A policy can read across it. In the policy's **Inputs & Outputs**, add a related-record input and choose the Smart Relationship as the relationship, then read the account's type or territory onto the person. From there it can be [written back to Salesforce](https://docs.allgoodhq.com/mk/data/sharing.md) like any other field.

## Plans

Use a plan to run a campaign: who enters, what they get, what moves them on, and what stops the sends. A plan is a set of **states**, like Promoted, Delivered, Handed Off and Unsubscribed. Each person in the plan is in exactly one state. **Transitions** move people between states when something happens — a form submit, a booked meeting, an unsubscribe, or a field changing (for instance, a policy flagging them sales-engaged). Each state has **actions**: send this email now, send that one three days after they arrived.

Two rules make plans safe to run:

* **Leaving a state cancels what it had not sent yet.** Someone who converts, books a meeting or unsubscribes stops getting the sequence, with no suppression rule to build.
* **Every move is a decision with a reason.** It names the exact form submit or field change that caused it. "Why is Jane in Handed Off?" has one answer.

Plans are under **Orchestration → Config → Plans**. The plan page shows the funnel with live counts in each state and, below it, each state as a block: what it sends and when, and the transitions that lead into it. The **Decisions** tab is the history. A person's page lists every plan they are in.

**Gated content, end to end.** You do not usually build a plan by hand. A [motion](https://docs.allgoodhq.com/mk/motions/index.md) builds one for you. For a Gated Content motion you provide the content asset, the landing page and capture form, a delivery email, and one or more follow-up emails, each sent a set time after submit. Optionally, an audience to promote it to first. Publish the motion and this plan runs live, woken by each form submit, meeting, unsubscribe or bounce as it arrives:

```mermaid theme={null}
stateDiagram-v2
    direction LR
    state Active {
        Promoted --> Delivered: submits the form
    }
    [*] --> Promoted: in the promo audience
    [*] --> Delivered: submits the form
    Active --> HandedOff: meeting booked or sales engaged
    Active --> Unsubscribed: unsubscribes
    Active --> Bounced: email hard-bounces
```

| State | How you get there | What it sends |
| - | - | - |
| **Promoted** | You are in the promo audience | The promo emails, until you convert |
| **Delivered** (success) | You submit the form, whether or not you were promoted | The delivery email right away, then the follow-ups on their schedule |
| **Handed Off** | A meeting is booked or sales engages, from any state | Nothing further |
| **Unsubscribed** / **Bounced** | You unsubscribe or your email hard-bounces, from any state | Nothing further |

Because the form submit is itself the conversion, there is no enrollment race: the submission that creates the person is the one that admits them. Booking a meeting moves them out of Delivered, so the unsent follow-ups cancel on their own. Every one of those moves is in the log with its reason: "Converted: submitted the gate form", "Handed off to sales".

Plans also run without a motion. A lifecycle-stage plan or an account-engagement plan is just a plan whose transitions are all field changes.

## How this maps to Marketo

| In Marketo | In allGood |
| :- | :- |
| Data-management smart campaigns (normalization, scoring, routing) | Policies |
| Program statuses and flow steps | A plan's states, transitions and actions |
| Wait steps | Actions timed from when a person entered a state |
| Suppression rules ("don't send if they converted") | Leaving a state cancels its unsent actions |
| Program templates cloned per campaign | Motion templates, filled in per motion |
| Lead-to-account matching tools | A Smart Relationship |
| Activity log and campaign results | The decision log, in allGood and in [your warehouse](https://docs.allgoodhq.com/ops/snowflake/outbound-sharing.md) |

allGood builds your first policies and motion templates with your team. After that you can add more yourself, or describe what you need in plain language and have an agent in allGood draft the policy for you to review.

## Good to know

* **Publishing a change re-runs it.** Edit a policy's prompt and everyone is re-decided against the new version. Expect a burst of agent calls after a change to a policy or Smart Relationship with a large population.
* **A policy cannot clear a field.** An empty answer leaves the old value in place. If "unknown" needs to exist, make it a real value.
* **A Smart Relationship does not revisit past decisions when new accounts arrive.** A lead left unmatched stays unmatched until something about the lead changes or you republish the relationship. One match per lead, at most.
* **Field names are exact.** `title` and `Title` are different fields. If a policy sees nothing, check the case; the Gate preview shows you what it sees.
* **Decisions can't be searched here.** The Decisions tabs are lists. To query decisions by person or field, use the [outbound share](https://docs.allgoodhq.com/ops/snowflake/outbound-sharing.md).
* **Warehouse data arrives on a schedule; decisions leave live.** A policy reacting to a CRM change runs after the next sync lands. Its decision is readable in your warehouse as soon as it is applied. See [Data Sharing](https://docs.allgoodhq.com/mk/data/sharing.md).

> [!NOTE]
>
> Questions? Reach out to [support@allgoodhq.com](mailto:support@allgoodhq.com), or ask your allGood implementation lead.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.