Skip to content

Latest commit

 

History

History
179 lines (121 loc) · 10.2 KB

File metadata and controls

179 lines (121 loc) · 10.2 KB

CLAUDE.md

Runbook for Claude Code sessions running inside a clone of GTAG-Manager. Follow this file as the source of truth when a user asks you to set up a Google Tag Manager workspace.


1. What this repo does

GTAG-Manager is a local Python CLI (binary: gtm-agent) that drives the Google Tag Manager API. It takes a YAML spec describing the variables, triggers, and tags a workspace should contain, diffs that spec against the live workspace, and applies the changes. Optionally it creates and publishes a new container version. It is operated by you (Claude Code) on behalf of the user.

You are running locally on the user's machine. OAuth tokens never leave this machine. There is no hosted service, no telemetry, no third-party intermediary.


2. First-run checklist

If gtm-agent whoami already works, skip this section. Otherwise help the user complete each step before doing any GTM work.

  1. Create a Google Cloud project. Open https://console.cloud.google.com/, project picker, New Project, name it gtag-manager.
    • Verify: the project picker shows the new project as the active project.
  2. Enable the Tag Manager API. Direct link (one click): https://console.cloud.google.com/apis/library/tagmanager.googleapis.com — click Enable. This step is required; without it every API call returns accessNotConfigured / SERVICE_DISABLED. If gtm-agent list fails with that error after the user thinks they enabled it, ask them to confirm the enabled API is on the same project whose OAuth client they used for .env.
    • Verify: the API page shows "API enabled" and a "Manage" button.
  3. Create an OAuth client (Desktop app). APIs & Services > Credentials > Create credentials > OAuth client ID > Desktop app. Copy the Client ID and Client secret.
    • Verify: the credentials page lists a new OAuth 2.0 Client ID of type "Desktop".
  4. Set up .env.
    cp .env.example .env
    # Edit .env and paste GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET.
    • Verify: grep GOOGLE_OAUTH .env shows both values populated, neither blank.
  5. Install the CLI.
    pip install -e .
    • Verify: gtm-agent --help lists the seven commands (auth, whoami, list, init, plan, apply, publish).
  6. Authenticate.
    gtm-agent auth
    • Verify: a browser window opens, the user approves consent, the CLI prints a success message.
  7. Sanity check.
    gtm-agent whoami
    • Verify: prints the user's email and three GTM scopes. Stop and debug if email is missing or scopes are wrong.

Once whoami succeeds, the agent is ready. Do not proceed to GTM operations until then.


3. Three modes the user might be in

Decide which mode applies and route accordingly.

(a) "Here is a brief / doc / paragraph describing what we want." The user pastes free-form requirements. Go to section (4) Brief to spec workflow.

(b) "Here is an existing YAML spec at PATH." The user already has a spec file. Run:

gtm-agent plan PATH

Show the user the full plan output. Ask: "This will make N changes. Confirm yes apply this to proceed." Wait for the user's explicit confirmation. Then run:

gtm-agent apply PATH

Only run with --publish --yes-publish if the user explicitly told you to publish. See section (6) Publish gate.

(c) "I'm not sure what I need — ask me questions." Run the interactive starter:

gtm-agent init starter.yaml

The wizard prompts the user through the basics. Once starter.yaml is written, switch to mode (b) with PATH=starter.yaml.


4. Brief to spec workflow

When the user pastes a brief, do not start writing YAML immediately. Ask these clarifying questions, one block at a time, and wait for answers:

  1. GA4 measurement ID. "What is your GA4 measurement ID? It looks like G-XXXXXXX." If they give a UA- ID, stop and tell them GA4 only.
  2. Events to track. "List every event you want fired, one per line. For each, say whether it is a built-in browser event (page view, link click) or a custom data layer event." Get an explicit list.
  3. Ecommerce. "Is this an ecommerce site? (yes/no)" If yes: "Which ecommerce events specifically — purchase, add_to_cart, view_item, begin_checkout, others?"
  4. Consent mode. "Is consent mode required? (yes/no)" If yes: "Default deny analytics + ads, or default deny ads only?"
  5. App architecture. "Is this a single-page app (Next.js/React/Vue with client-side routing) or a multi-page app (server-rendered, full page loads)?" SPAs need history-change triggers; MPAs do not.
  6. Page URL scope. "Should tags fire on all pages, or only specific URL patterns? If patterns, list them (e.g. /checkout/*, /blog/*)."

When all six are answered, generate the spec by editing a copy of an existing example, not from scratch:

  • For pageview-only or simple event tracking, copy examples/ga4-pageview.yaml.
  • For ecommerce, copy examples/ga4-ecommerce.yaml.

Write the result to ./generated-spec.yaml. Then validate it:

gtm-agent plan ./generated-spec.yaml

If plan fails with a Pydantic error, the spec is malformed — fix it, do not skip the validation. Show the user the plan output and switch to mode (b) for confirmation and apply.


5. Always plan before applying

Never run apply without first showing the user the output of plan and getting an explicit "yes apply this" (or equivalent — "go", "ship it", "do it"). The plan output is the source of truth: every action, every resource, in the order it will run.

If the user is confused by what the plan says, do not proceed. Walk them through each row. If they want changes to the spec, edit the YAML, re-plan, re-confirm.

gtm-agent apply mutates a real GTM workspace. There is no undo button.


6. Publish gate

Never publish unless the user explicitly says "publish it", "ship it", "push it live", or unmistakable equivalent. The default after a successful apply is to leave the workspace dirty and unpublished — the user can then review the diff in the GTM UI.

The CLI enforces this with the --yes-publish flag: --publish alone is rejected. You must still ask the user before passing both flags. Required exchange:

Agent: "Apply succeeded. The workspace has changes that are not yet published. Want me to publish a new version now?" User: "Yes, publish it."

Then run:

gtm-agent apply ./generated-spec.yaml --publish --yes-publish \
    --version-name "<short name>" --version-notes "<what changed and why>"

If the user says "not yet" or anything ambiguous, stop. Do not pass --publish.


7. Spec reference

The YAML schema is a thin wrapper over the GTM v2 API. When you need to know what a type value means, consult these references:

type values in the spec are short codes from the API, not display names. Common ones:

  • Tags: gaawc (GA4 config / Google Tag), gaawe (GA4 event), html (custom HTML).
  • Triggers: pageview, customEvent, click, linkClick, historyChange, formSubmission.
  • Variables: c (constant), v (data layer variable), jsm (custom JavaScript), k (1st party cookie), u (URL).

If you can't find a type code in the API reference, ask the user — do not guess.


8. Common pitfalls

  • Built-in variables are separate from user-defined variables. pageUrl, clickElement, clickClasses, etc. are not created via the variables endpoint; they are enabled via built_in_variables.create. The CLI handles this for you, but only if you list them in the spec's built_in_variables section. Forgetting this means {{Page URL}} references will silently resolve to empty strings in the browser.
  • Custom event triggers match the data layer event key. The GTM API field is named customEventFilter (not filter). The filter compares {{_event}} to the event name string. The CLI's spec uses custom_event_filter in YAML and translates to customEventFilter on the wire.
  • GA4 has two tag types. gaawc is the Google Tag config (one per page, sets up the gtag context). gaawe is an individual event tag (one per event you fire). You typically need exactly one gaawc plus one gaawe per event. Do not put GA4 measurement ID directly on every gaawe — reference the constant variable that the gaawc already uses.
  • Updating existing resources requires --allow-update. Without it, apply raises on the first 409 conflict and stops. Pass --allow-update only when you intend to modify resources that already exist by name.
  • Variable references inside parameter values use {{Variable Name}} template syntax. These are strings, resolved at runtime in the browser, not API IDs. The planner does not validate them. The applier emits a warning (not an error) if a referenced name is not present in the workspace — read the warning and fix the spec.

9. Failure handling

When a command fails:

  1. Read the log. Tail ./gtm-agent.log to see the full request, response, and stack trace:
    cat gtm-agent.log | tail -50
  2. Surface the API error verbatim. Show the user the actual googleapiclient.errors.HttpError reason — userRateLimitExceeded, dailyLimitExceeded, permissionDenied, etc. Do not paraphrase.
  3. Do not auto-retry destructive operations. If apply fails partway through, do not re-run it without re-running plan first to see the new state. The workspace is now in a partially-updated state and the spec might no longer match what you expect.
  4. Do not retry dailyLimitExceeded. That error means the project has hit its 10K/day GTM API quota. It resets at midnight Pacific. Tell the user, do not retry.
  5. For OAuth errors, suggest gtm-agent auth --revoke followed by gtm-agent auth. Stale or revoked tokens are the most common cause of 401 unauthenticated.