SDK
The typed TypeScript package behind this workspace — the same models and rules the app uses, runnable locally against sample data.
Local / demo SDK. There is no hosted API and no network client. The SDK reads and writes an in-memory or local JSON store seeded with SOURCE-REPORTED, PROPOSAL and SYNTHETIC sample data. It has no method that sends, publishes, schedules, spends or exports customer data.
Setup
# unzip otah-gtm-sdk-0.1.0.zip, then:
cd sdk
npm install # dev deps only: typescript, tsx, @types/node
npm run typecheck # tsc --noEmit
npm run example # examples/basic-usage.ts
npm run build # dist/ (CommonJS + .d.ts)Requires Node.js 18+. The example writes to ./.local-data/gtm-store.json, created from seed data on first run.
Versioning
- SDK 0.1.0 — pre-1.0; the API may change without notice.
- Tracks app v0.1.0 and context pack v1.0.
- Seed-data changes bump the patch version; model or method changes bump the minor version until 1.0.
- The app imports
sdk/src/types,core,validationandbrief-generatordirectly, so rules stay identical in both.
Typed models
Brand
Tier, readiness + evidence class, activation record, missing inputs, boundaries, prohibited terms
ActivationRecord
10 fields, each with value, FieldStatus (evidence class or UNKNOWN), source and note
ReadinessEvent
Audit trail of readiness changes with rationale and recorder
Source
S00–S11 register entry with dates, scope, limitations and brand scope
Claim
Exact claim, audience, source, evidence class, approved use, owner, expiry, prohibited inference
Experiment
Full card incl. denominator, budget cap, capacity cap, success rule, stop rule, status
Brief
DRAFT decision brief or asset, with per-section evidence status
EvaluationCase / Run / Score
E01–E16 cases, runs with date + config version, 0/1/2 scores
BlockedAction
Send / Publish / Schedule / Spend / Export — why disabled and what authorization is needed
GTMClient methods
| Method | Behavior |
|---|---|
| listBrands(filter?) | Filter by readiness, tier or search; adds completeness + unknownFields. |
| getBrand(id) | Brand-scoped detail only — never another brand’s records. |
| updateReadiness(brandId, input) | Rationale required; APPROVED/VERIFIED need recorder + provenance. |
| updateActivationField(brandId, key, field) | Same provenance rule for non-UNKNOWN statuses. |
| listSources() | S00–S11 register, ordered. |
| listClaims(filter?) | Filter by brand and evidence class. |
| createClaim(input) | Rejects sources outside the claim brand’s scope. |
| listExperiments(filter?) | Filter by brand and status. |
| createExperiment(input) | Baseline defaults to UNKNOWN; approval is never assumed. |
| updateExperiment(id, patch) | Status changes re-validated; brand link is immutable. |
| computeEconomics(inputs) | Contribution, CAC, payback (seeded only with SYNTHETIC inputs). |
| generateBrief(brandId, kind) | Always DRAFT; gaps marked UNKNOWN; lens labels neutralised. |
| listBriefs(brandId?) | Stored drafts. |
| getEvaluationChecklist(runId?) | Cases with status + run summary. |
| createEvaluationRun(input) | configVersion required. |
| scoreEvaluation(runId, caseId, input) | Score 0/1/2 or null (NOT RUN) + critical flag. |
| getAuthorizationBoundaries() | Lists blocked actions — the SDK has no send/publish/schedule/spend/export methods. |
Example
import { GTMClient, SYNTHETIC_ECONOMICS_INPUTS } from '@otah/gtm-sdk';
const client = new GTMClient({ filePath: './.local-data/gtm-store.json' });
const capsules = await client.listBrands({ tier: 'capsule' });
const tc = await client.getBrand('tutorial-coach'); // brand-scoped
const brief = await client.generateBrief('tutorial-coach'); // status: 'DRAFT'
const econ = client.computeEconomics(SYNTHETIC_ECONOMICS_INPUTS); // SYNTHETIC only
const checklist = await client.getEvaluationChecklist();
console.log(checklist.summary.status); // 'NOT RUN' until all 16 cases are scoredThe full runnable example is sdk/examples/basic-usage.ts in the source viewer below. Want the same rules in the UI? See Experiments and Evaluation.
Source
1# @otah/gtm-sdk — OTAH GTM Coordinator SDK (local / demo)23> **LOCAL / DEMO SDK — v0.1.0.** There is no hosted API. Every method reads and writes a local4> store (in-memory, or a JSON file you choose). Nothing in this package sends, publishes, schedules,5> spends or exports customer data. All seed data is SOURCE-REPORTED, PROPOSAL or SYNTHETIC sample data.67The SDK is the single source of truth for the OTAH GTM Coordinator's domain model and rules. The web8app imports the same `types`, `core`, `validation` and `brief-generator` modules, so a rule enforced9here (e.g. "APPROVED needs a recorder and provenance") is enforced in the app too.1011## Setup1213```bash14cd sdk15npm install # typescript, tsx, @types/node (dev only)16npm run typecheck # tsc --noEmit17npm run example # runs examples/basic-usage.ts against ./.local-data/gtm-store.json18npm run build # emits dist/ (CommonJS + .d.ts)19```2021Requires Node.js 18+.2223## Quick start2425```ts26import { GTMClient } from '@otah/gtm-sdk';2728// In-memory store seeded from the context pack (nothing is persisted):29const client = new GTMClient();3031// Or persist to a local JSON file (created from seed data on first use):32const local = new GTMClient({ filePath: './.local-data/gtm-store.json' });3334const brands = await client.listBrands({ tier: 'capsule' });35const detail = await client.getBrand('tutorial-coach'); // brand-scoped: no other brand's records36const brief = await client.generateBrief('tutorial-coach', 'decision_brief'); // status: 'DRAFT'37```3839## Typed models (`src/types.ts`)4041| Model | Purpose |42| --- | --- |43| `Brand` | Registry entry with tier, readiness (+ evidence class), activation record, missing inputs, boundaries, prohibited terms |44| `ActivationRecord` / `ActivationField` | 10 fields (identity, buyer, job, offer, product_state, positioning, funnel, channel, data_policy, next_decision) each with value, `FieldStatus`, sourceId, note |45| `ReadinessEvent` | Audit trail of readiness changes (from → to, evidence class, rationale, recorder) |46| `Source` | S00–S11 register: date, checked date, scope, limitations, brand scope, evidence class |47| `Claim` / `ClaimInput` | Claim ledger row: exact claim, audience, source, evidence class, approved use, owner, expiry, prohibited inference |48| `Experiment` / `ExperimentInput` | Full experiment card: decision, hypothesis, denominator, budget cap, capacity cap, success rule, stop rule, status… |49| `EconomicsInputs` / `EconomicsResult` | Unit-economics calculator (used only with SYNTHETIC numbers in seed data) |50| `Brief` / `BriefSection` | DRAFT decision brief or asset (landing, outbound, discovery, pilot, onboarding) |51| `EvaluationCase` / `EvaluationRun` / `EvaluationScore` / `EvaluationSummary` | E01–E16 checklist with 0/1/2 scoring |52| `BlockedAction` | Send / Publish / Schedule / Spend / Export Customer Data — why disabled, what authorization is needed |5354Evidence classes: `SOURCE-REPORTED`, `HYPOTHESIS`, `APPROVED`, `VERIFIED`, `PROPOSAL`, `SYNTHETIC` (plus `UNKNOWN` for field status).55Readiness levels (proposed, not assigned): `unknown`, `discovery`, `pilot-ready`, `pilot-observed`, `repeatable`, `scale-ready`.5657## GTMClient methods (`src/client.ts`)5859| Method | Notes |60| --- | --- |61| `listBrands(filter?)` | Filter by readiness, tier, search. Adds `completeness` and `unknownFields`. |62| `getBrand(id)` | Brand-scoped detail: sources, claims, experiments, briefs, readiness events for that brand only. |63| `updateReadiness(brandId, input)` | Requires rationale; APPROVED/VERIFIED require `recordedBy` and provenance. |64| `updateActivationField(brandId, key, field)` | Same provenance rule for non-UNKNOWN statuses. |65| `listSources()` | S00–S11 register. |66| `listClaims(filter?)` / `createClaim(input)` | Rejects a source that is out of scope for the claim's brand. |67| `listExperiments(filter?)` / `createExperiment(input)` / `updateExperiment(id, patch)` | Real experiments need a brand; approved/running/completed need an approval recorder. Baseline defaults to UNKNOWN. |68| `computeEconomics(inputs)` | Contribution, CAC, payback. |69| `generateBrief(brandId, kind)` / `listBriefs(brandId?)` | Output is always DRAFT; missing inputs are marked UNKNOWN; prohibited terms are neutralised. |70| `getEvaluationChecklist(runId?)` / `createEvaluationRun(input)` / `scoreEvaluation(runId, caseId, input)` | PASS only when all cases are scored, total ≥ 85% and no critical failure. |71| `getAuthorizationBoundaries()` | Lists blocked actions. There are intentionally **no** send/publish/schedule/spend/export methods. |7273Pure helpers are also exported from `src/core.ts`: `evidenceCompleteness`, `computeEconomics`,74`caseStatus`, `summarizeEvaluation`, `applyClaimGuard`, `sourceAllowedForBrand`, `expiryState`,75`BLOCKED_ACTIONS`, `COMPLETENESS_WEIGHTS` (a PROPOSED heuristic) and `SYNTHETIC_ECONOMICS_INPUTS`.7677## Rules the SDK enforces7879- **Brand separation** — retrieval is brand-scoped; a source outside a brand's scope cannot back that brand's claim.80- **No invented approval** — APPROVED / VERIFIED need a named recorder and provenance.81- **DRAFT only** — generated briefs and assets carry `status: 'DRAFT'`; gaps are `UNKNOWN`.82- **Lens labels are not affiliations** — e.g. DealFlow.Coach's "BlackRock" lens label is replaced by a neutral term in public drafts.83- **Registry ≠ operations** — 23 inventory names do not prove active commercial operations.8485## Versioning8687`0.1.0` is pre-1.0: the API may change without notice. The SDK version tracks the app version88(v0.1.0) and the context pack it encodes (v1.0). Seed data changes bump the patch version; model89or method changes bump the minor version until 1.0.9091## Layout9293```94sdk/95 package.json96 tsconfig.json97 README.md98 src/99 types.ts typed models100 core.ts pure rules: completeness, economics, evaluation, blocked actions101 validation.ts input validation + GTMValidationError102 brief-generator.ts DRAFT brief/asset templates103 seed-brands.ts 23 brands (SOURCE-REPORTED / PROPOSAL)104 seed-records.ts sources, claims, experiments, evaluation cases105 store.ts MemoryStore / JsonFileStore106 client.ts GTMClient107 index.ts public exports108 examples/109 basic-usage.ts110```111