@veleads/gtm 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +72 -0
- package/dist/cli.js +146 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to `@veleads/gtm`. Each entry is tagged: **no action**, **op
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.2.1] - 2026-10-24
|
|
9
|
+
- **no action** The npm package now has a README (what it is, quick start, commands, guidance for
|
|
10
|
+
coding agents).
|
|
11
|
+
- **no action** `gtm <command> --help` and `gtm help <command>` print that command's usage, what it
|
|
12
|
+
writes, and examples, without running it. Previously `--help` after a command ran the command.
|
|
13
|
+
|
|
8
14
|
## [0.2.0] - 2026-10-24
|
|
9
15
|
- **action** ICP approvals are now pinned to the approved content. New `gtm approve icp --by "<name>"`
|
|
10
16
|
records the sign-off with a `content_hash`; `gtm validate` fails if `context/icp.yaml` changes after
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @veleads/gtm
|
|
2
|
+
|
|
3
|
+
CLI and process kit for **gtm-brain**: run outbound for many clients with one standard,
|
|
4
|
+
agent-agnostic process. Each client gets its own **private** git repo; this package scaffolds it,
|
|
5
|
+
keeps its playbooks in sync with the core, validates it, and upgrades it safely.
|
|
6
|
+
|
|
7
|
+
Works with Claude Code, Codex, or any coding agent that can read files and run shell commands.
|
|
8
|
+
Source: [Veleads/gtm-core](https://github.com/Veleads/gtm-core) · MIT
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
Requires Node.js 22+ and pnpm (`corepack enable`, or use `npx pnpm@10`).
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @veleads/gtm init acme --name "Acme Corp"
|
|
16
|
+
cd gtm-client-acme
|
|
17
|
+
pnpm install
|
|
18
|
+
pnpm gtm status
|
|
19
|
+
pnpm gtm validate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Push the new folder to a **private** repository, then open it in your coding agent. The generated
|
|
23
|
+
`AGENTS.md` tells the agent how to work in the repo, starting at stage `00-intake`.
|
|
24
|
+
|
|
25
|
+
## What you get in a client repo
|
|
26
|
+
|
|
27
|
+
| Path | What | Edit? |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `AGENTS.md` | operator manual: session start, 9-stage routing, hard stops, data rules | no, generated by `gtm sync` |
|
|
30
|
+
| `.gtm/` | stage playbooks (Agent Skills), templates, JSON schemas, provider docs | no, generated by `gtm sync` |
|
|
31
|
+
| `CLIENT.md` | client-specific rules that add to the process | yes |
|
|
32
|
+
| `client.yaml`, `context/` | owners, ICP (md + yaml), signals, personas, offer, proof, voice | yes |
|
|
33
|
+
| `campaigns/<id>/` | brief, config, copy, QA report, run logs | yes |
|
|
34
|
+
|
|
35
|
+
Stages: intake → ICP (**client sign-off**) → TAM → enrich → qualify → copy (**client sign-off**) →
|
|
36
|
+
QA → launch (**go/no-go**) → results. ICP and copy approvals are pinned to the approved content:
|
|
37
|
+
editing either afterwards makes `gtm validate` fail until it's re-approved.
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
Run inside a client repo as `pnpm gtm <command>`. `gtm <command> --help` shows usage, **what the
|
|
42
|
+
command writes**, and examples, without running it.
|
|
43
|
+
|
|
44
|
+
| Command | What it does | Writes |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `init <slug> --name "<Name>"` | scaffold a new client repo | new folder |
|
|
47
|
+
| `new-campaign <slug>` | scaffold `campaigns/<slug>/` | that folder |
|
|
48
|
+
| `validate [campaign]` | schemas, gates, cross-references, no lead data, core sync | nothing |
|
|
49
|
+
| `status` | campaigns, stages, gates | nothing |
|
|
50
|
+
| `approve icp --by "<name>"` | record ICP sign-off, pin its hash | `context/icp.yaml` |
|
|
51
|
+
| `approve copy <campaign> --by "<name>"` | record copy sign-off, pin its hash | campaign `config.yaml` |
|
|
52
|
+
| `sync [--check]` | copy the core kit into `.gtm/` + `AGENTS.md` | `.gtm/`, `AGENTS.md` (nothing with `--check`) |
|
|
53
|
+
| `migrate [--dry-run]` | move YAML files to the current schema versions | YAML files |
|
|
54
|
+
| `upgrade [version]` | install a newer core, sync, migrate, validate, show changelog | deps, `.gtm/`, YAML |
|
|
55
|
+
| `job <name> <campaign>` | pipeline jobs (TAM, enrich, …) | planned, not available yet |
|
|
56
|
+
|
|
57
|
+
Exit codes: `0` success, `1` failure or validation errors.
|
|
58
|
+
|
|
59
|
+
## For coding agents
|
|
60
|
+
|
|
61
|
+
- Inside a client repo, **read `AGENTS.md` first** and follow it; then `CLIENT.md`.
|
|
62
|
+
- Read-only commands are always safe: `validate`, `status`, `sync --check`, `migrate --dry-run`,
|
|
63
|
+
and any `--help`.
|
|
64
|
+
- Never edit `AGENTS.md` or `.gtm/`. Never run `gtm approve` unless a named human explicitly approved
|
|
65
|
+
in the session.
|
|
66
|
+
- `gtm job` is not available yet: stop and tell the human rather than improvising with scripts.
|
|
67
|
+
|
|
68
|
+
## Upgrades
|
|
69
|
+
|
|
70
|
+
Client repos pin an exact version. New releases arrive as a pull request from the repo's weekly
|
|
71
|
+
`gtm-upgrade` workflow, or via `pnpm gtm upgrade`. Breaking YAML changes ship with automatic
|
|
72
|
+
migrations; see [CHANGELOG.md](https://github.com/Veleads/gtm-core/blob/main/CHANGELOG.md).
|
package/dist/cli.js
CHANGED
|
@@ -939,21 +939,134 @@ ${notes || "(no changelog entries)"}
|
|
|
939
939
|
return valid;
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
+
// src/help.ts
|
|
943
|
+
var COMMANDS = {
|
|
944
|
+
init: {
|
|
945
|
+
usage: 'gtm init <client-slug> --name "<Client Name>" [--dir <path>]',
|
|
946
|
+
summary: "scaffold a new client repo",
|
|
947
|
+
details: [
|
|
948
|
+
"Creates a complete client repo: client.yaml, context/ templates, campaigns/, tam/, CLIENT.md,",
|
|
949
|
+
"CI workflows, .gtm/ (core kit) and AGENTS.md, pinned to this CLI's version, then runs git init.",
|
|
950
|
+
"Push the result to a PRIVATE repo: it will hold client context."
|
|
951
|
+
],
|
|
952
|
+
writes: "A new folder (default ./gtm-client-<slug>). Refuses if it exists and is not empty.",
|
|
953
|
+
examples: ['npx @veleads/gtm init acme --name "Acme Corp"', 'npx @veleads/gtm init acme --name "Acme Corp" --dir ./clients/acme']
|
|
954
|
+
},
|
|
955
|
+
"new-campaign": {
|
|
956
|
+
usage: "gtm new-campaign <campaign-slug>",
|
|
957
|
+
summary: "scaffold campaigns/<slug>/",
|
|
958
|
+
details: ["Copies the campaign template (brief.md, config.yaml, copy.md, runs/). Owner comes from GTM_USER."],
|
|
959
|
+
writes: "campaigns/<slug>/ (refuses if it exists).",
|
|
960
|
+
examples: ["git switch -c campaign/q1-uk-cfo && pnpm gtm new-campaign q1-uk-cfo"]
|
|
961
|
+
},
|
|
962
|
+
validate: {
|
|
963
|
+
usage: "gtm validate [campaign]",
|
|
964
|
+
summary: "check repo against schemas, gates, data rules",
|
|
965
|
+
details: [
|
|
966
|
+
"Checks client.yaml, context/ and campaigns against the schemas; segment/persona/signal references;",
|
|
967
|
+
"gate order (no stage past an unapproved or changed ICP/copy approval); required files; run-log names;",
|
|
968
|
+
"no lead data (blocks data files, warns on email addresses); .gtm/ matches the installed core.",
|
|
969
|
+
"Exit code 1 if there is any error; warnings never fail."
|
|
970
|
+
],
|
|
971
|
+
writes: "Nothing (read-only).",
|
|
972
|
+
examples: ["pnpm gtm validate", "pnpm gtm validate q1-uk-cfo"]
|
|
973
|
+
},
|
|
974
|
+
status: {
|
|
975
|
+
usage: "gtm status",
|
|
976
|
+
summary: "campaigns, stages, gates",
|
|
977
|
+
details: ["One screen: client, core version, ICP gate, and per campaign the stage, copy/launch gates, owner and latest run log."],
|
|
978
|
+
writes: "Nothing (read-only).",
|
|
979
|
+
examples: ["pnpm gtm status"]
|
|
980
|
+
},
|
|
981
|
+
approve: {
|
|
982
|
+
usage: 'gtm approve icp --by "<Name (side)>" [--notes ".."] [--date YYYY-MM-DD]\ngtm approve copy <campaign> --by "<Name (side)>" [--notes ".."] [--date YYYY-MM-DD]',
|
|
983
|
+
summary: "record a sign-off and pin a hash of the approved content",
|
|
984
|
+
details: [
|
|
985
|
+
"Run ONLY after the named human explicitly approved in this session (AGENTS.md section 4).",
|
|
986
|
+
"Pins a content hash: if context/icp.yaml or the campaign's copy.md changes afterwards,",
|
|
987
|
+
"`gtm validate` fails until it is re-approved. Refuses if the file would not validate.",
|
|
988
|
+
"The launch gate is recorded by hand in config.yaml (its content is the lead set)."
|
|
989
|
+
],
|
|
990
|
+
writes: "context/icp.yaml \u2192 approval (icp), or campaigns/<campaign>/config.yaml \u2192 gates.copy (copy).",
|
|
991
|
+
examples: ['pnpm gtm approve icp --by "Maria Chen (client)" --notes "Segments A+B, personas CFO+AP"', 'pnpm gtm approve copy q1-uk-cfo --by "Maria Chen (client)"']
|
|
992
|
+
},
|
|
993
|
+
sync: {
|
|
994
|
+
usage: "gtm sync [--check]",
|
|
995
|
+
summary: "copy core kit into .gtm/ + AGENTS.md",
|
|
996
|
+
details: [
|
|
997
|
+
"Makes .gtm/ (skills, templates, schemas, provider docs) and AGENTS.md match the installed core.",
|
|
998
|
+
"--check only compares and exits 1 if they differ (CI uses this; never edit .gtm/ by hand)."
|
|
999
|
+
],
|
|
1000
|
+
writes: ".gtm/ (replaced entirely) and AGENTS.md; creates CLAUDE.md if missing. With --check: nothing.",
|
|
1001
|
+
examples: ["pnpm gtm sync", "pnpm gtm sync --check"]
|
|
1002
|
+
},
|
|
1003
|
+
migrate: {
|
|
1004
|
+
usage: "gtm migrate [--dry-run]",
|
|
1005
|
+
summary: "upgrade YAML files to current schema versions",
|
|
1006
|
+
details: ["Applies core schema migrations to client.yaml, context/*.yaml and campaigns/*/config.yaml, keeping comments."],
|
|
1007
|
+
writes: "Those YAML files, only if a migration applies. With --dry-run: nothing.",
|
|
1008
|
+
examples: ["pnpm gtm migrate --dry-run", "pnpm gtm migrate"]
|
|
1009
|
+
},
|
|
1010
|
+
upgrade: {
|
|
1011
|
+
usage: "gtm upgrade [version] [--force]",
|
|
1012
|
+
summary: "install newer core, sync, migrate, validate",
|
|
1013
|
+
details: [
|
|
1014
|
+
"Installs @veleads/gtm@<version|latest> pinned exactly, then sync, migrate and validate, and prints the changelog.",
|
|
1015
|
+
"Refuses while a campaign is in qa or launch, or with uncommitted changes (--force overrides; ask a GTM engineer)."
|
|
1016
|
+
],
|
|
1017
|
+
writes: "package.json, lockfile, node_modules, .gtm/, AGENTS.md and migrated YAML files.",
|
|
1018
|
+
examples: ["pnpm gtm upgrade", "pnpm gtm upgrade 0.3.0"]
|
|
1019
|
+
},
|
|
1020
|
+
job: {
|
|
1021
|
+
usage: "gtm job <name> <campaign>",
|
|
1022
|
+
summary: "run a pipeline job (Phase 2)",
|
|
1023
|
+
details: [
|
|
1024
|
+
"Planned: tam, enrich, suppression:import, signals, qualify, qa, push, activate, results, status.",
|
|
1025
|
+
"Not available yet: it exits 1. Per AGENTS.md this is a stop; do not improvise jobs with ad-hoc scripts."
|
|
1026
|
+
],
|
|
1027
|
+
writes: "Nothing yet.",
|
|
1028
|
+
examples: ["pnpm gtm job tam q1-uk-cfo"]
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
function generalHelp(version) {
|
|
1032
|
+
const width = Math.max(...Object.keys(COMMANDS).map((c) => c.length));
|
|
1033
|
+
const lines = Object.entries(COMMANDS).map(([name, c]) => ` ${name.padEnd(width)} ${c.summary}`);
|
|
1034
|
+
return `gtm v${version}: CLI for gtm-brain client repos (@veleads/gtm)
|
|
1035
|
+
|
|
1036
|
+
Usage: gtm <command> [options] (inside a client repo: pnpm gtm <command>)
|
|
1037
|
+
|
|
1038
|
+
Commands:
|
|
1039
|
+
${lines.join("\n")}
|
|
1040
|
+
|
|
1041
|
+
Run \`gtm <command> --help\` for usage, what it writes, and examples.
|
|
1042
|
+
|
|
1043
|
+
Global options:
|
|
1044
|
+
--root <dir> repo root (default: current directory)
|
|
1045
|
+
-h, --help show help (with a command: that command's help; nothing is run)
|
|
1046
|
+
-v, --version print the version
|
|
1047
|
+
|
|
1048
|
+
Exit codes: 0 success, 1 failure or validation errors.
|
|
1049
|
+
|
|
1050
|
+
For coding agents: inside a client repo, read AGENTS.md first and follow it. Read-only commands
|
|
1051
|
+
(validate, status, sync --check, migrate --dry-run) are always safe to run.`;
|
|
1052
|
+
}
|
|
1053
|
+
function commandHelp(name) {
|
|
1054
|
+
const c = COMMANDS[name];
|
|
1055
|
+
if (!c) return null;
|
|
1056
|
+
return `gtm ${name}: ${c.summary}
|
|
1057
|
+
|
|
1058
|
+
Usage:
|
|
1059
|
+
${c.usage.split("\n").map((u) => ` ${u}`).join("\n")}
|
|
1060
|
+
|
|
1061
|
+
${c.details.map((d) => ` ${d}`).join("\n")}
|
|
1062
|
+
|
|
1063
|
+
Writes: ${c.writes}
|
|
1064
|
+
|
|
1065
|
+
Examples:
|
|
1066
|
+
${c.examples.map((e) => ` ${e}`).join("\n")}`;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
942
1069
|
// src/cli.ts
|
|
943
|
-
var HELP = `gtm v${GTM_VERSION}: gtm-brain core CLI (run inside a client repo)
|
|
944
|
-
|
|
945
|
-
gtm init <client-slug> --name "<Name>" [--dir <path>] scaffold a new client repo
|
|
946
|
-
gtm new-campaign <campaign-slug> scaffold campaigns/<slug>/
|
|
947
|
-
gtm validate [campaign] check repo against schemas, gates, data rules
|
|
948
|
-
gtm status campaigns, stages, gates
|
|
949
|
-
gtm approve icp --by "<Name (side)>" [--notes ..] [--date YYYY-MM-DD]
|
|
950
|
-
gtm approve copy <campaign> --by "<Name (side)>" [..] record a sign-off and pin a hash of the approved content
|
|
951
|
-
gtm sync [--check] copy core kit into .gtm/ + AGENTS.md
|
|
952
|
-
gtm migrate [--dry-run] upgrade YAML files to current schema versions
|
|
953
|
-
gtm upgrade [version] [--force] install newer core, sync, migrate, validate
|
|
954
|
-
gtm job <name> <campaign> run a pipeline job (Phase 2)
|
|
955
|
-
|
|
956
|
-
Global: --root <dir> repo root (default: current directory)`;
|
|
957
1070
|
var { values, positionals } = parseArgs({
|
|
958
1071
|
allowPositionals: true,
|
|
959
1072
|
options: {
|
|
@@ -973,11 +1086,27 @@ var { values, positionals } = parseArgs({
|
|
|
973
1086
|
var [command, ...args] = positionals;
|
|
974
1087
|
var cwd = process.cwd();
|
|
975
1088
|
var root = resolve2(cwd, values.root ?? ".");
|
|
1089
|
+
function help(name) {
|
|
1090
|
+
if (!name) {
|
|
1091
|
+
console.log(generalHelp(GTM_VERSION));
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
const text = commandHelp(name);
|
|
1095
|
+
if (!text) {
|
|
1096
|
+
console.error(`Unknown command "${name}"
|
|
1097
|
+
|
|
1098
|
+
${generalHelp(GTM_VERSION)}`);
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
console.log(text);
|
|
1102
|
+
return true;
|
|
1103
|
+
}
|
|
976
1104
|
function run() {
|
|
977
1105
|
if (values.version) {
|
|
978
1106
|
console.log(GTM_VERSION);
|
|
979
1107
|
return true;
|
|
980
1108
|
}
|
|
1109
|
+
if (values.help) return help(command === "help" ? args[0] : command);
|
|
981
1110
|
switch (command) {
|
|
982
1111
|
case "init":
|
|
983
1112
|
return runInit(args[0], { name: values.name, dir: values.dir, cwd });
|
|
@@ -998,13 +1127,13 @@ function run() {
|
|
|
998
1127
|
case "job":
|
|
999
1128
|
return runJob(args[0]);
|
|
1000
1129
|
case void 0:
|
|
1130
|
+
return help(void 0);
|
|
1001
1131
|
case "help":
|
|
1002
|
-
|
|
1003
|
-
return true;
|
|
1132
|
+
return help(args[0]);
|
|
1004
1133
|
default:
|
|
1005
1134
|
console.error(`Unknown command "${command}"
|
|
1006
1135
|
|
|
1007
|
-
${
|
|
1136
|
+
${generalHelp(GTM_VERSION)}`);
|
|
1008
1137
|
return false;
|
|
1009
1138
|
}
|
|
1010
1139
|
}
|