gtm-agent is an agent-safe Google Tag Manager control-plane CLI built on top of the maintained @owntag/gtm-cli wheel and Google Tag Manager API v2.
It does not try to replace the upstream GTM CLI. It adds the missing operational layer agents need before changing marketing infrastructure: doctor checks, snapshots, stable diffs, declarative plans, dry-run-first execution, publish gates, backups, raw passthrough, and an included agent skill.
Build locally:
go build -o ./gtm-agent ./cmd/gtm-agentInstall the upstream GTM wheel:
./gtm-agent install
./gtm-agent install --executeOr install directly:
npm install -g @owntag/gtm-cli@1.5.8Authenticate with the upstream wheel:
gtm auth loginFor automation, prefer a service account:
gtm auth login --service-account /path/to/service-account-key.jsonGrant the service account access inside Google Tag Manager before using it.
gtm-agent doctor --json
gtm-agent --version
gtm-agent inventory --account-id 123 --container-id 456 --workspace-id 7 --json
gtm-agent snapshot --account-id 123 --container-id 456 --workspace-id 7 --out snapshots/before.json
gtm-agent diff snapshots/before.json snapshots/after.json --json
gtm-agent plan template --out plan.yaml --json
gtm-agent plan validate plan.yaml --json
gtm-agent apply plan.yaml --json
gtm-agent apply plan.yaml --execute --json
gtm-agent backup --account-id 123 --container-id 456 --out backups/live.json --json
gtm-agent raw -- tags list --account-id 123 --container-id 456 --workspace-id 7 --output json
gtm-agent guideapplyis dry-run by default.- No plan mutation executes unless
--executeis present. - Publishing requires both
--allow-publishand--confirm <container-id>. raw -- ...is intentionally available for full upstream coverage, but it is clearly labeled as passthrough.- Mutating
raw -- ...commands require--allow-mutation; raw publish also requires--allow-publish --confirm <container-id>. - Snapshots, backups, service-account JSON, tokens, and env files are ignored by default.
- Snapshot/backup outputs inside the repo must live under
snapshots/orbackups/, or use.snapshot.json/.backup.jsonsuffixes unless--allow-unsafe-outis present. - Unit and E2E tests use a fake upstream
gtmbinary and never touch a real GTM account.
accountId: "123"
containerId: "456"
workspaceId: "7"
actions:
- kind: enableBuiltInVariables
types: ["pageUrl", "clickText"]
- kind: createTrigger
name: "All Pages"
type: "pageview"
- kind: createTag
name: "GA4 purchase"
type: "gaawe"
config:
parameter:
- type: template
key: eventName
value: purchase
- kind: createVersion
name: "agent release"
notes: "Created by gtm-agent"Publish action:
accountId: "123"
containerId: "456"
workspaceId: "7"
actions:
- kind: publishVersion
versionId: "42"Run it only with both gates:
gtm-agent apply publish.yaml --execute --allow-publish --confirm 456 --jsonThe repo includes skills/gtm-agent/SKILL.md. For Codex/Gemini/Claude-style local skill trees, symlink it with:
./scripts/link-skill.shThe script creates or refreshes symlinks in:
~/.agents/skills/gtm-agent~/.codex/skills/gtm-agent~/.gemini/antigravity/skills/gtm-agent~/.claude/skills/gtm-agent
go mod verify
go test ./...
go vet ./...
go build -o ./gtm-agent ./cmd/gtm-agent
./scripts/e2e-fake-gtm.shOptional:
govulncheck ./...Keep gtm-agent as the safety/control-plane layer. Contribute focused upstream improvements to owntag/gtm-cli when they belong to the raw GTM command surface, such as JSON consistency, additional resource coverage, command help, or broadly useful agent guide improvements.
Powered by:
This project is unofficial and is not affiliated with, endorsed by, or supported by Google.
MIT.