@friedbotstudio/create-baseline 0.6.0 → 0.8.0
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/README.md +14 -10
- package/bin/cli.js +19 -13
- package/obj/template/.claude/commands/init-project-doctor.md +74 -0
- package/obj/template/.claude/hooks/lib/resume_writer.py +14 -1
- package/obj/template/.claude/hooks/memory_session_start.sh +24 -0
- package/obj/template/.claude/hooks/track_guard.sh +11 -1
- package/obj/template/.claude/manifest.json +31 -99
- package/obj/template/.claude/schemas/workflow-track.v1.json +64 -0
- package/obj/template/.claude/skills/audit-baseline/audit.sh +2 -2
- package/obj/template/.claude/skills/chore/SKILL.md +2 -2
- package/obj/template/.claude/skills/harness/SKILL.md +15 -6
- package/obj/template/.claude/skills/intake/SKILL.md +1 -1
- package/obj/template/.claude/skills/swarm-plan/SKILL.md +2 -0
- package/obj/template/.claude/skills/tdd/SKILL.md +2 -2
- package/obj/template/.claude/skills/triage/SKILL.md +29 -6
- package/obj/template/.claude/skills/triage/seed-tasklist.mjs +107 -0
- package/obj/template/.claude/skills/upgrade-project/SKILL.md +18 -7
- package/obj/template/.claude/workflows.jsonl +6 -0
- package/obj/template/CLAUDE.md +8 -14
- package/obj/template/docs/init/seed.md +148 -3
- package/package.json +1 -1
- package/src/.claude/workflows.template.jsonl +6 -0
- package/src/CLAUDE.template.md +8 -14
- package/src/cli/install.js +5 -1
- package/src/cli/merge.js +42 -5
- package/src/cli/track-tasklist-materializer.js +223 -0
- package/src/cli/tui/upgrade.js +30 -41
- package/src/cli/upgrade-tiers.js +42 -4
- package/src/cli/workflow-migrator.js +40 -0
- package/src/cli/workflows-validator-invariants.js +417 -0
- package/src/cli/workflows-validator-predicates.js +19 -0
- package/src/cli/workflows-validator.js +156 -0
- package/src/seed.template.md +148 -3
- package/obj/template/.claude/skills/google-analytics/SKILL.md +0 -129
- package/obj/template/.claude/skills/google-analytics/references/audiences.md +0 -389
- package/obj/template/.claude/skills/google-analytics/references/bigquery.md +0 -470
- package/obj/template/.claude/skills/google-analytics/references/custom-dimensions.md +0 -355
- package/obj/template/.claude/skills/google-analytics/references/custom-events.md +0 -383
- package/obj/template/.claude/skills/google-analytics/references/data-management.md +0 -416
- package/obj/template/.claude/skills/google-analytics/references/debugview.md +0 -364
- package/obj/template/.claude/skills/google-analytics/references/events-fundamentals.md +0 -398
- package/obj/template/.claude/skills/google-analytics/references/gtag.md +0 -502
- package/obj/template/.claude/skills/google-analytics/references/gtm-integration.md +0 -483
- package/obj/template/.claude/skills/google-analytics/references/measurement-protocol.md +0 -519
- package/obj/template/.claude/skills/google-analytics/references/privacy.md +0 -441
- package/obj/template/.claude/skills/google-analytics/references/recommended-events.md +0 -464
- package/obj/template/.claude/skills/google-analytics/references/reporting.md +0 -397
- package/obj/template/.claude/skills/google-analytics/references/setup.md +0 -344
- package/obj/template/.claude/skills/google-analytics/references/user-tracking.md +0 -417
- package/obj/template/.claude/skills/optimize-seo/SKILL.md +0 -313
- package/obj/template/.claude/skills/optimize-seo/scripts/pagespeed.mjs +0 -197
- package/obj/template/.claude/skills/pagespeed-insights/LICENSE.md +0 -37
- package/obj/template/.claude/skills/pagespeed-insights/SKILL.md +0 -446
- package/obj/template/.claude/skills/pagespeed-insights/reference.md +0 -50
- package/src/cli/diff-render.js +0 -54
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Foundation — v1 predicate vocabulary for workflows.jsonl Track preconditions
|
|
2
|
+
// and selector-node alternate preconditions. The set is closed; unknown
|
|
3
|
+
// predicates fail Article IV invariant I11 at validate time. Adding a new
|
|
4
|
+
// predicate is a constitutional change (seed.md §18.4 + this module + the
|
|
5
|
+
// CLAUDE.md Article IV invariant list).
|
|
6
|
+
|
|
7
|
+
export const V1_PREDICATES = Object.freeze(
|
|
8
|
+
new Set([
|
|
9
|
+
'requires_git',
|
|
10
|
+
'requires_user_override',
|
|
11
|
+
'requires_min_components',
|
|
12
|
+
'requires_phase_completed',
|
|
13
|
+
'requires_skill_present',
|
|
14
|
+
])
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export function isKnownPredicate(name) {
|
|
18
|
+
return V1_PREDICATES.has(name);
|
|
19
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Orchestration — validate `.claude/workflows.jsonl` line-by-line + run
|
|
2
|
+
// Article IV invariant checks. Returns { ok: true, tracks } on success or
|
|
3
|
+
// { ok: false, errors: [...] } on any failure (parse, schema-shape, schema-
|
|
4
|
+
// version, or invariant violation). See docs/init/seed.md §18 for the
|
|
5
|
+
// full contract.
|
|
6
|
+
|
|
7
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { join, dirname, resolve } from 'node:path';
|
|
10
|
+
import { checkAllInvariants } from './workflows-validator-invariants.js';
|
|
11
|
+
|
|
12
|
+
const SUPPORTED_SCHEMAS = new Set(['./schemas/workflow-track.v1.json']);
|
|
13
|
+
|
|
14
|
+
const REQUIRED_TRACK_FIELDS = [
|
|
15
|
+
'$schema', 'track_id', 'name', 'description', 'selectable',
|
|
16
|
+
'selector_hints', 'preconditions', 'invariants', 'nodes',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const KNOWN_TRACK_FIELDS = new Set([...REQUIRED_TRACK_FIELDS]);
|
|
20
|
+
|
|
21
|
+
export async function validateWorkflowsJsonl(filePath) {
|
|
22
|
+
const projectRoot = await findProjectRoot(filePath);
|
|
23
|
+
const knownSkills = await loadKnownInvokables(projectRoot);
|
|
24
|
+
const text = await readFile(filePath, 'utf8');
|
|
25
|
+
const lines = text.split('\n');
|
|
26
|
+
|
|
27
|
+
const tracks = [];
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const raw = lines[i];
|
|
30
|
+
if (raw.trim().length === 0) continue;
|
|
31
|
+
const parsed = tryParseJson(raw, i + 1);
|
|
32
|
+
if (parsed.error) {
|
|
33
|
+
return { ok: false, errors: [parsed.error] };
|
|
34
|
+
}
|
|
35
|
+
const shapeError = checkSchemaShape(parsed.value, i + 1);
|
|
36
|
+
if (shapeError) {
|
|
37
|
+
return { ok: false, errors: [shapeError] };
|
|
38
|
+
}
|
|
39
|
+
const versionError = checkSchemaVersion(parsed.value, i + 1);
|
|
40
|
+
if (versionError) {
|
|
41
|
+
return { ok: false, errors: [versionError] };
|
|
42
|
+
}
|
|
43
|
+
tracks.push(parsed.value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const allTracksMap = new Map(tracks.map((t) => [t.track_id, t]));
|
|
47
|
+
for (const t of tracks) {
|
|
48
|
+
Object.defineProperty(t, '_allTracks', { value: allTracksMap, enumerable: false });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const invariantErrors = checkAllInvariants(tracks, { knownSkills });
|
|
52
|
+
if (invariantErrors.length > 0) {
|
|
53
|
+
return { ok: false, errors: invariantErrors };
|
|
54
|
+
}
|
|
55
|
+
return { ok: true, tracks };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function tryParseJson(raw, lineNo) {
|
|
59
|
+
try {
|
|
60
|
+
return { value: JSON.parse(raw) };
|
|
61
|
+
} catch (err) {
|
|
62
|
+
const colMatch = err.message.match(/position\s+(\d+)/);
|
|
63
|
+
return {
|
|
64
|
+
error: {
|
|
65
|
+
kind: 'parse_failure',
|
|
66
|
+
line: lineNo,
|
|
67
|
+
col: colMatch ? parseInt(colMatch[1], 10) : 0,
|
|
68
|
+
message: `Line ${lineNo}: JSON parse failed — ${err.message}`,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function checkSchemaShape(track, lineNo) {
|
|
75
|
+
if (track === null || typeof track !== 'object' || Array.isArray(track)) {
|
|
76
|
+
return {
|
|
77
|
+
kind: 'schema_shape',
|
|
78
|
+
line: lineNo,
|
|
79
|
+
message: `Line ${lineNo}: Track record must be a JSON object.`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
for (const field of REQUIRED_TRACK_FIELDS) {
|
|
83
|
+
if (!(field in track)) {
|
|
84
|
+
return {
|
|
85
|
+
kind: 'schema_shape',
|
|
86
|
+
line: lineNo,
|
|
87
|
+
track_id: track.track_id,
|
|
88
|
+
message: `Line ${lineNo}: Track record missing required field '${field}'.`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const key of Object.keys(track)) {
|
|
93
|
+
if (!KNOWN_TRACK_FIELDS.has(key)) {
|
|
94
|
+
return {
|
|
95
|
+
kind: 'schema_shape',
|
|
96
|
+
line: lineNo,
|
|
97
|
+
track_id: track.track_id,
|
|
98
|
+
message: `Line ${lineNo}: Track '${track.track_id}' has unknown field '${key}' (strict schema; v1 fields only).`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function checkSchemaVersion(track, lineNo) {
|
|
106
|
+
if (!SUPPORTED_SCHEMAS.has(track.$schema)) {
|
|
107
|
+
return {
|
|
108
|
+
kind: 'unknown_schema_version',
|
|
109
|
+
line: lineNo,
|
|
110
|
+
track_id: track.track_id,
|
|
111
|
+
message: `Line ${lineNo}: Track '${track.track_id}' references unknown $schema='${track.$schema}'. Supported versions: ${[...SUPPORTED_SCHEMAS].join(', ')}.`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function findProjectRoot(startPath) {
|
|
118
|
+
let dir = resolve(startPath);
|
|
119
|
+
try {
|
|
120
|
+
const st = await stat(dir);
|
|
121
|
+
if (!st.isDirectory()) dir = dirname(dir);
|
|
122
|
+
} catch {
|
|
123
|
+
dir = dirname(dir);
|
|
124
|
+
}
|
|
125
|
+
while (dir !== dirname(dir)) {
|
|
126
|
+
if (existsSync(join(dir, '.claude/skills'))) return dir;
|
|
127
|
+
dir = dirname(dir);
|
|
128
|
+
}
|
|
129
|
+
return dirname(startPath);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function loadKnownInvokables(projectRoot) {
|
|
133
|
+
// Skills live at .claude/skills/<slug>/SKILL.md (slug = directory name).
|
|
134
|
+
// Commands live at .claude/commands/<slug>.md (slug = filename without .md).
|
|
135
|
+
// Both surfaces are valid `skill:` references in a workflows.jsonl Track
|
|
136
|
+
// node — commands are consent gates the user types; skills are Claude-
|
|
137
|
+
// invokable. The Track schema does not distinguish; both resolve here.
|
|
138
|
+
const known = new Set();
|
|
139
|
+
const skillsDir = join(projectRoot, '.claude/skills');
|
|
140
|
+
if (existsSync(skillsDir)) {
|
|
141
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
142
|
+
for (const entry of entries) {
|
|
143
|
+
if (entry.isDirectory()) known.add(entry.name);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const commandsDir = join(projectRoot, '.claude/commands');
|
|
147
|
+
if (existsSync(commandsDir)) {
|
|
148
|
+
const entries = await readdir(commandsDir, { withFileTypes: true });
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
151
|
+
known.add(entry.name.slice(0, -3));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return known;
|
|
156
|
+
}
|
package/src/seed.template.md
CHANGED
|
@@ -247,7 +247,7 @@ Each vendored shared global ships with its own `LICENSE` + `NOTICE` alongside th
|
|
|
247
247
|
|
|
248
248
|
- `chore` — for tasks with no failing-test-driven code change (documentation, governance counts, vendored-skill content updates, configuration, formatting, typo fixes, dependency bumps, skill consolidations). Skips `/scenario` and `/implement` — there is nothing to drive with a failing test. Runs the edits directly, then conditionally invokes `simplify` / `integrate` / `document` based on what the diff touches (each has explicit triggers in the chore skill body). `verify`, `archive`, and `/grant-commit` + `/commit` always run. Chore is a stripped-down pipeline, **not** a bypass — silent skips of triggered conditional phases are forbidden; the end-of-chore summary documents every skip rationale. Tasks that need a real failing test route to `/tdd` or higher instead.
|
|
249
249
|
|
|
250
|
-
### §4.4 Commands (
|
|
250
|
+
### §4.4 Commands (6) — structurally user-only
|
|
251
251
|
|
|
252
252
|
Files at `.claude/commands/<name>.md`. Commands differ from skills in exactly one way: **Claude cannot invoke them via the Skill tool.** A command is a button only a human can press.
|
|
253
253
|
|
|
@@ -258,8 +258,9 @@ Files at `.claude/commands/<name>.md`. Commands differ from skills in exactly on
|
|
|
258
258
|
| `grant-commit` | Opens a 5-minute consent window for `git commit` on a protected branch. Writes `.claude/state/commit_consent`. Enforced by `git_commit_guard`. |
|
|
259
259
|
| `grant-push` | Opens a 5-minute consent window for `git push` on a protected branch. Writes `.claude/state/push_consent`. Enforced by `git_commit_guard`. Not a workflow-phase gate — a runtime consent for the branch-aware policy (§11). |
|
|
260
260
|
| `init-project` | One-time bootstrap. Detects stack, proposes `.claude/project.json` (test cmd, lint cmd, TDD globs, destructive patterns, artifact required sections, swarm config). Flips `configured: true`. |
|
|
261
|
+
| `init-project-doctor` | Detects baseline drift — missing/invalid `.claude/workflows.jsonl`, schema/invariant violations, four-way Article IV / §18 mirror drift, and (advisory) shipped-tooling files placed outside `.claude/`. Interactive: presents each violation via `AskUserQuestion` and applies the named fix on confirmation. |
|
|
261
262
|
|
|
262
|
-
**Adding a
|
|
263
|
+
**Adding a seventh command requires answering yes to both:** "does a human need to press this?" and "is 'user-only via frontmatter flag' too weak a guarantee?" Otherwise make it a skill.
|
|
263
264
|
|
|
264
265
|
### §4.5 MCP servers (3)
|
|
265
266
|
|
|
@@ -338,7 +339,7 @@ Phases are fixed ordering; `/triage` picks the entry and may mark phases as exce
|
|
|
338
339
|
|
|
339
340
|
## §6 — Consent model
|
|
340
341
|
|
|
341
|
-
**Four consent gates + one bootstrap
|
|
342
|
+
**Four consent gates + one bootstrap + one doctor.** All are slash commands, not skills. Commands live in `.claude/commands/`; Claude cannot invoke them via the Skill tool. The guarantee is structural (file location), not flag-based. Three of the four gates are workflow-phase gates (A: `/approve-spec`, B: `/approve-swarm`, C: `/grant-commit`); the fourth (`/grant-push`) is a Bash-time consent for the branch-aware push policy in §11. The bootstrap is `/init-project`; the doctor is `/init-project doctor` (drift detector + repairer for `.claude/workflows.jsonl` + the §18 / Article IV four-way mirror; see §18.7).
|
|
342
343
|
|
|
343
344
|
| Gate | When it fires | Unlocks |
|
|
344
345
|
|---|---|---|
|
|
@@ -598,3 +599,147 @@ The audit at `.claude/skills/audit-baseline/audit.sh` consumes `manifest.owners.
|
|
|
598
599
|
The audit also verifies constitutional citation: CLAUDE.md SHALL contain the literal string "Article XI" and a reference to the manifest, and `docs/init/seed.md` SHALL contain "§17" and a manifest reference. Missing citations trigger FAIL with `CLAUDE.md missing Article XI citation` or `seed.md missing §17 citation`.
|
|
599
600
|
|
|
600
601
|
This provenance system is intentionally minimal: the manifest tracks shipped-file hashes; the frontmatter declares per-skill ownership; the audit reconciles the two against on-disk reality. Cryptographic supply-chain attestation, signed lock files, and per-skill aggregate merkle hashes are non-goals; the per-file `manifest.files` map already covers every file in every skill directory. A future `npx @friedbotstudio/create-baseline upgrade` subcommand will consume `manifest.owners.skills` + `manifest.files` to safely re-overlay baseline-owned files while leaving user-added skills and locally-customized baseline skills untouched — that subcommand is out of scope here.
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## §18 — Workflow definitions and Article IV invariants
|
|
606
|
+
|
|
607
|
+
### 18.1 Source of truth
|
|
608
|
+
|
|
609
|
+
`.claude/workflows.jsonl` is the canonical source for every workflow this baseline can execute. The file holds one Track record per line (JSONL). It is project-owned and `NEVER_TOUCH` (declared in `src/cli/install.js:NEVER_TOUCH` and `scripts/build-manifest.mjs:NEVER_TOUCH_PATHS`); baseline upgrades preserve user customizations verbatim via `NEVER_TOUCH_PRESERVE`. The shipped baseline overlays the pristine 6-track set from `src/.claude/workflows.template.jsonl` onto fresh installs via `scripts/build-template.sh` Stage 2; existing installs are not touched. The JSON Schema document at `.claude/schemas/workflow-track.v1.json` is referenced by `Track.$schema` and is itself `NEVER_TOUCH`.
|
|
610
|
+
|
|
611
|
+
`workflows.jsonl` supersedes the hardcoded triage templates (intake-full / spec-entry / tdd-quickfix / chore). Triage reads `workflows.jsonl` at seed time, validates each Track, classifies the user's request, and materializes the chosen Track's DAG into the TaskList. The canonical four tracks shipped in the pristine template are byte-equivalent to the pre-§18 hardcoded templates per spec AC-016 (`tests/byte-equivalent-migration.test.mjs`).
|
|
612
|
+
|
|
613
|
+
### 18.2 Track schema
|
|
614
|
+
|
|
615
|
+
A **Track** record has this shape (full definition in `.claude/schemas/workflow-track.v1.json`):
|
|
616
|
+
|
|
617
|
+
```jsonc
|
|
618
|
+
{
|
|
619
|
+
"$schema": "./schemas/workflow-track.v1.json",
|
|
620
|
+
"track_id": "<unique-across-file>",
|
|
621
|
+
"name": "<short label>",
|
|
622
|
+
"description": "<paragraph; read by the LLM classifier>",
|
|
623
|
+
"selectable": true, // false = sub-track only (referenced via sub_track)
|
|
624
|
+
"selector_hints": ["<descriptive phrase>", ...],
|
|
625
|
+
"preconditions": [{"name": "<predicate>", "argument": "<opt>"}, ...],
|
|
626
|
+
"invariants": ["commits", "requires_spec", ...],
|
|
627
|
+
"nodes": [Node, ...]
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
A **Node** is either a `task` (skill invocation or sub-track expansion) or a `selector` (picks one of multiple alternates at runtime):
|
|
632
|
+
|
|
633
|
+
```jsonc
|
|
634
|
+
{
|
|
635
|
+
"id": "<unique-within-track>",
|
|
636
|
+
"type": "task" | "selector",
|
|
637
|
+
// type=task → exactly one of:
|
|
638
|
+
"skill": "<skill-or-command-name>",
|
|
639
|
+
"sub_track": "<another-track_id>",
|
|
640
|
+
// type=selector → required:
|
|
641
|
+
"alternates": [Alternate, ...],
|
|
642
|
+
// shared:
|
|
643
|
+
"input": "<opt; passed to the skill at invocation>",
|
|
644
|
+
"invocation_prompt": "<opt; declared-now/used-later — v2 Handlebars+LLM>",
|
|
645
|
+
"output": "<opt; informational artifact path>",
|
|
646
|
+
"output_formatter_prompt": "<opt; declared-now/used-later>",
|
|
647
|
+
"depends_on": ["<predecessor node id>", ...],
|
|
648
|
+
"blocks": ["<successor node id>", ...],
|
|
649
|
+
"can_parallel": false, // true: peers at same dep level dispatch concurrently
|
|
650
|
+
"needs_user": false, // true: consent gate; harness yields
|
|
651
|
+
"activeForm": "<TaskList spinner text>",
|
|
652
|
+
"metadata": {"phase": "<...>"}
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
An **Alternate** (inside a selector node):
|
|
657
|
+
|
|
658
|
+
```jsonc
|
|
659
|
+
{
|
|
660
|
+
"skill": "<skill-name>", // XOR with sub_track
|
|
661
|
+
"sub_track": "<track_id>", // XOR with skill
|
|
662
|
+
"preconditions": [Predicate, ...],
|
|
663
|
+
"description": "<rationale>"
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
A **Predicate** (track-level and alternate-level):
|
|
668
|
+
|
|
669
|
+
```jsonc
|
|
670
|
+
{
|
|
671
|
+
"name": "<v1-vocabulary>",
|
|
672
|
+
"argument": "<opt; e.g., '3' for min_components>"
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### 18.3 Article IV invariants (I1..I11)
|
|
677
|
+
|
|
678
|
+
Every Track in `workflows.jsonl` SHALL satisfy these invariants. Validation runs at three points: install/upgrade time (audit-baseline), triage time (LLM-driven selector), and harness time (per-node before dispatch).
|
|
679
|
+
|
|
680
|
+
- **I1.** Unique `track_id` across the file.
|
|
681
|
+
- **I2.** Unique `node.id` within a track.
|
|
682
|
+
- **I3.** `type=task` nodes carry exactly one of `{skill, sub_track}`. `type=selector` nodes carry non-empty `alternates[]`.
|
|
683
|
+
- **I4.** Every `depends_on` and `blocks` reference resolves to a `node.id` in the same track.
|
|
684
|
+
- **I5.** The dependency DAG is acyclic.
|
|
685
|
+
- **I6.** Tracks declaring the `commits` invariant SHALL include a `needs_user: true` `grant-commit` node ordered before the node with `skill: "commit"`.
|
|
686
|
+
- **I7.** Every `sub_track` reference resolves to a Track with `selectable: false`.
|
|
687
|
+
- **I8.** Every `skill:` reference resolves to a known invokable — skill in `EXPECTED_SKILLS ∪ project.json additions.skills`, OR consent-gate command in `.claude/commands/` (e.g., `approve-spec`, `grant-commit`, `approve-swarm`).
|
|
688
|
+
- **I9.** `needs_user: true` nodes appear in dependency order before any node that depends on their consent.
|
|
689
|
+
- **I10.** A selector node's alternates SHALL share the same shape (all skill, or all sub_track) — they're interchangeable in the DAG.
|
|
690
|
+
- **I11.** Every `Predicate.name` resolves to a known v1 predicate (see §18.4).
|
|
691
|
+
|
|
692
|
+
### 18.4 Predicate vocabulary (v1)
|
|
693
|
+
|
|
694
|
+
The closed set of declarative predicates that may appear in Track or Alternate `preconditions[]`:
|
|
695
|
+
|
|
696
|
+
| Predicate | Argument | Evaluates true when |
|
|
697
|
+
|---|---|---|
|
|
698
|
+
| `requires_git` | — | `git rev-parse --is-inside-work-tree` exits 0 at the project root. |
|
|
699
|
+
| `requires_user_override` | `<value>` | The user explicitly named this alternate in conversation (e.g., "use solo"). |
|
|
700
|
+
| `requires_min_components` | `<int>` | The approved spec has at least N C4 Components. |
|
|
701
|
+
| `requires_phase_completed` | `<phase>` | The named phase appears in `workflow.json → completed`. |
|
|
702
|
+
| `requires_skill_present` | `<skill_id>` | The named skill exists in `EXPECTED_SKILLS ∪ additions.skills`. |
|
|
703
|
+
|
|
704
|
+
Adding a new predicate is a constitutional change: update this section, update `src/cli/workflows-validator-predicates.js`, and update the corresponding seed.template.md mirror.
|
|
705
|
+
|
|
706
|
+
### 18.5 `invocation_prompt` / `output_formatter_prompt` — declared, deferred
|
|
707
|
+
|
|
708
|
+
Both fields are part of the v1 Node schema and validated at parse time. They are **not actuated in v1** — the harness ignores them. They are declared now to lock the schema shape so future Track records can carry them without a schema bump. The v2 actuation plan: Handlebars-style templates with LLM interpolation, allowing per-track UX customization of the invocation phrasing and the post-skill output formatting. Until v2 ships, populating these fields is allowed but inert.
|
|
709
|
+
|
|
710
|
+
### 18.6 Migration from pre-§18 workflow.json
|
|
711
|
+
|
|
712
|
+
An in-flight `.claude/state/workflow.json` written by a pre-§18 baseline (carries `entry_phase` field, no `track_id`) is one-shot-migrated by the harness preflight before the workflow loads. The canonical map:
|
|
713
|
+
|
|
714
|
+
| `entry_phase` (pre-§18) | `track_id` (post-§18) |
|
|
715
|
+
|---|---|
|
|
716
|
+
| `intake` | `intake-full` |
|
|
717
|
+
| `spec` | `spec-entry` |
|
|
718
|
+
| `tdd` | `tdd-quickfix` |
|
|
719
|
+
| `chore` | `chore` |
|
|
720
|
+
|
|
721
|
+
`completed[]` is remapped from phase names to node ids; the canonical tracks are designed so most phase names equal the corresponding node id (identity remap), with the exception of selector wrappers (e.g., `implementation` in intake-full wraps the swarm-vs-tdd selection). The migrator initializes `skipped_alternates: []` and refreshes `updated_at`. Idempotent: re-running on an already-migrated workflow.json is a no-op. Unmapped `entry_phase` halts with a named error; the user restarts via `/triage`.
|
|
722
|
+
|
|
723
|
+
Migrator implementation: `src/cli/workflow-migrator.js` exports `migrateWorkflowJsonInPlace(filePath)`.
|
|
724
|
+
|
|
725
|
+
### 18.7 Lifecycle: install, upgrade, doctor
|
|
726
|
+
|
|
727
|
+
- **Fresh install.** `scripts/build-template.sh` overlays `src/.claude/workflows.template.jsonl` → `obj/template/.claude/workflows.jsonl` at Stage 2, and the pristine schemas/ directory bulk-rsyncs at Stage 1. The CLI install copies both into the consumer target. Result: every fresh install has `<target>/.claude/workflows.jsonl` with the canonical 4 selectable + 2 sub-track set.
|
|
728
|
+
|
|
729
|
+
- **Upgrade.** Both `.claude/workflows.jsonl` and `.claude/schemas/workflow-track.v1.json` are `NEVER_TOUCH`. The merge flow returns `NEVER_TOUCH_PRESERVE` for them on every upgrade; user customizations (added tracks, modified nodes, per-project additions like `cli-copy-review`) survive verbatim.
|
|
730
|
+
|
|
731
|
+
- **Doctor.** `/init-project doctor` (new sub-command) detects drift: missing `workflows.jsonl`, schema/invariant violations, four-way mirror drift between seed.md §18 / src/seed.template.md §18 / CLAUDE.md Article IV / src/CLAUDE.template.md Article IV, and (advisory) shipped-tooling files placed outside `.claude/` per the convention codified at §3.
|
|
732
|
+
|
|
733
|
+
### 18.8 Cross-references
|
|
734
|
+
|
|
735
|
+
- `CLAUDE.md Article IV` — phase-ordering rules; binding on every commit-producing track.
|
|
736
|
+
- `CLAUDE.md Article VII` — git rules; relevant to the `requires_git` precondition.
|
|
737
|
+
- `seed.md §3` — directory structure convention (tooling lives under `.claude/`).
|
|
738
|
+
- `seed.md §17` — skill provenance (separate concern; workflows.jsonl is project-owned, not baseline-owned).
|
|
739
|
+
- `.claude/workflows.jsonl` — this project's live tracks.
|
|
740
|
+
- `.claude/schemas/workflow-track.v1.json` — JSON Schema referenced by `Track.$schema`.
|
|
741
|
+
- `src/cli/workflows-validator.js` — validator orchestration.
|
|
742
|
+
- `src/cli/workflows-validator-invariants.js` — invariant checks I1–I11.
|
|
743
|
+
- `src/cli/workflows-validator-predicates.js` — predicate vocabulary.
|
|
744
|
+
- `src/cli/workflow-migrator.js` — pre-§18 → post-§18 migrator.
|
|
745
|
+
- `src/cli/track-tasklist-materializer.js` — Track → TaskList shape.
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: google-analytics
|
|
3
|
-
description: Comprehensive Google Analytics 4 guide covering property setup, events, custom events, recommended events, custom dimensions, user tracking, audiences, reporting, BigQuery integration, gtag.js implementation, GTM integration, Measurement Protocol, DebugView, privacy compliance, and data management. Use when working with GA4 implementation, tracking, analysis, or any GA4-related tasks.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Google Analytics 4 Complete Guide
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
Google Analytics 4 (GA4) is Google's event-based analytics platform for measuring user interactions across websites and applications. Every user interaction is tracked as an event with associated parameters, providing flexible cross-platform measurement.
|
|
11
|
-
|
|
12
|
-
## When to Use This Skill
|
|
13
|
-
|
|
14
|
-
Invoke this skill for any GA4-related task:
|
|
15
|
-
|
|
16
|
-
- Setting up GA4 properties, data streams, and Measurement IDs
|
|
17
|
-
- Installing GA4 via gtag.js, GTM, or CMS plugins
|
|
18
|
-
- Implementing event tracking (automatic, recommended, custom, ecommerce)
|
|
19
|
-
- Creating custom dimensions, audiences, and reports
|
|
20
|
-
- Exporting data to BigQuery for SQL analysis
|
|
21
|
-
- Server-side tracking via Measurement Protocol
|
|
22
|
-
- User ID and cross-device tracking
|
|
23
|
-
- Privacy compliance, Consent Mode, and GDPR/CCPA
|
|
24
|
-
- Testing and debugging with DebugView
|
|
25
|
-
|
|
26
|
-
## Quick Start
|
|
27
|
-
|
|
28
|
-
1. **Create property:** analytics.google.com -> Admin -> Create -> Property
|
|
29
|
-
2. **Create data stream:** Add web stream, note Measurement ID (G-XXXXXXXXXX)
|
|
30
|
-
3. **Install tracking** (choose one):
|
|
31
|
-
- **GTM (recommended):** Install container, create Google Tag with Measurement ID, trigger on All Pages, publish
|
|
32
|
-
- **gtag.js direct:**
|
|
33
|
-
```html
|
|
34
|
-
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
|
|
35
|
-
<script>
|
|
36
|
-
window.dataLayer = window.dataLayer || [];
|
|
37
|
-
function gtag(){dataLayer.push(arguments);}
|
|
38
|
-
gtag('js', new Date());
|
|
39
|
-
gtag('config', 'G-XXXXXXXXXX');
|
|
40
|
-
</script>
|
|
41
|
-
```
|
|
42
|
-
4. **Verify:** Enable GA Debugger extension, check Admin -> DebugView for session_start, page_view
|
|
43
|
-
5. **Send custom events:**
|
|
44
|
-
```javascript
|
|
45
|
-
gtag('event', 'button_click', { button_name: 'Subscribe', button_location: 'header' });
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Decision Tree: Which Reference Do I Need?
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
What are you trying to do?
|
|
52
|
-
|
|
53
|
-
Setting up GA4 for the first time? -> references/setup.md
|
|
54
|
-
Understanding how events work? -> references/events-fundamentals.md
|
|
55
|
-
Implementing standard tracking events? -> references/recommended-events.md
|
|
56
|
-
Creating business-specific custom events? -> references/custom-events.md
|
|
57
|
-
Making parameters appear in reports? -> references/custom-dimensions.md
|
|
58
|
-
Implementing User ID / cross-device? -> references/user-tracking.md
|
|
59
|
-
Building audiences for remarketing? -> references/audiences.md
|
|
60
|
-
Analysing data in GA4 reports? -> references/reporting.md
|
|
61
|
-
Exporting to BigQuery for SQL analysis? -> references/bigquery.md
|
|
62
|
-
Installing via gtag.js directly? -> references/gtag.md
|
|
63
|
-
Setting up GA4 in Google Tag Manager? -> references/gtm-integration.md
|
|
64
|
-
Sending events from server/backend? -> references/measurement-protocol.md
|
|
65
|
-
Testing and debugging implementation? -> references/debugview.md
|
|
66
|
-
Implementing GDPR/Consent Mode? -> references/privacy.md
|
|
67
|
-
Configuring Admin settings? -> references/data-management.md
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Core Concepts
|
|
71
|
-
|
|
72
|
-
### Event-Based Model
|
|
73
|
-
|
|
74
|
-
GA4 tracks everything as events in four categories:
|
|
75
|
-
|
|
76
|
-
| Category | Description | Examples |
|
|
77
|
-
|----------|-------------|----------|
|
|
78
|
-
| Automatic | Fire without configuration | session_start, first_visit |
|
|
79
|
-
| Enhanced Measurement | Toggle on/off in settings | scroll, click, file_download |
|
|
80
|
-
| Recommended | Google-defined with standard parameters | purchase, login, sign_up |
|
|
81
|
-
| Custom | Business-specific tracking | demo_requested, trial_started |
|
|
82
|
-
|
|
83
|
-
### Key Limits
|
|
84
|
-
|
|
85
|
-
| Limit | Value |
|
|
86
|
-
|-------|-------|
|
|
87
|
-
| Event names per property | 500 distinct |
|
|
88
|
-
| Parameters per event | 25 |
|
|
89
|
-
| Event name length | 40 characters |
|
|
90
|
-
| Parameter name/value length | 40 / 100 characters |
|
|
91
|
-
| Custom dimensions (event/user/item) | 50 / 25 / 10 |
|
|
92
|
-
| Audiences per property | 100 |
|
|
93
|
-
|
|
94
|
-
### Measurement ID
|
|
95
|
-
|
|
96
|
-
- Format: `G-XXXXXXXXXX` (G- prefix + 10 alphanumeric characters)
|
|
97
|
-
- Location: Admin -> Data Streams -> Web Stream
|
|
98
|
-
- Used in: gtag.js config, GTM tags, Measurement Protocol
|
|
99
|
-
|
|
100
|
-
## Common Workflows
|
|
101
|
-
|
|
102
|
-
### Ecommerce Tracking
|
|
103
|
-
|
|
104
|
-
1. Review [recommended events](references/recommended-events.md) for the purchase funnel: view_item -> add_to_cart -> begin_checkout -> purchase
|
|
105
|
-
2. Structure items array (required: item_id OR item_name; recommended: price, quantity, item_category)
|
|
106
|
-
3. Test with [DebugView](references/debugview.md), then register custom item parameters as [custom dimensions](references/custom-dimensions.md)
|
|
107
|
-
|
|
108
|
-
### Cross-Device Tracking
|
|
109
|
-
|
|
110
|
-
1. Implement [User ID](references/user-tracking.md) and configure Reporting Identity (Admin -> Data Settings)
|
|
111
|
-
2. Set [user properties](references/custom-dimensions.md) and build [cross-device audiences](references/audiences.md)
|
|
112
|
-
|
|
113
|
-
### GDPR Compliance
|
|
114
|
-
|
|
115
|
-
1. Set up [Consent Mode](references/privacy.md) with default denied state
|
|
116
|
-
2. Integrate with CMP (OneTrust, Cookiebot, etc.), update consent on user acceptance
|
|
117
|
-
3. Test consent implementation with [DebugView](references/debugview.md)
|
|
118
|
-
|
|
119
|
-
### Custom Reports
|
|
120
|
-
|
|
121
|
-
1. Understand available data in [reporting](references/reporting.md)
|
|
122
|
-
2. Register custom parameters as [dimensions](references/custom-dimensions.md), create Explorations
|
|
123
|
-
3. For unsampled data, export to [BigQuery](references/bigquery.md)
|
|
124
|
-
|
|
125
|
-
## Best Practices
|
|
126
|
-
|
|
127
|
-
- **Naming:** Use snake_case, be descriptive and action-oriented, keep under 40 characters, avoid generic names
|
|
128
|
-
- **Implementation order:** Enhanced Measurement -> recommended events -> custom events -> custom dimensions
|
|
129
|
-
- **Data quality:** Separate test/production properties, set up internal traffic filters from day one, document all custom events, audit regularly with DebugView, export to BigQuery for backup
|