Manifest Reference
Manifest format (v1alpha1)
Section titled “Manifest format (v1alpha1)”This reference is authoritative for Agoraform v0.6.0 and is based on the
tagged v0.6.0 manifest specification.
Agoraform configuration is a versioned YAML document containing declarative provider configuration and desired resources.
apiVersion: agoraform.io/v1alpha1providers: matomo: publish: true environment: liveresources: - address: matomo.goal.trial_started attributes: name: Trial Started matchAttribute: event_action pattern: trialStartedTop-level fields
Section titled “Top-level fields”| Field | Required | Description |
|---|---|---|
apiVersion | yes | Must be agoraform.io/v1alpha1. |
providers | no | Non-secret provider-specific desired state. |
resources | no | Desired managed resources. Omitted/empty is valid. |
Provider credentials, tokens, passwords, and other secrets must never be put in the manifest. They belong in runtime configuration such as environment variables.
Provider configuration is intentionally separate from credentials. For example, these are desired state and belong in Git:
providers: matomo: publish: true environment: liveThese do not:
MATOMO_TOKEN_AUTHMATOMO_URLGOOGLE_ADS_DEVELOPER_TOKENGOOGLE_ADS_REFRESH_TOKENMETA_ACCESS_TOKENMETA_AD_ACCOUNT_IDSee Matomo Tag Manager publication and the Google Ads and Meta providers.
Resource addresses
Section titled “Resource addresses”A resource address is three lowercase identifiers separated by dots:
provider.type.nameExample:
matomo.goal.trial_startedEach segment starts with a letter and may then contain lowercase letters, digits, or underscores. Duplicate addresses are rejected.
Resource references
Section titled “Resource references”Provider-neutral dependencies use a $ref object containing a logical
Agoraform address. Address-only references stay a single-key map:
resources: - address: matomo.trigger.trial_started attributes: type: customEvent event: trialStarted
- address: matomo.tag.trial_started attributes: type: matomoAnalytics trigger: $ref: matomo.trigger.trial_started eventCategory: signup eventAction: trialStartedThe $ref value is always a logical Agoraform address, never a provider-native
ID. Ordinary strings remain provider-owned values even if they happen to look
like an address.
An optional output selector consumes one declared non-sensitive named
output from the referenced resource, including across providers:
conversionId: $ref: googleads.conversion_action.trial_started output: conversionIdA reference without output still resolves to the full runtime binding
(provider-native identity plus computed outputs). A reference with output
resolves to that one value. Unknown, sensitive, unavailable, and wrong-kind
outputs fail before the dependent mutation. Arbitrary computed fields are not
automatically selectable.
Agoraform validates references and builds a directed dependency graph. Missing references, self-references, and cycles fail before remote mutations. Cross-provider output references create the same kind of dependency edge.
At apply time, logical references are resolved in dependency order. Those provider-native values are not written back into the manifest.
Resource attributes
Section titled “Resource attributes”resources[].attributes is provider-owned configuration. The core normalizes
YAML types and understands $ref; providers validate the actual schema.
Computed/read-only provider fields do not belong in configuration and must not
produce changes merely because provider-native IDs differ.
Matomo resources
Section titled “Matomo resources”matomo.goal
Section titled “matomo.goal”v0.1.0 introduced Matomo analytics goals. Common attributes:
| Attribute | Required | Description |
|---|---|---|
name | yes | Goal name; immutable once local state binds the resource. |
matchAttribute | yes | Goal matching mode such as event_action, url, or manually. |
pattern | unless manually | Value to match. |
patternType | no | contains (default), exact, or regex; numeric modes use provider defaults. |
Provider-native goal IDs live in local state, not attributes.
matomo.container
Section titled “matomo.container”A Tag Manager container can be declared instead of requiring
MATOMO_CONTAINER_ID:
- address: matomo.container.main attributes: name: Main Website context: webname and context (web, android, or ios) are required.
description is optional. Provider-native container IDs stay in local
state. v0.6.0 allows at most one matomo.container resource.
When that resource is present, Tag Manager children must reference it:
container: $ref: matomo.container.mainWhen it is absent, omit container and set MATOMO_CONTAINER_ID. Mixing
the two modes is rejected. See the Matomo provider reference.
matomo.variable
Section titled “matomo.variable”v0.2.0 supports Tag Manager Data Layer variables. v0.6.0 also supports Matomo Configuration variables:
- address: matomo.variable.user_id attributes: type: dataLayer key: userId name: User ID
- address: matomo.variable.config attributes: type: matomoConfiguration name: Matomo Configuration matomoUrl: https://matomo.example.com siteId: 1 enableLinkTracking: trueFor dataLayer, type and key are required; name is optional and
defaults to key. For matomoConfiguration, type, name, matomoUrl,
and siteId are required; enableLinkTracking is optional.
matomo.trigger
Section titled “matomo.trigger”v0.2.0 supports Custom Event triggers:
- address: matomo.trigger.trial_started attributes: type: customEvent event: trialStartedtype and event are required; name is optional and defaults to event.
matomo.tag
Section titled “matomo.tag”v0.2.0 supports Matomo Analytics event tags. Google Ads conversion tags use
the Matomo Tag Manager GoogleAdsConversion template:
- address: matomo.tag.trial_started attributes: type: matomoAnalytics trigger: $ref: matomo.trigger.trial_started eventCategory: signup eventAction: trialStarted matomoConfiguration: $ref: matomo.variable.config
- address: matomo.tag.google_ads_trial_started attributes: type: googleAdsConversion trigger: $ref: matomo.trigger.trial_started conversionId: $ref: googleads.conversion_action.trial_started output: conversionId conversionLabel: $ref: googleads.conversion_action.trial_started output: conversionLabelSupported event fields may be literals or, where documented, references to
managed variables. matomoConfiguration is an optional $ref to a managed
matomo.variable of type matomoConfiguration and applies to Matomo
Analytics tags. Google Ads conversion tags consume conversionId and
conversionLabel as literals or as selected outputs from a managed
googleads.conversion_action. Agoraform does not emit the application event;
the application still pushes the configured data-layer event. See the
Matomo provider reference
for the complete resource-specific schema, template parameter mapping, and
preservation behavior. The
v0.5 Matomo + Google Ads lifecycle example
is a complete managed-container workflow that consumes those outputs.
Google Ads resources
Section titled “Google Ads resources”v0.4.0 Search resources form a dependency graph. Campaigns require a budget; ad groups, targeting, and campaign conversion goals require a campaign; keywords and Responsive Search Ads require an ad group:
googleads.conversion_actiongoogleads.customer_conversion_goalgoogleads.campaign_budget └── googleads.campaign ├── googleads.campaign_conversion_goal ├── googleads.campaign_location ├── googleads.campaign_language └── googleads.ad_group ├── googleads.keyword └── googleads.responsive_search_adNew campaigns, ad groups, positive keywords, and Responsive Search Ads
default to PAUSED. See the
complete Google Ads Search campaign example.
googleads.conversion_action
Section titled “googleads.conversion_action”Website conversion actions. Common attributes:
| Attribute | Required | Description |
|---|---|---|
name | yes | Conversion action name. |
category | yes | Website category such as SIGNUP or PURCHASE. |
value | no | Default conversion value. |
count | no | ONE or MANY. |
primaryForGoal | no | Whether the action is primary for its conversion goal. |
status | no | ENABLED, HIDDEN, or REMOVED. |
type is always website (WEBPAGE) and is computed. Provider-native IDs and
resource names live in local state, not attributes. Optional conversion
windows, currency, and alwaysUseDefaultValue are documented in the
Google Ads provider reference.
- address: googleads.conversion_action.trial_started attributes: name: Trial Started category: SIGNUP value: 0 count: ONE primaryForGoal: trueSee the complete Google Ads conversion example and the complete Google Ads Search campaign example.
googleads.customer_conversion_goal
Section titled “googleads.customer_conversion_goal”Account-default website conversion-goal biddability. Google Ads creates
these objects automatically; Agoraform only updates biddable.
| Attribute | Required | Description |
|---|---|---|
category | yes | Website category such as SIGNUP or PURCHASE. |
origin | yes | WEBSITE. |
biddable | yes | Whether the goal is an account-default optimization goal. |
conversionAction | no | $ref to a managed googleads.conversion_action so apply creates that action first. |
- address: googleads.customer_conversion_goal.signup attributes: category: SIGNUP origin: WEBSITE biddable: true conversionAction: $ref: googleads.conversion_action.trial_startedgoogleads.campaign_budget
Section titled “googleads.campaign_budget”Daily Search campaign budgets. Amounts are declared in account-currency units and normalized to Google Ads micros for API calls and plan comparison.
| Attribute | Required | Description |
|---|---|---|
name | yes | Budget name used for creation and unmanaged discovery. For dedicated budgets, Google synchronizes the live name with the attached campaign and Agoraform does not treat that synchronization as drift. |
amount | yes | Daily budget in account-currency units. |
explicitlyShared | yes | false for a dedicated budget; true for a shared budget. A shared budget cannot be changed back to dedicated. |
deliveryMethod | no | STANDARD only for the supported Search workflow. ACCELERATED is rejected. |
- address: googleads.campaign_budget.brand attributes: name: Brand daily budget amount: 50 deliveryMethod: STANDARD explicitlyShared: falseSearch campaigns reference the budget by logical address:
- address: googleads.campaign.brand attributes: name: Brand budget: $ref: googleads.campaign_budget.brand bidding: strategy: MANUAL_CPCProvider-native IDs, resource names, micros, period, and type are computed. Updates use sparse field masks so unchanged sharing fields and Google-managed dedicated-budget names are not resent. Converting a dedicated budget to shared includes its name in the same mutation, as required by Google Ads. See the Google Ads provider reference.
googleads.campaign
Section titled “googleads.campaign”Search campaigns. The advertising channel is SEARCH. New campaigns default
to PAUSED. Campaigns must reference a googleads.campaign_budget.
Dynamic Search Ads settings are out of scope.
| Attribute | Required | Description |
|---|---|---|
name | yes | Campaign name. |
budget | yes | $ref to a googleads.campaign_budget. |
bidding | yes | Search bidding strategy such as MANUAL_CPC or MAXIMIZE_CONVERSIONS. |
status | no | PAUSED (default) or ENABLED. |
network | no | Search network / partner flags. |
startDate / endDate | no | YYYY-MM-DD. |
trackingUrlTemplate / finalUrlSuffix | no | Optional URL tracking fields. |
locationTargeting | no | Presence vs interest geotargeting: positive is PRESENCE, PRESENCE_OR_INTEREST, or SEARCH_INTEREST; negative is PRESENCE or PRESENCE_OR_INTEREST. |
- address: googleads.campaign.brand attributes: name: Brand status: PAUSED budget: $ref: googleads.campaign_budget.brand bidding: strategy: MANUAL_CPCUnsupported channel types fail validation before mutation. Ads, keywords, and location/language criteria are separate resources. See the Google Ads provider reference.
googleads.ad_group
Section titled “googleads.ad_group”Search standard ad groups. The type is SEARCH_STANDARD. New ad groups
default to PAUSED. Ad groups must reference a googleads.campaign.
| Attribute | Required | Description |
|---|---|---|
name | yes | Ad group name. Unique within the campaign. |
campaign | yes | $ref to a googleads.campaign. |
status | no | PAUSED (default) or ENABLED. |
type | no | Must be SEARCH_STANDARD when set. |
cpcBid | no | Max CPC bid in account-currency units. |
- address: googleads.ad_group.brand attributes: name: Brand status: PAUSED campaign: $ref: googleads.campaign.brand type: SEARCH_STANDARD cpcBid: 1.5Unsupported types fail validation before mutation. Targeting and ads remain separate resources. See the Google Ads provider reference.
googleads.keyword
Section titled “googleads.keyword”Search ad-group keyword criteria, including negative keywords. Keywords
must reference a googleads.ad_group. Match types are EXACT,
PHRASE, and BROAD. Keyword text is normalized to lowercase without
changing user intent. Text, match type, negative, and ad group are
immutable after create.
| Attribute | Required | Description |
|---|---|---|
adGroup | yes | $ref to a googleads.ad_group. |
text | yes | Keyword text without match-type punctuation. |
matchType | yes | EXACT, PHRASE, or BROAD. |
negative | no | true for a negative keyword. Defaults to false. |
status | no | Positive keywords default to PAUSED and may use PAUSED or ENABLED. Negative keywords default to ENABLED; their status is immutable after creation. |
cpcBid | no | Optional max CPC bid override in account-currency units. Not allowed on negative keywords. |
- address: googleads.keyword.brand_exact attributes: adGroup: $ref: googleads.ad_group.brand text: brand matchType: EXACT status: PAUSED cpcBid: 1.5- address: googleads.keyword.competitor_neg attributes: adGroup: $ref: googleads.ad_group.brand text: competitor matchType: PHRASE negative: trueNew negative keywords are created ENABLED when status is omitted. Creating
a new negative keyword as PAUSED is rejected because Google Ads does not
allow negative ad-group criteria to be updated later. For an existing negative
keyword, a requested status change fails during planning before any mutation.
Positive keyword status remains mutable.
Campaign-level negative keywords, Keyword Planner, audience or DSA criteria, and keyword-level URL or tracking overrides are out of scope. See the Google Ads provider reference.
googleads.responsive_search_ad
Section titled “googleads.responsive_search_ad”Responsive Search Ads attached to a Search ad group. Ads must reference
a googleads.ad_group. Agoraform manages serving copy, URLs, optional
display paths, optional pinning, and status. It does not generate
headlines or descriptions. Creative changes replace the underlying ad
lists; status updates the ad-group-ad relationship.
| Attribute | Required | Description |
|---|---|---|
adGroup | yes | $ref to a googleads.ad_group. |
finalUrls | yes | One or more absolute http or https landing-page URLs. |
headlines | yes | 3–15 headlines as strings or {text, pin} objects. |
descriptions | yes | 2–4 descriptions as strings or {text, pin} objects. |
path1 | no | Optional display-path segment. Requires no /. |
path2 | no | Optional second path segment. Requires path1. |
status | no | PAUSED (default) or ENABLED. |
- address: googleads.responsive_search_ad.brand attributes: adGroup: $ref: googleads.ad_group.brand status: PAUSED finalUrls: - https://example.com/ path1: shoes headlines: - text: Buy shoes online pin: HEADLINE_1 - Free shipping today - Shop the collection descriptions: - Find shoes that fit your style. - Free returns on every order.Dynamic Search Ads, Display, video, and Performance Max ads are out of scope. See the Google Ads provider reference.
googleads.campaign_location
Section titled “googleads.campaign_location”Search campaign location criteria, including excluded locations. Locations
must reference a googleads.campaign. Prefer canonical names or country
codes; Agoraform resolves them to Google Ads geo target constants and
fails when a name is missing or ambiguous. Campaign, location, and
negative are immutable after create.
| Attribute | Required | Description |
|---|---|---|
campaign | yes | $ref to a googleads.campaign. |
location | yes | Canonical name, ISO country code, or geoTargetConstants/{id}. |
negative | no | true to exclude the location. Defaults to false. |
- address: googleads.campaign_location.united_states attributes: campaign: $ref: googleads.campaign.brand location: United States- address: googleads.campaign_location.exclude_canada attributes: campaign: $ref: googleads.campaign.brand location: Canada negative: trueRadius/proximity targeting and audience segments are out of scope.
Presence vs interest behavior is locationTargeting on
googleads.campaign. See the
Google Ads provider reference.
googleads.campaign_language
Section titled “googleads.campaign_language”Search campaign language criteria. Languages must reference a
googleads.campaign. Prefer ISO codes such as en. Campaign and
language are immutable after create.
| Attribute | Required | Description |
|---|---|---|
campaign | yes | $ref to a googleads.campaign. |
language | yes | ISO code, language name, or languageConstants/{id}. |
- address: googleads.campaign_language.english attributes: campaign: $ref: googleads.campaign.brand language: enSee the Google Ads provider reference.
googleads.campaign_conversion_goal
Section titled “googleads.campaign_conversion_goal”Campaign-level website conversion-goal biddability. Google Ads creates
these objects automatically; Agoraform only updates biddable.
| Attribute | Required | Description |
|---|---|---|
campaign | yes | $ref to a managed googleads.campaign. |
category | yes | Website category such as SIGNUP or PURCHASE. |
origin | yes | WEBSITE. |
biddable | yes | Whether the goal is a campaign-level optimization goal. |
conversionAction | no | $ref to a managed googleads.conversion_action so apply creates that action first. |
- address: googleads.campaign_conversion_goal.trial_signup attributes: campaign: $ref: googleads.campaign.search_acquisition category: SIGNUP origin: WEBSITE biddable: true conversionAction: $ref: googleads.conversion_action.trial_startedSee the complete Google Ads Search campaign example.
Meta Ads resources
Section titled “Meta Ads resources”v0.6.0 supports one complete Meta website-conversion campaign graph. Declare the provider with an empty configuration block:
providers: meta: {}The provider block accepts no fields. META_ACCESS_TOKEN and
META_AD_ACCOUNT_ID are runtime settings and must not be placed in YAML.
The supported resources form this graph:
meta.ad├── meta.ad_set│ ├── meta.campaign│ ├── meta.custom_conversion│ │ └── meta.pixel│ └── meta.pixel└── meta.ad_creativeManaged relationships use logical $ref values. External Page, Instagram,
image, and video identifiers remain literal attributes.
New campaigns, ad sets, and ads default to PAUSED. Meta money attributes —
dailyBudget, lifetimeBudget, and bidAmount — are declared in ad account
currency units with at most two decimal places.
See the Meta provider and the complete Meta website conversion campaign example.
meta.pixel
Section titled “meta.pixel”Declares an existing Pixel/Dataset event source by name:
- address: meta.pixel.website attributes: name: Website| Attribute | Required | Description |
|---|---|---|
name | yes | Exact Pixel/Dataset name used for unique adoption. |
Agoraform does not create, rename, or delete Pixels/Datasets.
meta.custom_conversion
Section titled “meta.custom_conversion”Website Custom Conversions reference a managed Pixel/Dataset:
- address: meta.custom_conversion.trial_started attributes: name: Trial Started eventType: START_TRIAL pixel: $ref: meta.pixel.website rule: and: - event: eq: StartTrial defaultValue: 0| Attribute | Required | Description |
|---|---|---|
name | yes | Custom Conversion name. |
pixel | yes | $ref to a managed meta.pixel. |
rule | yes | Meta rule object, such as an event or URL condition. |
eventType | yes | Meta custom_event_type, such as START_TRIAL, PURCHASE, or LEAD. |
defaultValue | no | Non-negative default conversion value. |
pixel, rule, and eventType are immutable after creation.
meta.campaign
Section titled “meta.campaign”- address: meta.campaign.website_acquisition attributes: name: Website Acquisition objective: OUTCOME_SALES status: PAUSED specialAdCategories: [] buyingType: AUCTION adSetBudgetSharingEnabled: false| Attribute | Required | Description |
|---|---|---|
name | yes | Campaign name. |
objective | yes | Supported OUTCOME_* objective. |
specialAdCategories | yes | Applicable categories, or an empty list when none apply. |
status | no | PAUSED (default) or ACTIVE. |
buyingType | no | AUCTION (default and only supported value). |
dailyBudget / lifetimeBudget | no | Mutually exclusive positive amounts in account-currency units. |
bidStrategy | no | Campaign bid strategy; valid only with a campaign-level budget. |
adSetBudgetSharingEnabled | no | Defaults to false; cannot be true with a campaign-level budget. |
Objective, buying type, and budget ownership/type cannot change in place.
meta.ad_set
Section titled “meta.ad_set”- address: meta.ad_set.instagram_trial attributes: name: Instagram Trial Acquisition status: PAUSED campaign: $ref: meta.campaign.website_acquisition dailyBudget: 50 billingEvent: IMPRESSIONS optimizationGoal: OFFSITE_CONVERSIONS bidStrategy: LOWEST_COST_WITHOUT_CAP destinationType: WEBSITE pixel: $ref: meta.pixel.website customConversion: $ref: meta.custom_conversion.trial_started targeting: countries: [US] publisherPlatforms: [INSTAGRAM] instagramPositions: [FEED, STORIES, REELS]For OFFSITE_CONVERSIONS, both pixel and customConversion are required
and must reference the same pixel. The campaign objective must be
OUTCOME_SALES.
meta.ad_creative
Section titled “meta.ad_creative”- address: meta.ad_creative.instagram_trial attributes: name: Instagram Trial Creative pageId: "123456789012345" instagramUserId: "234567890123456" destinationUrl: https://example.com/trial primaryText: Start organizing your catalog today. headline: Start Your Free Trial callToAction: LEARN_MORE imageHash: "0123456789abcdef0123456789abcdef"Use exactly one external imageHash or videoId. Only name is mutable.
meta.ad
Section titled “meta.ad”- address: meta.ad.instagram_trial attributes: name: Instagram Trial Ad adSet: $ref: meta.ad_set.instagram_trial creative: $ref: meta.ad_creative.instagram_trial status: PAUSEDname, status, and creative can be updated. The parent adSet is
immutable after creation.
Matomo provider desired state
Section titled “Matomo provider desired state”v0.2.0 recognizes:
providers: matomo: publish: true environment: live| Field | Required | Description |
|---|---|---|
publish | no | Boolean; default false. When true, converge the configured Tag Manager container into the target environment through normal plan/apply/destroy. |
environment | no | Tag Manager environment; default live. |
Unknown provider configuration fields are rejected.
Validation
Section titled “Validation”agoraform validateagoraform validate -f path/to/manifest.yamlagoraform validate path/to/manifest.yamlValidation covers:
- YAML and
apiVersion; - provider names and provider-specific configuration;
- resource address syntax and duplicates;
$refand{ $ref, output }validity and dependency cycles;- registered provider/resource support;
- provider connectivity;
- provider-specific resource fields;
- managed-container versus
MATOMO_CONTAINER_IDexclusivity.
Matomo runtime connection settings come from MATOMO_URL,
MATOMO_TOKEN_AUTH, and MATOMO_SITE_ID; Tag Manager resource/publication
work also requires either a matomo.container resource or
MATOMO_CONTAINER_ID. Google Ads connection settings come
from GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID,
GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, and
GOOGLE_ADS_CUSTOMER_ID. Meta connection settings come from
META_ACCESS_TOKEN and META_AD_ACCOUNT_ID.
See plan, apply, import, destroy, and local state.