Skip to main content
Your Adjar config can live in a single TOML file or be split across many — the loader merges everything into one logical account before any plan or apply runs, so the split is purely about how you want to read, diff, and edit. This page covers when to split, how the imports directive composes files, and the two rules that keep write-back predictable.

Single file or split?

Both are fully supported.
Single fileSplit (recommended)
Best forSmall or experimental accounts, one editorReal accounts, team or AI-agent editing
DiffsEvery change touches one big fileEach change touches one small file
SetupNothing — just google.tomlA root file plus an imports list
adjar import bootstraps to a single file (or stdout) by default, so starting single and splitting later is the natural path — there’s no migration, just move blocks into new files and add an imports entry. For anything beyond a handful of campaigns:
google.toml                   ← root: platform + [account] only
google/
  assets.toml                 ← [[assets]] library
  conversions.toml            ← [[conversions]]
  campaigns/
    brand.toml                ← one [[campaigns]] each
    db-access-control.toml
    competitor-terms.toml
# google.toml
platform = "google"
imports = [
  "google/assets.toml",
  "google/conversions.toml",
  "google/campaigns/*.toml",
]

[account]
id = "4821937650"
Why this shape:
  • Diffs stay small and scoped. apply writes server-issued IDs back into the file that declared each element, so editing one campaign touches one file in git — not a 2,000-line monolith.
  • Clean boundaries for AI agents. An agent told to tune the competitor campaign edits competitor-terms.toml and can’t accidentally clobber another. One file = one unit of work.
  • Match files to change rate. [account], assets, and conversions change rarely; campaigns churn constantly. Keeping the stable sections in their own files means most diffs only hit campaigns/.

How imports composes files

The imports array in a file lists the fragments to merge into it. See the account root reference for the field itself; the resolution rules are:
  • Glob-aware. "google/campaigns/*.toml" picks up every campaign file in the directory — adding a new campaign is just creating a new file.
  • Relative to the importing file’s own directory, not the repo root or your working directory.
  • Nesting is allowed. An imported file may itself declare imports, resolved relative to its location. Cycles are detected and rejected.
  • Deterministic merge order. Within each section, files merge in sorted order, so the result is reproducible.
Imported fragments may contain only top-level array sections — [[assets]], [[conversions]], [[campaigns]]. The singletons platform and [account] must stay in the root file, or the loader errors. This is what makes a fragment unambiguously a fragment.

Two rules that keep write-back predictable

Because apply rewrites your config to record server-issued IDs, two behaviors are worth knowing:
  1. New blocks land in the root file. When you add a campaign (or asset, or conversion) with no id and run apply, the loader has no recorded “slot” for it, so its written-back form goes to google.toml rather than into campaigns/. After the first apply, move the block into its own file — subsequent applies then keep it there.
  2. Configs are machine-edited, so comments don’t survive. Every apply re-serializes the files it touches. Inline TOML comments are dropped on write-back. Keep explanatory notes in commit messages, a README, or your agent’s SKILL.md — not inside the TOML.
  • Account Root — the platform, imports, and [account] fields in the root file
  • Introduction — why plain-text config in git is the foundation for AI-assisted ad management
  • The core workflow — how import, plan, apply, and report turn config edits into live changes