diff --git a/MIGRATION.md b/MIGRATION.md index c34a3809..2f53ee43 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -26,8 +26,8 @@ unchanged. - `package-index.json` and its schema-v1 validator; - canonical package payloads as they are merged; -- `aligned-onboarding`, `corpus-search`, and `building-integrations` as a - temporary compatibility set; +- `meta-and-voc-onboarding` and `building-integrations` as a temporary + compatibility set; - the Runneth Library rebuilding-page site; - scripts and GitHub workflows; and - repository documentation. @@ -35,9 +35,12 @@ unchanged. Legacy use cases that have no active package migration are available only from the archive branch and snapshot tag. -Aligned Onboarding is intentionally retained with both directories referenced -by its instructions. Do not remove any member of that set until a replacement -package carries the same behavior and dependencies. +Meta and Voice of Customer Onboarding is intentionally retained with `building-integrations`, +which its instructions reference. `corpus-search` was removed with the v2 +onboarding package: retrieval runs on Knoweth with summaries in Cacheth +(staging), and no remaining instruction depends on it. Do not remove +`building-integrations` until a replacement package carries the same behavior +and dependencies. ## Archived migration candidates @@ -51,13 +54,13 @@ snapshot tag. They must return to `main` only as schema-v1 packages: | Permissions | Complete the active rework and add a schema-v1 manifest | They are not package-manager installable until a canonical package payload, -matching `runneth-package.json`, and `package-index.json` entry are merged. +matching `package.json`, and `package-index.json` entry are merged. ## Package acceptance criteria Every package pull request must: -1. add one package payload and schema-v1 `runneth-package.json`; +1. add one package payload and schema-v1 `package.json`; 2. add a matching `package-index.json` entry; 3. reference only existing relative paths without symlinks; 4. target a supported root (`agent_apps`, `agent_brain`, `agent_skills`, or diff --git a/README.md b/README.md index ddb0cdc0..695cbe25 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,24 @@ are available from the archive branch and snapshot tag. Reintroduce one to `main` only after rebuilding it as a schema-v1 package; do not restore its legacy directory directly. -## Aligned Onboarding compatibility - -`aligned-onboarding/` remains on `main` with `corpus-search/` and -`building-integrations/`. These are a deliberate compatibility exception so -the recently merged onboarding flow keeps its source and referenced -dependencies while it is migrated to the package contract. +## Meta and Voice of Customer Onboarding + +`meta-and-voc-onboarding/` is a real indexed package: it carries a schema-v1 +`package.json` manifest and is registered in `package-index.json` with +`installPolicy: manual` - nothing installs it except one explicit +`package install "github:Motion-Creative/runneth-apps/meta-and-voc-onboarding#main"` +call. The completed install records selected intent (VM rebuilds reinstall it) and +`updatePolicy: auto` rolls out merged updates. The install message must also tell the agent to read +`/agent/brain/meta-and-voc-onboarding/post-install.md` and execute its install-time +sequence in the same conversation - that clause is what kicks off the VoC/Meta +setup; the exact copy-paste message lives in `meta-and-voc-onboarding/README.md` under +"How to install". A branch ref instead of `#main` exists only for +branch testing. If an install fails, report the exact error and stop - never +work around the package manager by hand-copying files or editing state under +`/agent/.runneth/packages/`. `building-integrations/` remains on `main` as a compatibility +exception. The `corpus-search/` tool has been removed: retrieval now runs on +Knoweth, with per-creative summaries held in Cacheth (staging). The removed +payload remains available from the archive branch and snapshot tag. ## Library website diff --git a/aligned-onboarding/README.md b/aligned-onboarding/README.md deleted file mode 100755 index 25199001..00000000 --- a/aligned-onboarding/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# Meta Onboarding Package: Overview - -This package teaches Runneth how to understand and work inside a customer's Meta ad account. It -ships as two parts that live side by side. Install and run them in order. - -The two parts: - -- **Account Context Brain** - how Runneth should analyze this account. -- **Creative Corpus** - the per-creative attributes Runneth analyzes. - -The one-line model: - -> **The Account Context Brain tells Runneth how to analyze the account. The Creative Corpus gives -> Runneth the per-creative attributes it needs to actually do the job.** - -The Creative Corpus depends on the Account Context Brain and never re-derives it. Keep them as two -files: they do different jobs, persist to different places, and refresh on different cadences. - ---- - -## Where the package files live - -These instruction files (this overview, the Account Context Brain, the Creative Corpus, and the -Motion CLI Data-Query Guide) are the package itself, not its output. They live in the Brain outside -the `meta` folder structure; the exact folder for them is not fixed yet and can be decided later. -corpus-search is a bundled tool, not an instruction file, and installs under -`/agent/tools/corpus-search/`. The `meta` folder holds only what Runneth generates from running the -package: the filled account context and the per-creative files. - ---- - -## Scope rules (apply to both parts) - -- **Meta only.** Never look for or pull other ad platforms (TikTok, LinkedIn, YouTube). -- **Ignore Motion workspace settings.** Treat workspace goal, preferred KPI, spend threshold, and - attribution config as if they do not exist. Everything comes from auto-pulled Meta ad data, the - worksheet, and customer confirmation. -- **One workspace at a time.** Every auto-pull names the account with `--workspace-id `. -- **Brain files are customer-facing.** Only account interpretation goes into the saved files. Never - save internal Runneth-team content: tool-calling nuances, CLI commands or flags, - command-vs-command discrepancies, or debugging notes. Metric nuances about how a metric shows up - in this account are welcome, written in business terms. -- **Onboarding pull window.** The fill-in auto-pulls default to `last_365d` so onboarding sees - enough history. This governs the fill-in only, not later performance queries. - ---- - -## The two parts - -### Account Context Brain -File: `account-context-brain.md` - -- **Job:** capture how the team interprets the account, so rankings, "best ad" calls, and insights - match how they actually think. Nine required context fields (sources of truth, conversion - hierarchy, metric gotchas, naming, attribution, account structure, funnel map, creative metrics, - targets). -- **How it runs:** auto-pull, then confirm with a person, then validate, then flag what it cannot - capture. `[AUTO]` values are proposals until a person confirms them. -- **Persists to:** `/agent/brain/meta/account-context.md` (create the `meta` folder if needed) -- **Activation:** merges a read-before-performance guard into `/agent/user.md`. -- **Refresh:** monthly cadence plus structural-drift triggers, logged in - `/agent/brain/meta/_changelog.md`. - -### Creative Corpus -File: `creative-corpus-playbook.md` - -- **Job:** build and maintain one enriched record per active creative (identity, summary, hook, - value props, transcript, AI tags, naming), the attributes Runneth uses to do the analysis the - Account Context Brain defines. -- **How it runs:** reads what the Account Context Brain already knows, then pulls from Motion only - what the Account Context Brain cannot tell it (the creative content itself). No separate corpus - tool to install. -- **Persists to:** individual creative Markdown files under `/agent/brain/meta/creatives/`, plus an - optional tagging taxonomy at `/agent/brain/meta/creatives/_tagging-taxonomy.md`. -- **Retrieval:** automatic through Knoweth. Writing the file is the index step. -- **Maintenance:** daily and event-triggered updates as creatives change. - ---- - -### Motion CLI Data-Query Guide (supporting reference) -File: `motion-cli-data-query-guide.md` - -- **Job:** the canonical contract for how Runneth pulls Meta, TikTok, Inspo, benchmark, and - workspace-setup data through the `motion` CLI, so queries come out right on the first try. Both - parts above lean on it for their auto-pulls. -- **Not run on its own.** It's reference knowledge, not a step to execute. It is brand-agnostic and - carries no account-specific IDs. - -### corpus-search (bundled tool) -Source: `Motion-Creative/runneth-apps/corpus-search` - -The package ships with **corpus-search**, a local hybrid-retrieval CLI, to **supplement** Knoweth -(not replace it). Knoweth stays the default: everything written under `/agent/brain/` is surfaced -automatically as pre-context. Reach for corpus-search when you need deliberate, filterable search -over a lot of raw text. - -**corpus-search is a general raw-text retrieval layer, not a creative-only tool.** The Creative -Corpus is one source it indexes; it is meant to hold any high-volume raw text the brain accumulates, -with customer reviews and voice-of-customer as primary use cases, alongside transcripts, notes, and -similar. Everything shares one index, kept separate by the `kind` tag (`creative`, `review`, -`voice-of-customer`, `transcript`, and so on), so you can search within a type or across all of them. - -- **Install:** stage it under `/agent/tools/corpus-search/`, then run - `bash /agent/tools/corpus-search/install.sh` and resolve its checklist. -- **Requires `OPENAI_API_KEY`** reachable in the workspace for embeddings. If the checklist flags it - as missing, request it securely (host `api.openai.com`), never pasted into chat. Some workspaces - pre-provision it. -- **Register sources by kind:** for this package, add `/agent/brain/meta/creatives` to - corpus-search's `sources.json` with `kind: creative`. Register other raw-text folders (reviews, - voice-of-customer, transcripts) the same way under their own `kind` so `refresh` keeps them all - current. Give each indexed file frontmatter (`brand`, `workspace`, `source_id`, and `event_at` - where it applies) so corpus-search can filter and dedupe on it. - ---- - -## Install and run order - -1. **Install the package.** Staging the files does not self-run anything. -2. **Activate the Account Context Brain.** Merge its guard block into `/agent/user.md`. -3. **Run the Account Context Brain fill-in.** Auto-pull, confirm with a person, validate, flag - gaps. This writes `/agent/brain/meta/account-context.md`. -4. **Install corpus-search.** Run `bash /agent/tools/corpus-search/install.sh`, resolve its - checklist (including `OPENAI_API_KEY`), and register `/agent/brain/meta/creatives` as a source - with `kind: creative`. One-time; can happen before or after the corpus is built. -5. **Build the Creative Corpus.** With the Account Context Brain in place, generate the per-creative - attribute files (each with its frontmatter). The Creative Corpus reads the Account Context Brain - for interpretation. Then index the folder into corpus-search so filterable search is available. -6. **Keep both current.** The Account Context Brain on its refresh cadence, the Creative Corpus on - daily and event-triggered maintenance, and refresh the corpus-search index on that same cadence. - ---- - -## How the two parts relate - -- The Account Context Brain is the lens; the Creative Corpus is the material. A performance question - uses the Account Context Brain to decide what "best" means and which numbers to trust, then the - Creative Corpus to reason about the specific creatives. -- The Account Context Brain's read-before-performance guard is what forces the lens to be loaded - before any performance work. The Creative Corpus is surfaced automatically through Knoweth when - creatives are discussed. -- The dependency runs one way: the Creative Corpus reads the Account Context Brain. The Account - Context Brain never depends on the Creative Corpus. diff --git a/aligned-onboarding/SKILL.md b/aligned-onboarding/SKILL.md deleted file mode 100644 index e6973e15..00000000 --- a/aligned-onboarding/SKILL.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -name: aligned-onboarding -description: > - Teaches Runneth how a customer reads their Meta ad account, then builds and maintains one - enriched record per active creative. Two parts run in order: the Account Context Brain (how to - analyze the account) and the Creative Corpus (the per-creative attributes). Meta only, one - workspace at a time. Trigger on "run aligned onboarding", "set up my Meta account context", - "build my account context", "teach Runneth how we read the account", "build the creative corpus", - or when a Meta performance question is asked and /agent/brain/meta/account-context.md does not - exist yet. -triggers: - phrases: - - "run aligned onboarding" - - "aligned onboarding" - - "set up my meta account context" - - "build my account context" - - "teach runneth how we read the account" - - "build the creative corpus" - - "onboard my meta account" - intent: "User wants Runneth to learn how their Meta account should be interpreted and build the per-creative corpus." ---- - -# Aligned Onboarding - -Teaches Runneth how this customer reads their Meta ad account, then builds the per-creative corpus -off that lens. It ships as two parts that do different jobs and persist to different places. - -The one-line model: - -> The **Account Context Brain** tells Runneth **how to analyze** the account. The **Creative -> Corpus** gives Runneth **the attributes it needs to actually do the job**. - -Read the package overview at `/agent/brain/aligned-onboarding/README.md` before running. The full -procedures live in the staged docs and are the source of truth for each step: - -- Account Context Brain: `/agent/brain/aligned-onboarding/account-context-brain.md` -- Creative Corpus playbook: `/agent/brain/aligned-onboarding/creative-corpus-playbook.md` -- Motion CLI data-query guide: `/agent/brain/aligned-onboarding/motion-cli-data-query-guide.md` - -## Scope rules (apply throughout) - -- **Meta only.** Never pull or reason about other ad platforms (TikTok, LinkedIn, YouTube). -- **Ignore Motion workspace settings.** Treat workspace goal, preferred KPI, spend threshold, and - attribution config as if they do not exist. Everything comes from auto-pulled Meta data, the - worksheet, and customer confirmation. -- **One workspace at a time.** Every auto-pull names the account with `--workspace-id `. -- **Brain files are customer-facing.** Save only account interpretation. Never write tool-calling - nuances, CLI commands or flags, or debugging notes into the saved files. -- **Onboarding pull window is `last_365d`** for the fill-in only, so onboarding sees enough history. - -## Run order - -1. **Resolve the workspace.** Confirm the target `` (the Meta account being onboarded). - Use `motion workspaces` if it is not already known. -2. **Activate the guard.** Merge the account-context guard block from `account-context-brain.md` - into /agent/user.md using the sentinel convention (`runneth:account-context-guard`), - substituting the real ``. Author it from `building-integrations/behavior-snippet.md`. - Replace an existing block in place; never duplicate it. -3. **Run the Account Context Brain fill-in.** Follow `account-context-brain.md`: auto-pull all nine - fields, present them together as one overview, confirm the open questions with a person, - validate, and flag what cannot be captured. Write the prose result to - `/agent/brain/meta/account-context.md` and index it in `/agent/INDEX.md`. `[AUTO]` values stay - proposals until a person signs off. -4. **Reuse corpus-search (optional but recommended).** If `/agent/tools/corpus-search/` is not - already present, fetch corpus-search from the public library and install it per its own - install-config; never clobber a customized copy. It supplements Knoweth for deliberate, - filterable search. Register `/agent/brain/meta/creatives` as a source with `kind: creative`. -5. **Build the Creative Corpus.** Follow `creative-corpus-playbook.md`: read what the Account - Context Brain already knows, pull only the creative content from Motion, and write one enriched - Markdown file per active creative under `/agent/brain/meta/creatives/`. Writing the files is the - index step for Knoweth; index the corpus-search source too if installed. -6. **Keep both current.** Account Context Brain on a monthly-plus-drift cadence; Creative Corpus on - daily and event-triggered maintenance. Log every refresh in `/agent/brain/meta/_changelog.md`. - -## Precedence - -`/agent/brain/meta/account-context.md` is the sole source of account interpretation (how "best," -"winner," and cost-per are judged). It defers only to a metric the user names explicitly in the -current turn. The Creative Corpus reads the Account Context Brain and never re-derives it; when they -disagree, the Account Context Brain wins. diff --git a/aligned-onboarding/account-context-brain.md b/aligned-onboarding/account-context-brain.md deleted file mode 100755 index 07adf3f1..00000000 --- a/aligned-onboarding/account-context-brain.md +++ /dev/null @@ -1,661 +0,0 @@ -# Meta Account Context: Brain Onboarding Package - -This package teaches Runneth how a customer understands their Meta ad account, so its queries, -rankings, and insights match how the team actually thinks about the data. This package is -Meta-only: it never looks for or pulls other ad platforms (TikTok, LinkedIn, YouTube). Meta is -the ad platform for this account by definition. Installing it stages -these files into the customer brain. It does not self-run. Activation, below, is what makes -Runneth run the fill-in and then live by the result. - -Two things exist after activation: -1. A durable, workspace-scoped context file, written as a plain-language reference document (not - the worksheet), that Runneth writes and later reads as source of truth. -2. A small standing guard merged into `/agent/user.md` that forces Runneth to read that file - before any performance work. - ---- - -# How this package operates - -## 1. Activation (what triggers it, and when) - -Installing only stages files. The package does not self-run. To activate it, merge the guard -block below into `/agent/user.md`, then run the fill-in procedure. - -Merge the block using the standard behavior-snippet convention (author it from -`building-integrations/behavior-snippet.md`). It is sentinel-wrapped so it is idempotent. - -**MERGE INSTRUCTIONS:** If a block with the sentinel `runneth:account-context-guard` already -exists in `/agent/user.md`, replace it in place. Otherwise append it. Never duplicate it. Do not -edit anything outside the sentinels. - -``` - -Account context guard (workspace ): - -- Before any ad-performance work for this account (rankings, "best ads," CPA/ROAS reads, - winner or cut calls, creative performance judgments), read - /agent/brain/meta/account-context.md first. -- If that file does not exist, or its required interpretation fields are not all [CONFIRMED], - treat account - interpretation as unknown. Offer to run the account-context fill-in flow, and do not answer - performance questions on guesses. -- Runneth may auto-fill and mark [AUTO] fields on its own immediately. It must hold [CONFIRMED] - fields for a person and never promote [AUTO] to [CONFIRMED] without human sign-off. -- Precedence: this file is the sole source of account interpretation (how "best," "winner," and - cost-per are judged). Do not read or defer to Motion workspace settings (workspace goal, - preferred KPI, spend threshold, attribution config); treat them as if they do not exist for - this account. Defer only to a metric the user names explicitly in the current turn. - -``` - -## 2. Workspace scope - -This context describes one workspace. Record the scope before pulling anything: - -- Target workspace: `` (ad account: ``) -- Date window for filling in this package: the `[AUTO]` pulls used to complete these fields - default to `last_365d` (the last 365 days of creatives), so onboarding sees enough history to - interpret the account. This window governs the fill-in pulls only. It is not a standing default - for later performance queries; those still use their own requested window, or the normal - defaults, unless the user asks otherwise. -- Every `[AUTO]` pull passes `--workspace-id ` explicitly. Customer brains are - usually one workspace, but multi-workspace orgs are real and the pulls must name the account. -- Platform scope: Meta only. Never look for, pull, or reason about other ad platforms (TikTok, - LinkedIn, YouTube) in this package. -- Settings scope: pretend Motion workspace configuration settings do not exist. Do not read or - rely on workspace goal, preferred KPI, spend threshold, or attribution-window config. Every - value comes from auto-pulled Meta ad data, this worksheet, and customer confirmation. This - file is the only source of account interpretation. - -## 3. Where the filled result lives (persistence) - -Confirmed answers do not live in this worksheet. Runneth writes them to a durable brain file so -future turns read them. - -- Create the account's `meta` folder in the brain if it does not exist. Save the filled result - to `/agent/brain/meta/account-context.md`. The per-creative files from the Creative Corpus live - in a `creatives` subfolder beside it (`/agent/brain/meta/creatives/`). - -**The saved file is a prose reference document, not the worksheet.** Capture and communication are -two different jobs. The fields-and-statuses procedure below is how Runneth captures rigorously; the -saved file is how it communicates. Write the saved file the way a sharp analyst would explain this -account to a new teammate: interpretation baked into sentences, the decision stated, readable in -about 30 seconds. State conclusions, not statuses. Do not carry `[CONFIRMED]`/`[AUTO]`/`[FLAGGED]` -badges or `Field N` headings into it. Express open items in plain language (we are still confirming -per-product targets with the team), not as flag noise. Use this order: - -1. **Title (H1):** `# - Meta Account Context` -2. **One short intro paragraph, in plain language:** what this file is, that Runneth reads it - before any Meta performance work for this account, and how to read the field statuses - (`[CONFIRMED]` = a person validated it, `[AUTO]` = pulled but unconfirmed, `[FLAGGED]` = still - needs the customer). This replaces the bare `Load before any performance analysis.` line; keep - that meaning, but say it like a sentence, not a machine directive. -3. **At a glance:** a few bullets a human can skim: last refreshed, confidence, fields confirmed - (count / 9), and any open flags. -4. **The nine fields**, in order. -5. **File metadata (last):** end the file with a `## File metadata` heading followed by the machine - contract as a fenced `yaml` code block, so refresh routines have something to read but it never - dominates the top of the file. Keep it valid and fenced so no renderer shows it as a wall of - body text. The block holds these keys: - - - `domain: meta` - - `ownership: ` - - `substance: account-interpretation` - - `managed_by: account-context onboarding package` - - `sources: [meta-auto-pull, customer-confirmation]` - - `refresh_cadence: monthly` - - `last_refreshed: ` - - `confidence: ` - - `confirmed_by_team: ` - -**Write conclusions, not readouts.** The difference: -- Worksheet (internal capture): `ROAS: [CONFIRMED] blended, runs below 1, all products one pixel.` -- Saved file (prose): ROAS always looks low here because every product shares one pixel, so it - comes out blended. Don't lead with it; judge each product on CPA. -The reader should never have to interpret a status. The interpretation is already done for them. -Model the tone on a strategist's account brief, not a filled form. - -- Index it in `/agent/INDEX.md` with aliases (account context, KPI hierarchy, how we judge ads, - performance interpretation) and a one-line note. The read-before guarantee comes from the guard - in `user.md`, not from the index. INDEX is a routing surface, not always-on context, so indexing - alone does not force a read. - -### Output skeleton (match this shape) - -Produce the saved file in this shape and voice. Placeholders in `<...>` get replaced with the -account's real interpretation; the point is prose that states conclusions, not a status readout. - -~~~markdown -# - Meta Account Context - - - -## At a glance -- Platform: Meta only. -- How we judge: . -- Attribution: . -- Biggest gotcha: . - -## How we read this account -<2 to 4 short paragraphs. What "best" means here and why. Which numbers to trust and which -mislead, with the reason baked in, e.g. "ROAS looks low because all products share one pixel, so -judge on CPA." Each point is a conclusion, not a status.> - -## Conversion events - - -## Campaigns and funnel - - -## Naming - - -## How we decide - - -## Still confirming - - -## File metadata -```yaml -domain: meta -workspace_id: -workspace_name: -brands_in_scope: [<...>] -other_workspaces_in_org: [] -ownership: -managed_by: account-context onboarding package -refresh_cadence: monthly -last_refreshed: -confidence: -confirmed_by_team: -``` -~~~ - -## 4. Refresh (keep it current, never one-time) - -- `refresh_cadence` is set in the File metadata block (recommend monthly for account interpretation). -- The `meta` folder keeps `/agent/brain/meta/_changelog.md`. Any refresh - appends a one-line entry. No silent updates. -- Structural drift is a second trigger: when new conversion events, campaigns, or naming - patterns appear, re-open only the affected `[CONFIRMED]` fields for re-confirmation and - re-synthesize only those. -- Delivery is recommend-then-confirm: Runneth proposes the cadence, the team confirms before a - routine is created. -- Honest constraint: the clean scheduled-refresh primitive (`background-upkeep`) is not shipped - yet. Until it lands, run refresh as a deterministic script on best-effort scheduling, or as a - manual re-run. - -## 5. Precedence - -State this in the filled file too. This account-context file is the sole source of account -interpretation (how "best," "winner," and cost-per are judged). Do not consult Motion workspace -settings; treat workspace goal, preferred KPI, spend threshold, and attribution config as if they -do not exist for this account. This file defers only to a metric the user names explicitly in the -current turn. - ---- - -# How Runneth fills this in - -Work through the fields in order. For each field: - -1. **Auto-pull.** Run the observable pulls listed under the field (scoped with `--workspace-id`) - and pre-fill with what the account actually shows. Mark those lines `[AUTO]`. -2. **Ask, intuitively.** Do not read the prompts below as a script. Read what auto-pull returned - first, then ask only what the data genuinely leaves open, in the customer's own terms, - grounded in the specifics you actually pulled. Each field states what to *understand*, not - wording to recite. Mark confirmed answers `[CONFIRMED]`. -3. **Validate.** Use the field's validation question as an acceptance test, instantiated with the - account's real events, campaigns, and names. If Runneth can answer it correctly from the - filled fields, the field is done. -4. **Flag.** If a field cannot be auto-pulled and has not been answered, mark it `[FLAGGED]` and - write one line on what is blocking it. - -Hard rules: - -- Never guess, infer, or invent a value to fill a blank. A `[FLAGGED]` field is always better - than a wrong one. -- `[AUTO]` values are proposals until a person confirms them. Auto-pull shows what fired, never - what it means. Never promote `[AUTO]` to `[CONFIRMED]` without human sign-off. -- The intake is not deterministic. If the pull already answers something, do not ask it again. - If the pull surfaces something surprising, follow it with a question no script listed. -- Meta only. Do not look for or pull other ad platforms (TikTok, LinkedIn, YouTube). -- Do not read or rely on Motion workspace settings (workspace goal, preferred KPI, spend - threshold, attribution config). Treat them as nonexistent. Everything Runneth needs comes from - auto-pulled Meta ad data, this worksheet, and customer confirmation. -- Video-only metrics (thumbstop, hold rate, video plays, and other view/retention metrics) do not - apply to static image ads. For statics, treat them as not applicable, never as 0. Never rank, - compare, judge, or flag a static on a video metric, and never include statics when computing - video-metric averages. -- Do not volunteer or rank by ROAS unless the account has confirmed revenue-based conversions and - ROAS is confirmed as a trusted metric. Many Meta accounts (lead-gen, app, non-purchase) have no - meaningful ROAS; there, treat ROAS as not applicable and rank by the confirmed conversion event - instead. Never present ROAS as a headline number on an account whose north-star is a lead or - other non-purchase event. -- The saved brain files are customer-facing account interpretation only. Never write internal - Runneth-team content into them: tool-calling nuances, CLI command names or flags, or - endpoint-vs-endpoint comparisons. Capture metric behavior in account and business terms, not in - terms of which command returned what. -- Do not write generic metric definitions or universal creative principles into the file (for - example "thumbstop is the 3-second rate," "statics have no video metrics"). That is practitioner - baseline, not account context. Only what is true about THIS account belongs here. -- `[CONFIRMED]` means a person validated it, never that Runneth observed it in data. Runneth-observed - evidence is `[AUTO]`. -- When a field's purpose is unclear, ask what it is for before filling it. Do not invent a purpose. -- `motion brand-context` (own-brand strategy) is allowed input for reasoning about what the account - optimizes for. It is not a Motion workspace setting, so the "ignore settings" rule does not block - it. -- The fields and statuses in this procedure are internal capture scaffolding: how Runneth tracks - confirmed vs assumed vs missing while it works. They are NOT the saved file. Never save the - worksheet (status badges, `Field N` headings, flag lists) as the brain file. The brain file is the - prose reference document specified in the persistence section. - -### How to ask well - -- Anchor every question in a specific thing you pulled: a named event, a specific campaign, an - actual naming pattern, a metric that looked off. The pulled data is context that makes the - question concrete — not a proposal for the person to confirm. Ask openly. -- Ask the fewest questions that close the real gaps. Skip anything the data already settled. -- When something the pull surfaced is ambiguous or unexpected, ask about that first. - -The difference: -- ❌ Abstract: "What attribution windows do you use?" -- ✓ Anchored open: "Your campaign suffixes use `7D1V1E` and `7D1V` — what windows are you - actually reading results against?" - -- ❌ Abstract: "Is Northbeam connected?" -- ✓ Anchored open: "Northbeam returned null across every row. Is it connected here, or has it - been deprecated?" - -The data gives the person something real to react to. The question is still genuinely open. - -**Presenting the full picture (default output format).** After auto-pulling all nine fields, -present them together as a single overview — not one item at a time. This is the default output. -Go field by field, and for each one: state what you pulled, then ask the single open question that -the pull leaves unanswered. Where the pull fully settles a field, say what you know and move on -with no question. When the person responds, confirm or update fields from their answers, then -write the saved file. - -Rules for the full overview: -- Talk about the account, never the worksheet. Do not show field numbers, status badges, or - `[FLAGGED]` labels. Those are internal. -- Each field gets one anchored question at most. No compound questions or sub-bullets. -- Lead with what you know. The ratio should feel like mostly settled reads with a few specific - things still open — not a list of things you don't know. -- Keep it moving and light. When a field is settled by the pull, say so briefly and move on. - Do not ask for confirmation of things the data already answered. - -### Status legend - -- `[EMPTY]` nothing captured yet -- `[AUTO]` pre-filled from the account, needs a person to confirm -- `[CONFIRMED]` a person validated it -- `[FLAGGED]` could not be captured, needs the customer -- `[N/A]` does not apply to this account - ---- - -## Field-to-command map - -How to pull each field. Exact command shapes and flags live in the Motion CLI Data-Query Guide -(`motion-cli-data-query-guide.md`); this table says which command answers which field and what to -read from the result. Resolve any uncertain metric key with `motion meta metric-reference` and any -fuzzy name with `motion meta filter-reference` first. - -| Field | Pull with | Extract | -|---|---|---| -| 1. Sources of truth | `motion meta custom-conversion-metrics`; a `motion meta ads --grain adnames --northbeam --include-metrics` probe | which events exist; whether Northbeam returns values (third-party attribution present) vs Meta native only | -| 2. Conversion events | `motion meta custom-conversion-metrics`; `motion meta metric-reference --query "purchase"` (or the relevant event) | each event's id/name and the standard vs custom key; which product each maps to | -| 3. Known metric gotchas | `motion meta insights --date-range last_365d --include-metrics` (inspect the returned rows) | which metric columns are null/zero/misleading across creatives (e.g. thumbstop, ROAS, asset-type, campaign/ad set names) | -| 4. Naming conventions | `motion meta insights --include-metrics` (adName on rows); `motion meta ads --grain adnames`; `motion meta ads --grain ads` for membership | the name strings per level; detect structure and per-level reliability; note if campaign/ad set names come back empty | -| 5. Attribution | No pull. Motion settings are ignored by design | propose 7-day click / 1-day view and confirm with the team | -| 6. Account structure | `motion meta ads --grain ads --include-associated-objects` | budget level (CBO vs ABO) and ad set / ads-per-set counts where observable; the rest is team input | -| 7. Funnel map | `motion meta ads --grain ads` (campaigns + objectives); `motion meta insights` to read `fs-`/`p-` from ad names | campaign-to-stage grouping; product lines; north-star is team input | -| 8. Creative performance metrics | `motion meta insights --date-range last_365d --include-metrics --table-kpi ` (keys resolved via metric-reference) | account averages for the metrics judged on (CPA, hold rate, CTR); compute video-only metrics from video creatives only | -| 9. Targets, thresholds and decision rules | `motion meta insights --include-metrics --table-kpi ` | reference cost-per-event to anchor targets; the targets, cut, and scale rules are team input | - -Reminder: these commands belong in the package (how Runneth does the work). None of this command -detail is written into the saved account-context file, which stays customer-facing. - ---- - -# Required context fields - -All nine fields are required, and Runneth auto-pulls every one of them. There is no optional set. -Fields 1 to 4 establish whether Runneth is even correct for this account: which numbers to trust -and what "best" means. Fields 5 to 9 make its answers sharp and actionable. All of them get -pulled, filled, and confirmed. - -## 1. Sources of truth - -Status: `[EMPTY]` - -This account runs on Meta. Do not look for or pull other ad platforms (TikTok, LinkedIn, -YouTube); Meta is the ad platform by definition. This field captures which tool is authoritative -for each kind of number layered on top of Meta. - -**Auto-pull** -- List the data sources feeding this Meta account (Meta native, plus any third-party attribution - source such as Northbeam). -- Note whether a third-party attribution source is connected. - -**What to understand** (ask only what the pull leaves open) -- Which tool the customer treats as authoritative for creative performance, spend, conversions, - and attribution, and which wins when tools disagree. -- Meta native only: confirm. Meta plus a third-party source: the disagreement question is the - key one. - -**Fields** -- Ad platform: Meta (fixed) -- Data/attribution sources connected: `` -- Source of truth, creative performance: `<...>` -- Source of truth, spend: `<...>` -- Source of truth, conversions: `<...>` -- Source of truth, attribution: `<...>` -- Tie-breaker when sources disagree: `<...>` - -**Validation question:** "What was our cost per [north-star event] last month, and which source -is that from?" A correct answer names the trusted source, not the Meta default. - -**Flag if:** sources are detected but no authority ranking is confirmed. - -## 2. Conversion events: definitions and hierarchy - -Status: `[EMPTY]` - -Captures every conversion event, what it means to the business, and how it ranks. Defines what -"best" means for this account. - -**Auto-pull** -- List the conversion events firing in the account (custom conversions and standard events). -- Where observable, note which campaigns optimize toward which event. -- If an event returns zero across all creatives, treat it as not currently in use. Do not judge on - it. Fall back to the standard purchase event, or another event that logically fits the business. - -**What to understand** (ask only what the pull leaves open) -- What each event represents to the business, and how the customer ranks them by value. -- Which events are true optimization targets versus upstream-only signals. -- Let the pulled event names shape it: confirm the self-explanatory, ask about the cryptic or the - low-value event being optimized toward. -- Use `motion brand-context` to reason about what the account most likely optimizes for before - asking (a purchase-driven brand judges on cost per purchase, ROAS, or a purchase-like custom - event). Propose that read and confirm it, rather than asking cold. - -**Fields** (repeat per event) -- Event: `` | Meaning: `<...>` | Value rank: `<...>` | Optimization or upstream-only: `<...>` - -**Validation question:** "What are our best-performing ads right now?" A correct answer ranks by -the north-star event and shows cost-per that event, never spend, ROAS, or an upstream-only signal. - -**Flag if:** events are listed but meaning, rank, or the optimization split is not confirmed. - -## 3. Known metric gotchas - -Status: `[EMPTY]` - -Captures metrics that are broken, structurally zero, double-counted, or misleading here, and what -to use instead. - -**Auto-pull / flag candidates** -- Scan for suspicious patterns and propose them: a metric reading zero across spend, a conversion - column always blank, a metric that looks double-counted. -- High spend with zero conversions or zero CPA on a working purchase pixel is usually NOT a broken - metric. It typically means the campaign optimizes for a different event (awareness, traffic) or a - goal is misconfigured on another layer. Check the campaign objective and goal setup first; if it - is an objective mismatch, note it in the funnel/campaign context, not as a metric gotcha. -- Field availability differs by endpoint (a field can be null on one endpoint but present on - another). Verify a field on the endpoint you will actually use before recording it as missing. - -**What to understand** (ask only what the pull leaves open) -- For each flagged pattern, whether it is expected and what to use instead. -- Whether there are gotchas the scan could not see. Ask openly; some are only known to the team. - -**Fields** (repeat per gotcha) -- Metric: `<...>` | Why misleading here: `<...>` | Use instead: `<...>` | Status: `` - -**What to record (and what not to):** a gotcha is about how a metric behaves in this account, in -business terms: what it reads, why it misleads, what to use instead. Never record tool-calling -mechanics, CLI command names or flags, or endpoint-vs-endpoint comparisons; those are internal -notes and do not belong in the brain. If a discrepancy is real but unconfirmed, record it as an -open flag in account terms and carry it forward for monitoring. - -Example, written for the brain with the mechanics stripped out: -`Open flag: purchase count and ROAS come back empty when creatives are rolled up by ad name, but -populate at the individual-creative level. Likely an aggregation difference. Not confirmed as a -gotcha; carry forward for monitoring.` - -**Validation question:** "What's our ROAS on [campaign]?" A correct answer explains why the broken -metric reads the way it does and redirects to the right lens, instead of reporting the bad number. - -**Flag if:** a candidate was detected but not confirmed, or the open question was not asked. - -## 4. Naming conventions (campaign + ad set + ad, with reliability per level) - -Status: `[EMPTY]` - -Captures whether the account uses naming conventions, what each level encodes, and how reliable -each level is. Knowing they do NOT have strong naming is just as valid, and tells Runneth to lean -on creative signals and landing pages instead. - -**Purpose:** this field decodes EXISTING names so Runneth can interpret data. It is read-only -interpretation. It never prescribes or changes naming. Naming can only change going forward, and -changing it resets Meta's learning, so there is no such thing as "updating" an account's naming -here. - -**Auto-pull** -- Pull all campaign, ad set, and ad name strings. -- Detect structure per level (delimiters, positional consistency) and propose a decoder. -- Measure reliability per level: percent of names that fit the detected pattern. - -**What to understand** (ask only what the pull leaves open) -- For levels with a detected pattern, confirm what each position means. -- For levels with no reliable pattern, whether a convention exists that the data missed, or - whether to fall back to creative signals and landing pages. -- Let measured reliability set the tone: high-confidence pattern = quick confirm; messy level = - real fallback conversation. -- For any tag whose meaning is not obvious, record what it means AND an explicit "does NOT mean X" - line to block the intuitive-but-wrong reading (e.g. a tag that looks like an approval or scaling - flag but is not). -- Precedence: when a name-embedded code (such as a product code in the ad name) conflicts with the - campaign, the campaign wins. - -**Fields** (repeat per level) -- Level: `` | Reliability: `` | - Fields encoded and positions: `<...>` | Fallback if weak: `` - -**Validation question:** "What's our best-performing messaging angle across the account?" A correct -answer decodes the right position at the right level, or, if naming is weak, says it is using -creative signals and why. - -**Flag if:** a level has a detected pattern but no confirmed meaning, or a weak level has no -confirmed fallback. - -## 5. Attribution model and windows - -Status: `[EMPTY]` - -**Auto-pull** -- Nothing reliable from settings. Do not read attribution windows from Motion workspace - configuration; treat that config as nonexistent. Only note a connected third-party attribution - tool if one is observable in the data. - -**What to understand** (confirm a proposed default) -- Do not ask the customer to specify windows cold. Propose the standard default of **7-day click, - 1-day view** and ask if it is okay to assume that. If they confirm, mark it confirmed; if they - judge on different windows, capture those instead. Also confirm which source they trust for the - final call. - -**Fields** -- Trusted source: `<...>` | Click window: `` | - View window: `` | Judged-on window if different: `<...>` - -**Validation question:** "How many demos did we book from ads last month?" A correct answer uses -the trusted source and window and states both. - -**Flag if:** the proposed 7d click / 1d view was neither confirmed nor replaced with the -customer's own windows. - -## 6. Account structure - -Status: `[EMPTY]` - -**Auto-pull** -- Detect whether budget sits at campaign (CBO) or ad set (ABO) level. Note ad set counts and ads - per ad set. - -**What to understand** (ask only what the pull leaves open) -- Confirm the detected budget level, then learn the behavior the data cannot show: how tests are - batched, how many creatives per batch, and what triggers a pause or a cut. -- Campaign and ad-set membership must come from the correct endpoint (`motion meta ads`, grain ads, - plus the two-step filtered pull), not inferred from an unfiltered creative pull. Getting the - endpoint right is what prevents campaign misclassification and creative-overlap errors; no extra - classification machinery is needed. - -**Fields** -- Budget level: `` | Test batching: `<...>` | Creatives per batch: `<...>` | - Pause/cut rule: `<...>` - -**Validation question:** "Which ad sets should we consider cutting?" A correct answer applies -their pause/cut rule, not a generic low-performance heuristic. - -**Flag if:** structure is auto-pulled but the pause/cut logic is not confirmed. - -## 7. Funnel map - -Status: `[EMPTY]` - -Captures how the account's campaigns map to funnel stages and which campaigns carry the objective -the team cares about most. Expressed in campaigns, not raw events, because that is how the team -organizes and talks about the account. - -**Auto-pull** -- Pull the campaigns running in the account with their objectives. Propose how they group into - funnel stages (for example prospecting / top-of-funnel vs retargeting / bottom-of-funnel). -- Campaign names come from the `campaignName` field on the returned rows, or from - `motion meta ads` / `motion meta filter-reference`. Meta insights has no campaign group-by, so - read campaign names off the returned rows rather than trying to group by campaign. If a - campaign name looks wrong or mismatched against the ad, flag it rather than trusting it. - -**What to understand** (ask only what the pull leaves open) -- Confirm which campaigns belong to which funnel stage, and which campaign(s) or stage is the one - or two the team cares about most (their north-star). Where useful, tie each stage to the - conversion event it optimizes toward (from field 2). Ground it in the campaigns actually pulled, - not the abstract. -- Record confirmed campaign names and their roles (scaling, testing, launch, excluded). Structural - roles are defined by which campaign, not by spend level; an ad's role is its campaign's role - (e.g. a testing ad is one inside the testing campaign, regardless of its spend). -- Explicitly list excluded campaigns: off-Meta or otherwise incomparable campaigns (marketplace- - routed, off-site conversion) that must be kept out of standard CPA/DTC comparisons. -- For spend-accurate reads, use the two-step filtered pull: a filtered pull for campaign-accurate - spend, an unfiltered pull for creative detail, joined by ID. - -**Fields** -- Campaign-to-stage map: `` | Campaign roles (scaling/testing/launch): `<...>` | - North-star campaign(s) or stage: `<...>` | Event each stage optimizes toward: `<...>` | - Excluded campaigns (off-Meta / incomparable): `<...>` - -**Validation question:** "Which of our campaigns are top-of-funnel versus closing, and which -matter most?" A correct answer places each campaign in the right stage and names the north-star -campaign or stage. - -**Flag if:** the campaign-to-stage map is proposed but not confirmed. - -## 8. Creative performance metrics and benchmarks - -Status: `[EMPTY]` - -**Auto-pull** -- Pull the metric values and current account averages to anchor target-setting. -- Thumbstop, hold rate, and other view metrics are not guaranteed to come back by default. Resolve - the exact metric key with `motion meta metric-reference` and request it explicitly (for example - with `--table-kpi` / `--chart-kpi`, or the matching sort) rather than assuming the default pull - includes it. Never invent or transform a metric key. -- Engagement metrics can be null on a long window (`last_365d`) even when they exist. Test a recent - window (e.g. `last_30d`) before concluding a metric is unavailable for the account. -- Compute those video-only metrics (thumbstop, hold rate, video plays) from video creatives only. - Static image ads have no such metrics: mark them not applicable, never 0, and keep them out of - video-metric averages and benchmarks. - -**What to understand** (ask only what the pull leaves open) -- Which creative metrics the customer judges on, and their target or floor for each. Use the - pulled averages to anchor, not a cold ask. - -**Fields** (repeat per metric) -- Metric: `<...>` | Target or floor: `<...>` | Account average: `` - -**Validation question:** "Is this video's hook working?" A correct answer checks their metrics -against their targets in priority order, not a generic read. - -**Flag if:** metrics are auto-pulled but no targets are confirmed. - -## 9. Targets, thresholds and decision rules - -Status: `[EMPTY]` - -**Auto-pull** -- Pull current cost-per-event as a reference. Propose a spend confidence floor (about 5x target). - -**What to understand** (ask only what the pull leaves open) -- Target CPA per event, how much spend makes a result trustworthy, and when the customer scales - versus cuts. Anchor on the pulled costs so targets are set against reality. -- Every spend threshold must state its time window: cumulative lifetime spend, or spend within a - stated window (e.g. last 30 days). A threshold with no window is incomplete; capture the window - explicitly, and flag it if the team has not specified one. - -**Fields** (repeat per event) -- Event: `<...>` | Target CPA: `<...>` | Spend confidence floor: `` | - Spend window: `` | Graduation threshold: `` | - Scale rule: `<...>` | Cut rule: `<...>` - -**Validation question:** "Is this ad a winner yet?" A correct answer checks spend against the -confidence floor before declaring anything, then judges CPA against the target. - -**Flag if:** reference costs are auto-pulled but targets and thresholds are not confirmed. - ---- - -# Derived capabilities (not filled, enabled) - -Runneth computes these from the fields above. Never asked or filled; they turn on once their -inputs exist. - -- **Cross-KPI surfacing** needs the Funnel map and its north-star campaign or stage. -- **Click-to-conversion diagnosis** needs the Funnel map and landing page context. -- **Metric-gotcha handling** needs field 3. - -If an input field is `[FLAGGED]`, say plainly that its derived capability is off until the input -is captured. - ---- - -# Context health check - -Once fields are filled, run these as a suite, instantiated with the account's real events, -campaigns, and names. Each is the acceptance test for its field. A failed answer points straight -back to the field that is wrong or missing. - -1. Sources of truth: "What was our cost per [north-star event] last month, and which source is that from?" -2. Conversion events: "What are our best-performing ads right now?" -3. Metric gotchas: "What's our ROAS on [campaign]?" -4. Naming conventions: "What's our best-performing messaging angle across the account?" -5. Attribution: "How many demos did we book from ads last month?" -6. Account structure: "Which ad sets should we consider cutting?" -7. Funnel map: "This Form Fallback ad, is it pulling anything real beyond leads?" -8. Creative metrics: "Is this video's hook working?" -9. Targets and thresholds: "Is this ad a winner yet?" - -## Overall status - -- Fields confirmed: `` / 9 -- Flagged fields needing the customer: `` -- Written to: `/agent/brain/meta/account-context.md` -- Indexed in `/agent/INDEX.md`: `` -- Guard merged into `/agent/user.md`: `` diff --git a/aligned-onboarding/creative-corpus-playbook.md b/aligned-onboarding/creative-corpus-playbook.md deleted file mode 100755 index dc77df04..00000000 --- a/aligned-onboarding/creative-corpus-playbook.md +++ /dev/null @@ -1,312 +0,0 @@ -# Meta Creative Corpus Playbook (Onboarding Package) - -**How Runneth builds and maintains the per-creative attribute corpus for a Meta account, -using the Account Context Brain it already has.** - -This is the creative-attributes part of the Meta onboarding package. It pairs with the -**Meta Account Context Brain** (`/agent/brain/meta/account-context.md`). - -The one-line model: - -> The **Account Context Brain** tells Runneth **how to analyze** the account. The **Creative -> Corpus** gives Runneth **the attributes it needs to actually do the job**: one enriched record -> per active creative. - -The Creative Corpus depends on the Account Context Brain for interpretation and does not -re-derive it. It only pulls from Motion what the Account Context Brain cannot already tell it: the -creative content itself. - ---- - -## What this is - -The output is: - -- **Individual creative Markdown files**, one per active creative, with identity, summary, hook, - value props, transcript, AI tags, and naming. -- An optional thin **tagging taxonomy** file, only if the Account Context Brain has a decoded - naming convention to - project. -- These files are automatically retrievable through **Knoweth**. There is no separate corpus - index to build. - -## How retrieval works here (Knoweth first, corpus-search to supplement) - -Runneth already has Knoweth, its local retrieval layer. Any Markdown written under -`/agent/brain/` in a readable lane is automatically chunked, indexed, and surfaced as -pre-context in future turns. Knoweth is the default and needs no setup: - -- Writing the file under `/agent/brain/meta/creatives/` is the index step. No manual `index`, - `embed`, or `refresh` needed for Knoweth to surface it. -- To confirm a file is discoverable, reference its topic in a later turn, or list the folder. -- Use `ContextConfig` only if these files need a specific lane (for example a workspace lane). - -**corpus-search supplements Knoweth** for this package. It ships alongside (see the README for -install) and is the right tool when you need structured, filterable search over the creative files: -by `kind`, brand, field, or a specific intent across the whole corpus, rather than the automatic -pre-context Knoweth surfaces. Knoweth stays the default for everyday recall; reach for corpus-search -when you need to query the corpus deliberately. corpus-search requires its own index step (below); -Knoweth does not. - ---- - -## Step 1 - Read what the Account Context Brain already knows (do not re-derive) - -Open `/agent/brain/meta/account-context.md` first and pull these directly: - -- **Naming conventions** (Account Context Brain field 4): if it has a decoded pattern, use it to decode - each creative's name. If it does not, just store the raw ad name as the attribute and move on. -- **AI tags**: always capture them using Motion's own glossary definitions. The Account Context - Brain governs how - they are used in analysis, not whether the Creative Corpus records them. -- **Workspace and date window**: the target `workspaceId` and the default pull window - (`last_365d` unless the account or the person overrides it), from the Account Context Brain's scope header. -- **Spend thresholds and targets**: used to derive Spend State without a separate threshold fetch. - -If a needed field in the Account Context Brain is `[FLAGGED]` or missing, that is the only case where you gather -it live, and you flag it the same way rather than guessing. - ---- - -## Step 2 - Pull the creative corpus from Motion - -This is the genuinely new data the Account Context Brain does not hold. Use the workspace and window from the Account Context Brain -(default `last_365d`). - -``` -motion meta insights --date-range last_365d --include-glossary --include-metrics --include-transcript --workspace-id -``` - -Inspect the returned file with `jq`: - -- `totalCount` vs `providerTotalCount`: if they differ, the pull is partial. Narrow and re-pull - before treating it as the full set. -- `.creatives[0]`: confirm summaries, hooks, glossaryTags, value props, and `transcript` are - populated. -- `.adsWithoutCreativeAsset`: spend-bearing ads with no synced creative. Skip them for - individual files. - -Always pull `--include-glossary` and capture the tags Motion returns, using Motion's own -definitions. Whether they get surfaced in analysis is the Account Context Brain's call; capturing them is not -conditional. - -**Transcripts.** `--include-transcript` returns `creative.transcript` on the same pull, so one -pass usually gets everything. On a large corpus this can be heavy, and some rows may come back -without a transcript. In that case, do a second scoped pass over the creative asset IDs from -this pull: - -``` -motion meta insights --scope creative-asset-id --creative-asset-id [--creative-asset-id ...] --include-transcript --date-range last_365d --workspace-id -``` - -Only video creatives have a spoken transcript. If a creative returns no transcript, record that -it has none rather than inventing one. - -Note the exact pull date and window. This anchors the "corpus as of" timestamp. - ---- - -## Step 3 - Tagging taxonomy (only if there is something to project) - -If the Account Context Brain has a decoded naming convention, project it into a short reference -file: the naming table (pattern to meaning) plus the standard MD template below. If it has no -naming decode, -skip the naming table entirely; the per-creative files simply carry the raw ad name. - -Do not build elaborate auto-tagging logic. Keep this file to the naming table (if any) and the -template. Save it at: -``` -/agent/brain/meta/creatives/_tagging-taxonomy.md -``` -The underscore keeps it at the top of the folder and signals it is a reference, not a creative. - ---- - -## Step 4 - Generate individual creative MD files (the attributes) - -One file per creative. - -**File naming:** match the ad name exactly, `.md` extension, replace slashes or special -characters with hyphens. - -**Location:** `/agent/brain/meta/creatives/.md` - -**Each file contains:** - -```markdown ---- -title: -brand: -workspace: -source_id: -event_at: -duration_s: