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

# adjar plan

`adjar plan` is your safety net. It reads your local TOML config, fetches the current state of your live ad account (Google Ads or OpenAI Ads, read from the config's `platform` field), and prints a precise diff of every change that [`adjar apply`](/docs/cli/apply) would make. No API writes happen during a plan — it is completely read-only. Make `adjar plan` a habit before every apply, and treat its output as the authoritative record of what is about to change.

## Syntax

```bash theme={null}
adjar plan --config <file> [-o <plan-file>]
```

## Flags

<ParamField query="--config <file>" type="string" required>
  Path to the root TOML config file (e.g., `config/google.toml`). Adjar resolves all referenced subdirectory files relative to this root.
</ParamField>

<ParamField query="--credentials <path>" type="string">
  Path to the platform credentials JSON file (e.g. `google.json`). Alternatively set `ADJAR_CREDENTIALS`. See [Authentication](/docs/cli/overview#authentication).
</ParamField>

<ParamField query="-o, --out <file>" type="string">
  Write a reviewable **plan file** to this path instead of printing the diff. The file captures the exact steps and a hash of the config they were computed against, so [`adjar apply -f <file>`](/docs/cli/apply) can later execute it verbatim — and rejects it if the config has changed since. A plan file is only saved when the diff is clean; if drift is detected the command errors instead of writing one. The human-readable diff still prints (to stderr) so you can review what was saved.
</ParamField>

## Plan is always safe to run

`adjar plan` makes no writes to your ad account and does not modify any local files. You can run it as many times as you like at any point in your workflow — before committing, in a CI pipeline, or simply to confirm that your config is in sync with the live account.

## How plan works

Each run fetches the live account first, then diffs your local config against it:

<Steps>
  <Step title="Fetch live state">
    Adjar runs a set of read-only queries against the platform's API to pull the current state of the account — campaigns, ad groups, ads, and conversions, plus (on Google Ads) keywords, negatives, and assets. It prints each query result with a count as it lands.
  </Step>

  <Step title="Diff against config">
    Adjar compares the fetched state to your local TOML config and computes the set of resources to **create**, **archive**, or **update**.
  </Step>

  <Step title="Print the plan">
    Adjar prints a one-line headline, a summary by resource type, and then the individual changes grouped by type.
  </Step>
</Steps>

## Example output

Below is representative plan output **from a Google Ads account** after adding a new ad group, expanding keywords, switching three keywords from phrase to exact match, and adding a campaign negative. An OpenAI Ads plan reads the same — a headline, a summary by type, and the grouped changes — over its own resource types (campaigns, ad groups, ads):

```
adjar plan --config config/google.toml

Fetching live Google Ads state for customer 7272244390 — 10 queries…
  ✓ campaign negatives (180)
  ✓ keywords (247)
  ✓ ad groups (17)
  ✓ campaign asset links (34)
  ✓ ads (16)
  ✓ customer asset links (3)
  ✓ campaigns (3)
  ✓ campaign targeting (144)
  ✓ conversion actions (19)
  ✓ assets (74)
# google  ·  account 7272244390 (Bytebase Ads)

Plan: 11 to create, 3 to archive.

Summary by type:
  ad_groups: 1 to create
  keywords: 8 to create, 3 to archive
  campaign_negatives: 1 to create
  ads: 1 to create

Ad groups:
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords  "GORM keywords" · cpc=$0.01

Keywords:
    + DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database change management [EXACT]  "database change management" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database ci/cd [EXACT]  "database ci/cd" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database version control [EXACT]  "database version control" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm [EXACT]  "gorm" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm migration [EXACT]  "gorm migration" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm automigrate [EXACT]  "gorm automigrate" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm auto migrate [EXACT]  "gorm auto migrate" · EXACT
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm migrate [EXACT]  "gorm migrate" · EXACT
    - DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database version control [PHRASE]  (archive)
    - DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database change management [PHRASE]  (archive)
    - DB Change Mgmt | SEARCH | 2026-Q2 / Generic keywords / database ci/cd [PHRASE]  (archive)

Campaign negatives:
    + DB Change Mgmt | SEARCH | 2026-Q2 / ispirer [BROAD]  "ispirer" · BROAD · NEGATIVE

Ads (RSA):
    + DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / GORM Schema Migration  "GORM Schema Migration" · RSA · 13H/4D
```

## What the output shows

The output has four parts:

* **Fetch progress** — one `✓` line per read-only query, with the count of resources returned. This is Adjar pulling the live account state before diffing.
* **Headline** — the account being targeted (`# google · account 7272244390 (Bytebase Ads)`) followed by a one-line `Plan:` summary of total creates, archives, and updates.
* **Summary by type** — per-resource-type counts, so you can see at a glance how many ad groups, keywords, negatives, and ads are affected.
* **Changes by type** — the individual resources, grouped under a heading for each type. Each line is prefixed with an operation marker and shows the resource's full hierarchical path followed by its key details.

Operation markers:

* **`+` (plus)** — a resource that will be **created**, with its key fields shown after the path (e.g. `· EXACT`, `· cpc=$0.01`, `· RSA · 13H/4D`).
* **`~` (tilde)** — a resource that exists in both config and the live account but whose fields differ will be **updated**. Each changed field is listed beneath the path as `field: before → after` (large budget or bid swings are flagged with a `⚠` percentage).
* **`-` (minus)** — a resource that will be **archived**. Adjar archives rather than hard-deletes, so the change is recoverable on the platform.

Resource paths read top-down through the hierarchy, separated by `/` — for example `DB Change Mgmt | SEARCH | 2026-Q2 / GORM keywords / gorm [EXACT]` is the `gorm` exact-match keyword in the `GORM keywords` ad group of the `DB Change Mgmt | SEARCH | 2026-Q2` campaign.

## Next steps

Once you've reviewed the plan output and are satisfied with the proposed changes, run [`adjar apply`](/docs/cli/apply) to execute them against your live account.
