diff --git a/aligned-onboarding/README.md b/aligned-onboarding/README.md index 08a7e54..3a5b4a9 100644 --- a/aligned-onboarding/README.md +++ b/aligned-onboarding/README.md @@ -23,13 +23,15 @@ build found. ## Where the package files live This folder holds one part per subfolder: `meta/` (the Creative Attribution playbook, the -Account Context Brain package, the Meta Validation package, and the Motion CLI Data-Query -Guide) and `voc-data-pull/` (the VoC Data Pull skill, recipes, and templates). This README +Account Context Brain package, the Meta Validation package, the Motion CLI Data-Query +Guide, and the Cacheth Command Reference) and `voc-data-pull/` (the VoC Data Pull skill, recipes, and templates), plus `knoweth/` (the organize-the-brain part that runs after the questions). This README covers all of them; `install-config.json` maps every file to its installed location. These instruction files are the package itself, not its output. They live in the brain outside the `meta` folder structure. The brain's `meta` folder holds only what Runneth -generates from running them: the per-creative attribution files and the filled account context. +generates from running them: the filled account context (which carries the confirmed naming +decode). Per-creative content lives in Cacheth (the local creative cache); nothing in this +package writes it to brain files. --- @@ -40,8 +42,10 @@ generates from running them: the per-creative attribution files and the filled a attribution config as if they do not exist. Everything comes from auto-pulled Meta ad data and customer confirmation. - **One workspace at a time.** Every auto-pull names the account with `--workspace-id `. -- **Attribution files are customer-facing account content.** Only creative facts belong in them. - Never save internal notes, CLI commands, or debugging mechanics. +- **Brain files are customer-facing account content.** Only account facts belong in them. + Never save internal notes, CLI commands, or debugging mechanics. Per-creative content lives + in Cacheth; it goes into a brain file only when a person explicitly asks, as a dated snapshot + (the cache stays the source of truth for current facts). --- @@ -50,18 +54,20 @@ generates from running them: the per-creative attribution files and the filled a ### Creative Attribution File: `meta/meta-creative-attribution-playbook.md` -- **Job:** build and maintain one enriched record per active creative — identity, summary, hook, - value props, transcript, AI tags, naming. The per-creative facts Runneth uses for every analysis - the Account Context Brain defines. -- **Runs first.** Collects facts without interpreting them. Detects naming patterns provisionally - and passes them to the Account Context Brain as pre-filled proposals. -- **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. -- **Staging deployment note:** in staging, per-creative summaries live in **Cacheth** and are - surfaced through **Knoweth**. Never run this playbook automatically: do not auto-pull creatives - and store summary files in the brain. It runs only on an explicit request from a person. +- **Job:** establish the creative content layer — one enriched record per active creative + (identity, summary, hook, value props, transcript, AI tags) held in **Cacheth**, the local + creative cache — and detect naming patterns, passing them to the Account Context Brain as + pre-filled proposals. +- **Runs first.** Collects facts without interpreting them. +- **Persists to:** nothing. The provisional naming decode is a handoff to the Account Context + Brain (Field 4), which owns it once confirmed. **No creative files** — nothing here writes + per-creative content to the brain (Cacheth is the system of record; person-requested snapshot + files are a separate, explicit ask). +- **Retrieval:** Knoweth pre-context injection first (matching creative chunks arrive in the + turn automatically); when that is not enough, the local motion cache CLI + (`motion cache search-summaries`, `motion cache get-creative`). +- **Maintenance:** the cache syncs itself; if the account's naming convention changes, the + decode re-runs and routes through Field 4. ### Account Context Brain File: `meta/meta-account-context-brain-onboarding-package.md` @@ -87,6 +93,18 @@ File: `meta/motion-cli-data-query-guide.md` --- +### Cacheth Command Reference (supporting reference) +File: `meta/cacheth-command-reference.md` + +- **Job:** the canonical contract for querying the local creative cache through the + `motion cache` CLI — all five commands with every flag, the full-record field layout, `jq` + extraction recipes, and the retrieval priority order. The Creative Attribution playbook's + compact contract points here for the detail. +- **Not run on its own.** Reference only, not a step to execute. Brand-agnostic; carries no + account-specific IDs. + +--- + ## VoC Data Pull (separate part, own folder) Folder: `voc-data-pull/` @@ -111,23 +129,28 @@ Folder: `voc-data-pull/` ## Install and run order -1. **Install the package.** Staging the files does not self-run anything. In particular, nothing - in this package may auto-grab creatives and store them in the brain with summaries; in staging, - summaries live in Cacheth and are surfaced through Knoweth. -2. **Creative Attribution (Step 1) — explicit request only.** When a person asks for it, builds - the per-creative attribution files, detects naming patterns, and passes them to the Account - Context Brain as provisional proposals. Never run automatically as part of install or - onboarding. +1. **Install the package.** Staging the files does not self-run anything. Nothing in this + package writes per-creative files to the brain — creative content lives in Cacheth and is + surfaced through Knoweth. +2. **Creative Attribution (Step 1).** Confirms the workspace scope, establishes the creative + content layer (Cacheth + the query paths), detects naming patterns, and passes them to the + Account Context Brain as provisional proposals. Writes nothing per-creative to the brain. 3. **Activate and run the Account Context Brain (Step 2).** Merge the guard block into `/agent/user.md`, then run the fill-in. Confirms how the team judges performance, drawing on the attribution build (if one was requested) for naming proposals and creative evidence. 4. **Set up the VoC data sync (when asked).** For each connected VoC platform, run the voc-data-pull skill's "Set up the recurring sync" procedure - it creates the daily sync routine and kicks the backfill in the background. -5. **Keep everything current.** Creative Attribution maintenance (daily and event-triggered) - applies only where the attribution build was explicitly requested. Account Context Brain on - monthly cadence and structural-drift triggers. VoC data refreshes itself through its daily - routines once set up. +5. **Organize with Knoweth (after the questions are answered).** Once the Account Context Brain is + confirmed and data-source content has landed, organize the brain: keep shared content in the + global lane and make it findable with tags and a naming decoder, and merge both the + `runneth:knoweth-organize` and `runneth:knoweth-brain` guard blocks into /agent/user.md (per the + MERGE INSTRUCTIONS in that doc) so the organize trigger fires and save-routing/maintenance stay on. Do not carve data-source-family or + initiative lanes today; only global, the user lane, and the workspace lane are queried. See + knoweth/knoweth-organize-onboarding-package.md. +6. **Keep everything current.** Creative content stays current through the Cacheth sync + automatically. Account Context Brain on monthly cadence and structural-drift triggers. VoC + data refreshes itself through its daily routines once set up. --- @@ -144,5 +167,5 @@ Folder: `voc-data-pull/` when creatives are discussed. - **Naming decode is the handoff point.** Creative Attribution detects provisional naming patterns from ad names and passes them to the Account Context Brain as proposals. Account Context Brain - confirms or corrects them in Field 4. Once confirmed, the naming decode is re-projected onto - the creative files. + confirms or corrects them in Field 4. Once confirmed, the decode lives in the Account Context + Brain — the single owner — and creative queries decode ad names through it at analysis time. diff --git a/aligned-onboarding/install-config.json b/aligned-onboarding/install-config.json index b3db8b2..5f9129b 100644 --- a/aligned-onboarding/install-config.json +++ b/aligned-onboarding/install-config.json @@ -1,8 +1,8 @@ { "schema": "1.0", "id": "aligned-onboarding", - "version": "2.1.0", - "description": "The Meta onboarding package, v2. Stages five instruction docs into the brain: the package overview, the Creative Attribution playbook, the Account Context Brain onboarding package (v1.21), the Meta Validation onboarding package (v1.1), and the Motion CLI data-query guide. Installing only stages files; nothing self-runs. The Creative Attribution build runs only on an explicit request from a person and must never auto-grab creatives and store summary files in the brain: in staging, per-creative summaries live in Cacheth and are surfaced through Knoweth. No corpus-search dependency. Meta only, one workspace at a time. Also carries the VoC Data Pull part (voc-data-pull/): a skill installed to the skills root that, when setup is requested, creates one daily sync routine per connected VoC platform pulling reviews, support conversations, community posts, and ad comments into /agent/brain/data-sources/voc//. Nothing self-runs.", + "version": "2.3.0", + "description": "The Meta onboarding package, v2. Stages six instruction docs into the brain: the package overview, the Creative Attribution playbook, the Account Context Brain onboarding package (v1.21), the Meta Validation onboarding package (v1.3), the Motion CLI data-query guide, and the Cacheth command reference. Installing only stages files; nothing self-runs. Per-creative content lives in Cacheth (the local creative cache) and is surfaced through Knoweth; nothing in this package writes per-creative files to the brain. No corpus-search dependency. Meta only, one workspace at a time. Also carries the VoC Data Pull part (voc-data-pull/): a skill installed to the skills root that, when setup is requested, creates one daily sync routine per connected VoC platform pulling reviews, support conversations, community posts, and ad comments into /agent/brain/data-sources/voc//. Nothing self-runs. Also carries the Knoweth organize part (knoweth/): after the questions are answered it organizes the brain so retrieval stays tight and sets the standing save + maintenance discipline.", "requires": { "runtime": "any Runneth sandbox", "preinstalled": [], @@ -22,13 +22,13 @@ "from": "README.md", "to": "/agent/brain/aligned-onboarding/README.md", "on_exists": "overwrite", - "purpose": "Package overview: the two parts, their run order, and the staging deployment rule that the Creative Attribution build never runs automatically." + "purpose": "Package overview: the parts, their run order, and the scope rules. Creative content ownership: Cacheth is the system of record; nothing in the package writes per-creative files to the brain." }, { "from": "meta/meta-creative-attribution-playbook.md", "to": "/agent/brain/aligned-onboarding/meta-creative-attribution-playbook.md", "on_exists": "overwrite", - "purpose": "Step 1 (explicit request only): how to build and maintain one enriched Markdown record per active creative under /agent/brain/meta/creatives/. Never auto-run; in staging, creative summaries live in Cacheth and are surfaced through Knoweth." + "purpose": "Step 1: the creative content layer — what Cacheth holds per creative and how to query it (Knoweth pre-context injection first, then the motion cache CLI) — plus provisional naming-pattern detection passed to the Account Context Brain. Writes no per-creative files to the brain." }, { "from": "meta/meta-account-context-brain-onboarding-package.md", @@ -40,7 +40,7 @@ "from": "meta/meta-validation-onboarding-package.md", "to": "/agent/brain/aligned-onboarding/meta-validation-onboarding-package.md", "on_exists": "overwrite", - "purpose": "Step 3: the validation experience (v1.1). Answer-and-confirm loop, weekly deck build, lock-in (deck approval, refresh routine, Slack), and the MVCE gate saved to /agent/brain/meta/validation.md." + "purpose": "Step 3: the validation experience (v1.3). Answer-and-confirm loop with the show-the-work rule, weekly deck build, lock-in (deck approval, refresh routine, Slack), and the MVCE gate saved to /agent/brain/meta/validation.md." }, { "from": "meta/motion-cli-data-query-guide.md", @@ -48,6 +48,12 @@ "on_exists": "overwrite", "purpose": "Supporting reference: the canonical contract for pulling Meta data through the motion CLI. Brand-agnostic, carries no account IDs." }, + { + "from": "meta/cacheth-command-reference.md", + "to": "/agent/brain/aligned-onboarding/cacheth-command-reference.md", + "on_exists": "overwrite", + "purpose": "Supporting reference: the canonical contract for querying the local creative cache (Cacheth) through the motion cache CLI. All five commands with every flag, the full-record field layout, jq extraction recipes, and the retrieval priority order. Reference only, not a step to execute. Brand-agnostic, carries no account IDs." + }, { "from": "voc-data-pull/SKILL.md", "to": "/agent/.agents/skills/voc-data-pull/SKILL.md", @@ -83,9 +89,27 @@ "to": "/agent/.agents/skills/voc-data-pull/templates/community-post.md", "on_exists": "overwrite", "purpose": "Copyable file skeleton for community-post output files." + }, + { + "from": "knoweth/knoweth-organize-onboarding-package.md", + "to": "/agent/brain/aligned-onboarding/knoweth-organize-onboarding-package.md", + "on_exists": "overwrite", + "purpose": "Knoweth organize part: after the account questions are answered, organize the brain (keep shared content in the global lane, make it findable with tags + a naming decoder) and set the standing save + maintenance guard blocks. Today only global, the user lane, and the workspace lane are queried; data-source-family lanes are a documented forward path." } ], "changelog": [ + { + "version": "2.3.0", + "date": "2026-07-24", + "type": "minor", + "notes": "Removed the per-creative-files model everywhere: creative content lives in Cacheth (the local creative cache) and is queried via Knoweth pre-context injection first, then the motion cache CLI (search-summaries / get-creative; local, no API call). The Creative Attribution playbook is now the creative-content-layer contract plus naming decode. Validation gates on cache coverage instead of files under /agent/brain/meta/creatives/. The naming decode is a handoff, not an artifact: detected provisionally in Step 1 and folded into account-context.md (Field 4) on confirmation — no separate taxonomy file. Performance metrics are pulled live via the motion CLI, never stored. Staged the Cacheth Command Reference (meta/cacheth-command-reference.md) beside the Data-Query Guide as the flag-level contract for the motion cache CLI." + }, + { + "version": "2.2.0", + "date": "2026-07-23", + "type": "minor", + "notes": "Added the Knoweth organize part (knoweth/): after the account questions are answered, organize the brain so retrieval stays tight, plus a standing save + maintenance contract. Grounded in the real retrieval wiring - only global, user:, and project: (the workspace) are queried today, so shared content stays in the global lane and is sliced by tags; data-source-family lanes are a documented forward path gated on a harness change, not shipped." + }, { "version": "2.1.0", "date": "2026-07-23", diff --git a/aligned-onboarding/knoweth/knoweth-organize-onboarding-package.md b/aligned-onboarding/knoweth/knoweth-organize-onboarding-package.md new file mode 100644 index 0000000..95a2874 --- /dev/null +++ b/aligned-onboarding/knoweth/knoweth-organize-onboarding-package.md @@ -0,0 +1,372 @@ +# Runneth Brain + Knoweth: Setup and Maintenance (Onboarding Package) + +### Version 1.0 (July 2026) + +**How Runneth organizes the brain so retrieval stays tight and the org stays understood as it grows: lanes over the content onboarding produced, plus the standing save and maintenance discipline that keeps it that way.** + +The one-line model: + +> The data packages (VoC Data Pull, Meta Creative Attribution + Account Context) put **content** in the brain. **Knoweth** puts **structure** over it: lanes and projects that gate retrieval, a save contract so new writes land right, and a maintenance loop so weeks of human edits do not rot it. Knoweth runs after the content and the confirmed interpretation exist, then holds going forward. + +This part is **cross-cutting**. Unlike the Meta-only parts, it spans every data-source family on the VM (VoC, asset library, Meta, and any others) and every future write. It reflects the live packages (VoC Data Pull under `data-sources/voc/`, Aligned Onboarding v2 under `/agent/brain/meta/`) and the Cacheth creative store; the two roots are reconciled by the lane -> path map below, not by moving files. + +--- + +## How this activates and where it sits in onboarding + +This is the last setup step of the combined run and the first line of ongoing maintenance. Installing only stages this file; it does not self-run. It activates the same way as the other parts: when a person runs the package (the README run order), merge the two guard blocks below into `/agent/user.md`, then the triggers fire. + +**MERGE INSTRUCTIONS:** For each block, if its sentinel (`runneth:knoweth-organize` or `runneth:knoweth-brain`) already exists in `/agent/user.md`, replace it in place. Otherwise append it. Never duplicate. Do not edit anything outside the sentinels. + +**Guard 1 — organize the brain (runs once, after the questions are answered).** + +``` + +Knoweth organize (after the questions are answered): +- Organize the brain when all three gates hold; do not wait to be asked: + (1) the account interpretation is [CONFIRMED] (/agent/brain/meta/account-context.md signed off); + (2) content has landed: the voc-sync- backfill reports full date-window coverage (not + just files existing), and creatives are in Cacheth; + (3) /agent/brain/_tag-vocabulary.md does not exist - writing it is the organize step's last act, + so its existence means done; update the file instead of re-running. +- TODAY only three lanes are searched: global, user:, and project: (the + workspace). Keep all shared content in the global lane (the brain root default) and make it findable + with tags/attributes and a naming decoder. Do NOT carve data-source-family or initiative lanes + (voc, meta, campaign, ...): those lanes are not queried yet, so the content would go dark. Use a + user: lane only for genuine per-person isolation. The workspace lane is automatic. +- Detect single- vs multi-workspace first: a single-workspace org is all global + tags; a multi-workspace org relies on the automatic per-workspace lane and puts shared knowledge in global. Do not carve custom lanes either way. +- Do not organize an empty brain. If content has not landed, say what is missing and route back. +- Finish by writing the tag vocabulary + naming decoder to /agent/brain/_tag-vocabulary.md (gate 3's + done-marker) and noting it in /agent/brain/_changelog.md. When the harness starts layering + configured lanes (see the forward path), promote high-value tags to family lanes then, not before. + +``` + +**Guard 2 — standing save and maintenance contract (always on).** + +``` + +Knoweth brain discipline (all writes, going forward): +- On every save (from a pull, a conversation, or an upload), route it: raw vs compiled vs spec; the + data-source family folder (voc -> data-sources/voc/**, meta -> /agent/brain/meta/**); tags/attributes + and provenance. Keep it in the global lane so it is searchable today; the folder is for human + navigation, not a lane. Cacheth is the system of record for per-creative content: write a + per-creative file only when a person explicitly asks, and treat it as a dated snapshot (the + cache stays the retrieval source of truth for current facts). Performance metrics are pulled + live via the motion CLI, never saved. +- Keep compiled pages in sync with raw: new evidence restales and regenerates the dependent page; a + correction updates the compiled page (never raw) and propagates. Curate, do not append: merge into + the existing page rather than spawning a duplicate. +- Adopt stray human-added files (classify and tag, or flag) without moving the human's folders. + Default new dimensions to tags, not lanes; only user: isolation and the automatic workspace lane + are real lanes today. +- Keep one brain-maintenance routine: run `routine list --search "brain-maintenance"`; if absent, + create it (a scheduled sweep for stray/untagged files, duplicates, stale pages, and retention + candidates; per-creative files in the brain exist only by a person's explicit ask - if the + sweep finds ones of unknown provenance, ask the person before archiving, never silently move + or delete them) and never run the sweep in-conversation. + +``` + +### Activation checklist (verify it actually fired) +Because this activates by a run following the README rather than by an automatic trigger, verify it landed: +1. Both sentinels `runneth:knoweth-organize` and `runneth:knoweth-brain` are present in `/agent/user.md`. +2. The organize step ran: `/agent/brain/_tag-vocabulary.md` exists (the tag vocabulary + naming decoder, and the durable done-marker) and is noted in `/agent/brain/_changelog.md`. +3. The `brain-maintenance` routine exists (`routine list --search "brain-maintenance"`). +If any is missing, activation is incomplete; finish it before calling the package done. + +### Prerequisites (hard gate) +Do not set up lanes until Guard 1's gates 1 and 2 hold: the account interpretation is `[CONFIRMED]`, and content has landed complete (the VoC backfill reports full date-window coverage - a mid-backfill folder has files but has not "landed"). Lanes describe what is actually in the brain, so laning before content produces empty or wrong scopes. If either is missing, say what is missing and route back; never fake it. + +### Scope +Cross-cutting: every data-source family and every future write, not one platform. The per-source packages own their own folder conventions and how-to docs; Knoweth owns the layer above them (lanes, the retrieval contract, save routing, maintenance) and the **lane -> path map** that names each family's real root. One owner per fact; Knoweth points down to the source packages rather than restating their paths. + +### Persistence +The durable artifacts are the tag vocabulary + naming decoder at `/agent/brain/_tag-vocabulary.md` (also the organize done-marker) plus the two `/agent/user.md` guard blocks above; the Knoweth lane config only carries what is actually queried today (global, user isolation, the automatic workspace lane). Index this doc in `/agent/INDEX.md` (aliases: knoweth, lanes, retrieval, save routing, brain maintenance) with a one-line note. + +### Where it sits in the combined run +The run order is owned by the package README ("Install and run order", at `/agent/brain/aligned-onboarding/README.md` beside this doc); this part is its organize step. The sequence is deliberately not restated here - Guard 1 fires on its gates, not on a step number, and sequencing changes go in the README. + +**How to read this.** The method is the standard and the contents are decided. The structure, schemas, procedures, and rules below are the same on every VM. What you fill in is decided per brand: which segments, products, metrics, personas, naming, and sources exist all come from that brand's own data and needs. Follow the method exactly; decide the contents from the brand. Where a rule depends on a platform detail that can change (a capacity limit, the config format), verify it against the live configuration. + +--- + +## 1. The two-layer brain: raw and compiled +Knowledge has two layers and flows one way. +- **raw = evidence.** Source material, never rewritten in substance. It lives in one of two places: as **brain files** under `data-sources//...` (file conventions owned by the family's own package - for VoC that is the voc-data-pull skill; the folders are for navigation, and today all of it sits in the `global` lane), or in a **harness-backed store** when the platform has one. Meta creative content lives in a harness-backed store: per-creative summaries (identity, summary, hook, transcript, AI tags, naming) in **Cacheth**, surfaced through Knoweth. Performance metrics are not stored at all - they are pulled live through the `motion` CLI (the Motion CLI Data-Query Guide is the contract). Nothing in the package writes per-creative files to the brain; the brain-side Meta layer is interpretation only (`account-context.md`, which carries the confirmed naming decode). A per-creative file appears in the brain only when a person explicitly asked for one — a dated snapshot, with the cache the retrieval source of truth for current facts. +- **compiled = understanding.** Agent-maintained to a schema: the interpretation specs and the synthesized analysis (segments, personas, performance reads). The human corrects it in conversation, never hand-edits it. The agent may create, rewrite, merge, and delete compiled pages within the schema. +- **One-way flow: raw to compiled, never back.** Evidence is the source of truth; a compiled page is the current understanding of it. When they disagree, fix the compiled page, not the evidence. +- **Curate, do not just append.** Merge duplicates, delete dead pages. + +Both layers are the agent's to manage; the one-way flow and never-rewrite-raw discipline are behavioral, enforced by Runneth (see section 12), not by separate storage. + +--- + +## 2. How Knoweth retrieves (grounded in the Knoweth service) +Knoweth is a Rust resolver that indexes approved brain roots into SQLite + a Tantivy lexical index + optional OpenAI embedding vectors, and answers `/resolve` with ranked chunks (not whole files), each carrying its metadata. It watches roots and reindexes on change. One store is NOT indexed by Knoweth: **Cacheth** (creative asset/summary/AI tags/transcript); anything living only there is not Knoweth-searchable. Performance metrics are not stored anywhere - they are pulled live via the `motion` CLI. + +Per query, in order: +1. **Lane ACL gate (hard).** Lanes are hard namespaces (`lane_id`): `global`, `user:`, `project:`, or a family/domain lane. A request carries `user_id`, `project_id`, and requested `lanes.read`; Knoweth intersects them with the `[policy]` grants and searches only authorized lanes. **In the current harness the requested read set is exactly `[user:, project:, global]` with `project_id = `, so today only the global lane, the caller's user lane, and the workspace lane are searched** (verified against agent-builder's `resolveKnowethReadLanes`). Custom family lanes (`voc`, `meta`, ...) are never requested and never searched; the brain root defaults to `global`, so everything in the brain is found, and carving a sub-lane would move it out of `global` and hide it. +2. **Three candidate channels inside the authorized lanes:** lexical BM25 (Tantivy, boosting title, heading path, **tag**, exact phrase, path, body, with exact symbol/path/filename matches protected); graph expansion (document/import/path-twin neighbors); and adaptive dense (one query embedding vs cached chunk vectors, used when lexical/exact confidence is low, `use_dense_when_confidence_below` ~0.72). +3. **Exact-preserving RRF fusion** merges the three, then an **intent-aware packer** assembles the context (exact-lookup vs summary vs procedural vs comparison packing, with document focus). + +Two consequences drive everything below. **Tags/attributes are a ranking signal, not a gate:** they boost lexical rank and feed the embedding input, but never scope the search; only the lane ACL scopes. So keep vocabulary consistent, keep a naming decoder, and put the words a question will use into the file. Terminology: what earlier notes called a "facet" is not a Knoweth primitive. The real levers are **lanes/projects** (the ACL gate) and **attributes/tags** (a ranking signal in the text). + +### The answer standard: route by where the evidence lives, then combine +Every onboarding/validation question resolves to one of two evidence homes; classify first, then combine the mechanisms. +- **Knoweth-indexed (brain files):** VoC (`data-sources/voc/**`), the Meta interpretation layer (`meta/account-context.md`, which carries the confirmed naming decode), and asset-library. Answered directly: lane gate + lexical (tags/keywords) + dense. +- **Store- or CLI-backed (not in Knoweth):** Meta creative content (summary, AI tags, transcript) in **Cacheth**; performance metrics via live `motion` CLI pulls (per the Motion CLI Data-Query Guide). Answered by those query paths, with Knoweth supplying only the interpretation lane. + +In every join below, the winner metric and all interpretation come from `account-context.md` (per the account-context guard); Motion workspace settings the CLI can return (workspace goal, preferred KPI, spend threshold) are never used as interpretation. + +Two rules before applying any filter: +- **Read the naming decode first.** Before filtering by campaign, ad set, or ad name, read the account's naming conventions (`account-context.md`, Field 4) and filter on the decoded meaning, not a guessed substring. +- **Match the signal to the question.** Structural questions (funnel stage, audience, product mapping, campaign role) filter on campaign/ad-set names through the decode. Creative questions (format, hook type, content type, angle) use Cacheth tags and content — ad names may not encode any of that. When both carry the signal (e.g. a funnel stage encoded in the name and tagged in the summary), cross-check them; when they disagree, say so instead of picking one silently. + +Routing by question type: +- "What are 1-star reviewers saying about Product A?" -> `voc` lane; lexical on rating/product/segment terms + dense; agent-side filter. Pure Knoweth. +- "Campaign names / account structure / naming / what the data means to us" -> `meta` lane: `account-context.md` (including the confirmed naming decode). Pure Knoweth. +- "Top winning ads this week" -> motion CLI (rank by the account's winner metric + spend floor) + Cacheth (creative identity) + `meta` account-context (what "winner" means). A join; Knoweth is the interpretation, not the data. +- "Performance by campaign / product" -> motion CLI + `meta` naming decode (which campaigns map to which product). +- "Themes in winning ads (from AI tags + summaries)" -> motion CLI (winners) + Cacheth (AI tags/summaries) + `meta` account-context (winner def). AI tags live in Cacheth, not the Knoweth index - route tag/theme questions through Cacheth; do not expect Knoweth's index to contain them. +- "What are we testing / scaling / graduating" -> motion CLI (spend state) + `meta` account-context (the graduation rule, still a flagged/needed field). +- "Why are our winners working / why do customers respond" -> motion CLI (what is winning) + Cacheth (what the creative says and shows) + `voc` (why customers respond: reviews, support themes) - and ad comments (`data-sources/voc//`) connect performance and customer voice on the same creatives in near-real time. Treat performance and VoC as one system: performance shows what is winning, VoC explains why. + +**Show the work.** Any answer that ranked, filtered, or interpreted states in plain language: which filter it applied (and the decode behind it), which signal it read (names, tags, transcript, reviews - and when freshness matters, how fresh: Cacheth records carry per-layer hydration timestamps), and what it could not confirm. One plain sentence alongside the answer, not a template. Never deliver a bare number that hides a judgment call. + +### Why some data is not indexed in Knoweth +Everything the agent needs is reachable; the question is where it is stored, not whether it can be used. Knoweth indexes the **brain files** (VoC, the interpretation layer, specs, asset metadata) so they are searchable by meaning and keyword. The **creative store (Cacheth)** is a large, structured, frequently-updated dataset with its own query path, and **performance metrics** are live platform data behind the `motion` CLI; both are reached through those query paths (and, under Knoweth, alongside brain results), not copied into the search index. Duplicating them into files would bloat the index, split the source of truth, and go stale. So a creative or metric is "not in Knoweth" the same way a database is not in a wiki: the wiki points at it. Write the interpretation (what a creative means, how a metric is judged) as a brain file; leave the creative in its store and pull the number live. + +### Works with or without Knoweth +The organizing discipline here, folders, tags, save routing, specs, and maintenance, is retrieval-agnostic: it holds whether or not Knoweth is the retrieval layer on a given VM. Only the lane configuration is Knoweth-specific. Retrieval scoping (lanes and projects) becomes fully live as the Knoweth harness rolls out; until a VM is on it, the safe default that works on any harness is to keep shared content in `global` and slice with tags. A parallel version of this package without Knoweth reuses everything except the lane config, so keep the two separable: never write a file that only makes sense if lanes are active. Setting up before the Knoweth harness reaches a VM is fine: organizing, tags, save routing, specs, and maintenance all work regardless of harness; only lane/project scoping (including the automatic workspace lane) becomes fully live once the harness reaches the VM. Never block setup on it or promise lane behavior that is not on yet, `global` + tags is correct either way. + +--- + +## 3. The two organization layers: folders vs the retrieval overlay +- **Folders = the human layer.** The visible, editable brain tree; the customer's map. They reorganize it freely. Optimize for human sense-making. Caveat: not everything retrievable is visible here. Harness-backed lanes (meta creatives in Cacheth) have no files in the tree, so the human-facing view is the folder tree plus the agent or a source-of-truth dashboard for those lanes. +- **Lanes and projects = the retrieval overlay.** Agent-owned, optimized for retrieval. Coupled to folders via glob patterns, but many-to-many (one folder can feed several projects; one project can span folders). Under the hood both are the same primitive, a `lane_id` (`global`, `user:`, `project:`, or a family/domain lane); a request layers several (e.g. `["meta","project:css-2026","global"]`) and `[policy]` grants keyed by `user_id`/`project_id` decide which are readable. So a "project" is a lane by convention, and user/team separation means `user:`/`team:` lanes plus grants, not a different mechanism. File metadata is not itself a Knoweth query filter (see section 5). + +**How folders affect lanes.** Today they mostly do not: all shared brain content sits in the `global` lane regardless of folder, so reorganizing folders never changes retrieval scope. Folders are the human's navigation map. (Forward path: once the harness layers configured lanes, a family folder could back a family lane via `[[lane_assignments]]`; until then keep everything in `global` and slice with tags.) Knock-on effects that still hold: save-routing must write into the right family folder and tag it, or a file is mis-tagged; existing-org repair must re-home stray files and backfill tags; and any routine or app that reads the brain by path breaks if folders move, so treat the folder layout as stable. + +--- + +## 4. The canonical Knoweth config rule +**What is queryable today (the hard constraint).** The harness requests exactly three lanes: `global`, `user:`, and `project:` (the workspace). Family/business/initiative lanes are not requested, so they are not searched. Therefore: +1. **Default all shared content to the `global` lane** (the brain root default) and make it findable with **tags/attributes + a naming decoder**. Tags are the working slicer. Do not carve data-source-family lanes (`voc`, `meta`, `asset-library`) or initiative lanes (`project:css-2026`) on a live VM today: a `[[lane_assignments]]` glob would move that content out of `global` and it would go dark. `project` is the workspace, not an arbitrary initiative, so a campaign/initiative is a **tag**, not a project lane. Multi-workspace orgs (agencies) get per-workspace separation for free via `project:`. +2. **Use a real lane only for what is actually gated today:** `user:` lanes for genuine per-person isolation, and the automatic workspace lane. Everything finer (segment, product, campaign, rating, angle, hook) is a tag, resolved by keyword/dense ranking plus agent-side filtering. Put those words in the file so they are findable. +3. **Forward path (design for it, do not ship it yet).** The family-lane scheme (a lane per data-source family, plus a few earned business lanes) becomes viable only when the harness layers configured lanes into the requested read set. Until that ships, family lanes stay as tags in `global`. The dependency is concrete: agent-builder's lane resolution (`resolveKnowethReadLanes` in `apps/agent/src/harness/harneth/harneth-harness.ts`) requests exactly `[user:, project:, global]` today and must learn to layer configured lanes (tracked as PDEC-9225). When it lands, promote the high-value tags to family lanes via `[[lane_assignments]]`, keep the set small and under the cap (over-laning, e.g. a lane per platform or per workstream, is the usual way to blow the cap), and update the config then. +4. **Folders = the human's navigable tree.** Folders are for human sense-making, not lanes today (the lane is `global` regardless of folder). Reorganizing folders is safe; it does not change retrieval scope. + +### Allocating new content (tag -> project -> lane) +When new content or a new dimension shows up, allocate it in this order, proactively (not driven by where a file happened to land): +- **Tag it (default).** A slice of existing content (rating, segment, product, campaign, angle) stays in `global` and gets a tag. Costs nothing, always discoverable, gives the "slice inside a lane" behavior. Most new things land here. +- **Project = workspace (automatic).** Do not hand-carve project lanes; the only project lane queried is the workspace. Multi-workspace separation is free. +- **Lane (rare).** Only for genuine read isolation (`user:` per-person; a client lane in a future multi-tenant setup). Today only `user:` isolation is wired. +- **Propose, do not silently create.** If a tag is asked for constantly or the org clearly works in bounded initiatives, propose promoting it (to a family lane once the harness supports it, or a documented tag convention now). Keep a written allocation policy so new content is classified consistently over time. + +### How and when lanes get set up (users and workspaces) +Lanes are not something the setup hand-builds for most orgs. What happens automatically: every request already carries the caller's `user:` lane and the `project:` lane for the workspace it runs in, layered with `global`. So: +- **`global`** is set up by default (the brain root); shared org content lives here and needs no lane work. +- **The workspace lane (`project:`)** is automatic per workspace. You do not create it; content saved while working a workspace is scoped to it. This is how a multi-workspace org gets per-workspace separation for free. +- **A `user:` lane** is only set up when there is genuinely per-person private content or a person-level isolation need. You populate it by assigning that person's content to their user lane (by path or tag) and granting it to their `user_id`; most single-brand orgs never need one. +- **Custom lanes** (a data-source family, a client, a business area) are the forward path only; they are not queried today, so do not create them now. +The scenario test: shared across the org -> `global`; belongs to one workspace -> the workspace lane already holds it; one person's private material -> a `user:` lane; anything finer -> a tag. + +### Adapting to the org type: single-brand vs multi-workspace +Step zero of organizing: read how many workspaces the org has, then follow the matching path. Orgs differ, and the setup should read which kind it is rather than assume. Most orgs run a single workspace; a smaller number (agencies and large teams) run many, and those multi-workspace orgs generate a large share of real usage. Adapt: +- **Single-workspace org:** the workspace is the whole brand. Everything is `global` plus the automatic workspace lane; tags do all the slicing. Do not invent projects or lanes, there is nothing to separate. +- **Multi-workspace org (agency, large team):** each workspace is already its own `project:` lane, so per-client/per-brand separation is automatic. Put shared, reusable knowledge (playbooks, templates, cross-client conventions) in `global` so every workspace can reach it, and let each workspace's own content stay in its workspace lane. Do not carve custom per-client lanes; that duplicates what the workspace lane already does and burns the cap. +This is what "a project inside a lane" means in practice: a query layers `[user, project:, global]`, so a workspace's content sits inside the org-wide `global` context at query time. The workspace is the one business dimension that maps to a project today; every other dimension (segment, product, campaign) is a tag inside that scope, not its own project or lane. + +### Slices the config must make easy +For `voc`: by star rating, by tag, by segment/persona, by emerging segment, by keyword, by quote. For `meta`: by campaign, by the account's KPI, and by decoded angle/hook/format via the naming decoder. These are not structured filters; they resolve by keyword search on the facet text plus agent-side filtering of returned files, so put the facet words in the file (header and body) to make the slices findable. + +### Isolation vs retrieval scoping +A lane is the only hard boundary. Today a single brand needs no isolation lanes at all (everything sits in `global`); an agency gets per-client separation for free from the automatic `project:` lane. Reserve a `user:` lane only for genuine per-person isolation. + +### Default skeleton (guaranteed on every VM, the contract Knoweth defaults against) +``` +/agent/brain/ + data-sources/ # raw evidence; folders for navigation (all in the global lane today) + voc// # items only, id-keyed; format owned by the voc-data-pull skill. + # No non-item files (the sync's window checks read this folder) + voc/-context.md # compiled VoC analysis (segments, personas, keywords, quotes) + # - beside the item folders, never inside them + asset-library//file-.md # creative/asset files; another data-source family (lane) + meta/ # meta lane (today under /agent/brain/meta/, NOT data-sources/) + account-context.md # compiled interpretation (9 fields incl. the confirmed naming decode + # + spend-confidence floor) + _changelog.md + # per-creative content lives in Cacheth, surfaced via Knoweth - + # brain files only as person-requested snapshots; performance is + # pulled live via the motion CLI + integrations// # source guide specs; raw dumps forbidden here [not indexed] + team/.md team/user-map.json +/agent/INDEX.md +``` +### Declaring the config (real format, from the Knoweth service) +Knoweth reads a TOML config (`version = 2`). The pieces that matter for lanes/projects: +- `[[roots]]` with `lane_id` + `path` sets a root's default lane (a `voc` root defaults every file under it to the `voc` lane). +- `[[lane_assignments]]` override the lane for a root-relative path glob, last match wins (e.g. `css-2026/**` -> `project:css-2026`). This is how a project or business lane is carved out of a tree. +- `[policy]` with `default_read_lanes` and `[[policy.lane_grants]]` keyed by `user_id` and/or `project_id` (each `read = [lanes...]`, optional `write`) is the ACL: it decides which layered lanes a request can read. User/team separation lives here (grant `user:alice` only to `user_id = "alice"`). +- `[embeddings]`, `[hybrid]`, `[resolver]` tune the search channels (checked-in default is guarded OpenAI hybrid: lexical + graph + adaptive dense, fused with RRF). +The lane count matters because every authorized lane is scored per query; keep the set small (verify the cap). **Caveat: today only `global`, `user:`, and `project:` are in the requested read set, so `[[lane_assignments]]` that create family/initiative lanes are forward-path only, using them now hides content.** Keep content in `global` plus tags until the harness layers configured lanes. The skeleton plus the metadata/tag conventions are the content the config's roots/assignments are generated from. Note the repo is migrating to the OS package format (`package.json` schema-v1, targets under `agent_brain`/`agent_skills`/`agent_tools`/`agent_apps`); the Knoweth package registers there. + +--- + +## 5. File metadata (findability and provenance, not a filter) +File metadata is **not a Knoweth query filter.** Retrieval runs on lane (today `global`, `user:`, and the workspace) plus lexical/dense search over the text - and metadata is text, wherever it sits in the file. It earns its place for four things only: lexical findability (facet words become searchable text), provenance (`sources` cite the exact raw file), chunk-standalone context (a chunk is retrieved without its neighbors), and agent-side filtering of returned files. Keep it lean and do not restate what the path or config already encode. + +**Raw VoC files: the format is owned by the voc-data-pull skill (`/agent/.agents/skills/voc-data-pull/SKILL.md`) - never add front-matter to them.** Their metadata block sits at the bottom of the file; it is text, so Knoweth searches it exactly as it would a yaml header. Do not convert, duplicate, or extend it. Facet vocabulary the unified record does not carry (segment/persona assignments, brand tags, decoded product names) belongs in the compiled VoC analysis pages that cite the raw items, never injected into raw files. + +**Compiled pages (analysis, spec) - the front-matter this doc owns:** `page_type: compiled | spec`, `substance: facts | interpretation`, `sources: [...]` citing raw, `last_compiled`, `confidence`, and `tags: [, segment-, product-, ...]` (searchable facets, not structured filters). `lane:` / `project:` keys are forward-path tags only - today content sits in the `global` lane and they bite only once the harness layers configured lanes. Meta interpretation pages point at the Cacheth creative and the campaign KPI rather than embedding creative data. + +--- + +## 6. Save routing and refresh +On new information, decide in order: +1. **Evidence with no harness store** (VoC item, asset file, transcript, note) -> the family's own file contract: VoC items follow the voc-data-pull skill (id-keyed files under `data-sources/voc//`, written by the sync routine, not ad hoc); other families use `data-sources///-.md` (e.g. `data-sources/asset-library//file-.md`). Append/overwrite by id (idempotent), never rewrite substance, indexed. +2. **Meta creatives** -> Cacheth, surfaced via Knoweth; performance metrics are pulled live via the motion CLI, never saved. A per-creative brain file is written only on a person's explicit ask, as a dated snapshot; the cache stays the retrieval source of truth for current facts. +3. **Compiled understanding** (segments, personas, performance read, a fact) -> the matching compiled page; merge/rewrite, cite raw, follow the schema. +4. **How-to-read a source/metric/dashboard** -> a spec in `integrations/` (reference, unindexed). +5. **Preference or standing instruction** -> `team/`. **One-off scratch** -> do not persist. +Enforce one-way flow; regenerate a compiled page from evidence when corrected, never hand-patch; update the index on durable saves. + +**Refresh and cost.** The raw pull becomes a deterministic script (cheap, near-free). The agentic analysis on top (compiling segments/personas/reads) is the expensive step. Set cadence deliberately and, ideally, with CSM/user input; do not silently ship an expensive recurring routine a customer does not know about. Bounded pulls (a trailing window, server-side date bounds where available) keep both cost and index size in check; archive raw past `retain_until` once its facts are compiled and cited. + +--- + +## 7. Deciding the structure for a brand +Today all shared content lives in the `global` lane, so what the agent decides per brand is the **tag vocabulary and the naming decoder**: which segments/personas exist, which products and campaigns to tag, the account's real KPI, and the words each question will use. Method: +1. List the real questions the team asks (from data, routines, interview answers). +2. Tag each by the dimension it scopes on (segment, product, campaign, rating, funnel stage). +3. Make every recurring dimension a **tag/attribute** with a consistent name, recorded in the naming decoder. Note the dimensions asked for constantly as **candidates for a future family lane** (forward path); do not carve a lane now. +4. Read the human's folders as a signal of what matters, and complement rather than mirror them. + +The costly-to-reverse decision is the lane set; that is exactly why the default is tags (which re-tag cheaply) and why family lanes wait for the harness change rather than being carved on day one. Stay minimal: `global` + tags now, `user:` lanes only for real isolation, the workspace project lane automatic. + +--- + +## 8. Standard specs: what they are and how to set them up +A **Standard spec** is a canonical, triggerable setup for one capability, stood up the same way on every VM: the raw ingestion contract, the compiled schema, the questions to ask the human, and the validation. Three initial Standards: +- **Meta (Aligned Onboarding v2, three steps).** Step 1 Creative Attribution: one enriched record per active creative (identity, summary, hook, transcript, AI tags, naming) held in Cacheth and surfaced via Knoweth, with performance pulled live via the motion CLI (the Motion CLI Data-Query Guide, installed beside this doc, is the query contract); no per-creative files are written to the brain. Step 2 Account Context Brain (`/agent/brain/meta/account-context.md`): the interpretation layer, nine fields, with naming decode confirmed as the handoff from Step 1 and the mandatory spend-confidence-floor ask. Step 3 Validation: the answer-and-confirm loop, the weekly deck, and the MVCE (minimum viable context engine) gate. Ask the human the account idiosyncrasies platform settings cannot capture: the real success metric, which conversion event judges winners and whether products roll up, attribution windows, the cut rule, per-campaign KPI differences, naming clarifications. Validate: performance questions answer with numbers that reconcile to source. +- **Voice of Customer.** Raw is owned end-to-end by the voc-data-pull skill at `/agent/.agents/skills/voc-data-pull/SKILL.md` (folder convention, file format, unified metadata record, PII rules, sync routine). Compiled is the analysis layer (`data-sources/voc/-context.md`, beside the platform item folders, never inside them): segments, emerging segments, keywords, quotes, personas, each tracing to items. Ask the human: canonical sources, which personas are established vs aspirational, off-limits claims. Validate: every claim traces to a real verbatim. +- **Brain and Knoweth setup (this document).** Raw is the connected-data probe; compiled is the org-understanding page plus the specs; it lays the seeded skeleton and the default overlay. + +The spec files are short reference pages the human fills in with the agent's help. Fill-in loop: connect the data, teach the agent the idiosyncrasies, visualize to validate, confirm against the question set. + +**The standard-spec shape, in more detail.** A spec is a short, load-bearing definition of one capability that Runneth is trained to recognize and the customer fills in with content, not structure. It has four parts: the raw ingestion contract (what lands, where, in what file shape), the compiled schema (what the interpretation page looks like), the questions to ask the human (the idiosyncrasies platform data cannot capture), and the validation (how you know it is right). The same shape backs the other durable primitives the org builds on, a dashboard, a context source, a routine: each is a named definition of the primitive's shape, so the language is agreed, taught to Runneth, and consistent across VMs. The customer never edits the structure; they supply the specifics (their sources, their metrics, their naming), and Runneth keeps the filled spec in sync with the evidence. + +--- + +## 9. Initial setup sequence, new org +1. **Probe** what is connected; record as evidence, best-effort. +2. **Write the org-understanding page** from that data, each line citing evidence; flag unknowns as asks; assume platform settings are wrong and re-ask. +3. **Keep shared content in the `global` lane** and set the tag vocabulary + naming decoder (family lanes are a forward path, not carved today). +4. **Decide the facets** per brand (segments, products, campaigns, KPI) from the questions. +5. **Seed the load-bearing compiled pages first:** org-understanding, the naming decoder / meta interpretation, the VoC analysis layer, the question validator. Content-first, not empty scaffolding. +6. **Validate and run the loop** (section 11). + +Setup experience: **act, do not be "too meta."** Do the work and surface results; do not narrate what you are about to do and ask permission at each step. Autofill everything you can, then surface only the 3-8 gap questions the human must answer; the CSM or customer answers them through their own process. + +--- + +## 10. Existing org repair checklist +1. **Read the existing folders** and respect them. +2. **Inventory dependencies** (routines, apps that reference paths) before moving or re-tagging. +3. **Audit lanes.** Collapse any lane-per-platform or lane-per-workstream mess back into `global` + tags; those custom lanes are not queried today, so their content is likely dark. Keep only `user:` isolation lanes and the automatic workspace lane. +4. **Migrate in safe order: tags first, then projects, then lanes.** Never delete a lane holding unique indexed content without re-homing it. +5. **Move source dumps into `data-sources/`**; per-creative files in the brain exist only by a person's explicit ask (see the Cacheth gotcha) - if any are of unknown provenance, ask the person before archiving, never silently move or delete them; stop indexing specs. +6. **Fill or remove empty scaffolding.** +7. **Dry-run, apply, then verify what is actually readable** and run the validator. + +--- + +## 11. Validation and the eval loop +- **The question validator** is the done-signal: can the agent answer the org's core questions correctly from its own data. Run it graded; a failure points at a missing spec or a bad pull. +- **Close the loop with good / bad / why**; corrections regenerate the compiled page, never touch raw. +- **Instrument questions trained and trusted** as the real metric. +- **A validation dashboard is the visual proof** the compiled understanding reconciles to source, in the customer's own metrics. + +--- + +## 12. Rollout, triggering, and how it stays consistent +- **The package ships to the GitHub repo and installs on every VM, but installing does not act.** A trigger is needed: an SSH conversation per VM that says "use this package / do the readme," which runs the setup. New orgs onboard this way; existing orgs get a manual cleanup pass. +- **VoC setup is manual too.** Nothing runs just because a platform is connected: when a person (or the onboarding run) asks, the voc-data-pull skill's "Set up the recurring sync" procedure creates one daily `voc-sync-` routine per available platform and kicks the backfill. Stored-key platforms (Okendo, Stamped) first need a customer key via the secret-collection flow. +- **Refresh** runs as a deterministic script (cheap pull) with agentic analysis on top (set cadence deliberately, section 6). +- **Non-divergence has two homes.** One is the per-VM setup/config file (the handoff that lays the overlay). The other is Runneth's system prompt, which must teach how Knoweth works, the retrieval model (global + tags today, family lanes as a forward path), where each kind of data lives (Cacheth vs brain files vs live motion CLI pulls), and where to save. That system-prompt work is a separate stream; without it the method is followed by hand and drifts, with it the method holds. This doc is the specification; the prompt change makes it stick. + +### Self-organization over time +Setup gets a VM clean on day one; staying organized over weeks of real use is a separate, mostly-runtime problem, because the human keeps adding and moving files and Runneth keeps writing. What degrades: user-added files land with no metadata, no family folder, or no tags; folder moves orphan content or break path-based routines; compiled pages go stale as new raw arrives; duplicates accumulate; conversational corrections do not propagate; the lane scheme erodes as ad-hoc lanes creep in; raw grows past the index budget; new integrations and new segments/products appear mid-life; and renames break keyword retrieval. + +Countering that is behavior Runneth runs on the relevant turns, not a one-time setup: +- **Classify on every save.** Any write (pull, conversation, upload) runs the save-routing decision: raw vs compiled vs spec, family/lane, project tags, provenance. User-triggered saves land correctly, not in a default dump. +- **Adopt stray files.** When Runneth reads the brain and finds human-added files with no header or outside the convention, classify and tag them into the right lane/project or flag them, without moving the human's folders. +- **Respect and re-anchor on reorganization.** When the human moves folders, re-derive the overlay and re-anchor membership; if a move crossed a family boundary, reconcile the lane. +- **Keep compiled in sync with raw.** New evidence triggers regeneration of the dependent compiled pages with fresh citations; mark a compiled page stale when its raw changed. This is one-way flow enforced over time. +- **Curate, not append.** Find the existing page on a topic and merge or supersede rather than spawn a duplicate; delete dead pages. +- **Propagate corrections.** A conversational correction fixes the compiled page (never raw) and checks whether it invalidates other compiled pages. +- **Guard the scheme.** Resist adding lanes; default new dimensions to facets/projects; propose a lane only when it clearly earns one. +- **Enforce retention.** Archive raw past its window once compiled, keeping the index lean. +- **Extend cleanly.** A new integration mid-life runs the same probe -> family folder -> spec -> lane-decision -> seed flow; new segments/products/campaigns update the org-understanding page and the facet vocabulary. +- **Maintain vocabulary.** Because retrieval is keyword-first, a rename updates the naming decoder and adds aliases (or re-tags) so old content stays findable under new terms. + +Some of this is reactive (on the turn it comes up); the rest needs a **recurring maintenance routine** (the daily/weekly brain-audit shape): scan for stray/untagged files, duplicates, stale compiled pages, ad-hoc lanes, and retention candidates, then fix or surface them. Pull-side refresh is a cheap deterministic script; the audit and compile are the agentic steps, so set cadence deliberately. Bottom line: setup organizes day one, but self-organization over weeks lives in the system prompt (these behaviors) plus a maintenance routine. Without them the brain drifts back to entropy no matter how clean the initial setup. +--- + +## Maintaining this going forward +Two mechanisms keep the brain organized after day one, and both are set up by this part: +1. **The `runneth:knoweth-brain` guard in `/agent/user.md`** (Guard 2 above) makes the discipline always-on: every save is routed and tagged, compiled pages regenerate when their raw changes, corrections update the compiled page (never raw), stray human-added files get adopted, and duplicates get merged rather than appended. This is what stops weeks of human edits from rotting the brain. +2. **The `brain-maintenance` routine** (create-if-absent) runs the scheduled sweep the guard cannot do reactively: stray/untagged files, duplicates, stale compiled pages, ad-hoc lanes, and retention candidates. +`/agent/user.md` is the durable home for this behavior, so keep it current as the org evolves: a rename updates the naming decoder (and adds aliases, since retrieval is keyword-first); a new integration runs the same probe -> folder -> spec -> tag flow; a new recurring dimension becomes a tag. Section 12 has the full behavior list; this is the short version to hold in your head. + +## 13. Gotchas +- **Only `global`, `user:`, and `project:` are queried today; keep shared content in `global` + tags and do not carve family/initiative lanes (they go dark). Lane count stays capped for the forward path.** +- **Empty scaffolding equals empty retrieval.** Seed content-first. +- **Keep one canonical view of the model** (this doc); the agent misread its own setup when there was none. +- **Read-access scoping can silently hide everything;** verify readability after setup. +- **Cacheth is a primitive - assume it is present; it is the system of record for per-creative content** (Knoweth surfaces the creatives from Cacheth; nothing in the package writes creative files to the brain). A per-creative file exists in the brain only when a person explicitly asked for it: a dated snapshot that will not stay synced with the cache - cite the cache for current facts. If the maintenance sweep finds per-creative files of unknown provenance, ask the person before archiving; never silently move or delete them. +- **Sourcing discipline holds:** trust live data, assume manual platform settings are wrong and re-ask, never fabricate, label inferences. + +--- + +## 14. Worked example (illustrative) +A brand asks "top ads for Product A last week." Runneth pulls performance through the motion CLI, ranks by the account's winner metric (defined in `account-context.md`, not a Motion workspace setting), pulls creative identity from Cacheth, and reads the interpretation page (`meta/account-context.md`, in `global`) for how Product A is judged plus the naming decoder for angle/hook/format. A VoC question ("what are one-star reviewers saying about Product A") searches the `global` lane over `data-sources/voc//review-*`, ranked lexically on the metadata block's rating field and the product/segment terms from the tag vocabulary, with agent-side filtering. Neither carves a lane. When the human corrects an interpretation, the compiled page regenerates from the cited raw; the raw is never edited. + +--- + +## 15. Standard method, brand-decided contents +- **Standard on every VM:** the raw/compiled model and one-way flow; how retrieval works; folders vs overlay; the retrieval model (everything in `global` + tags today, `user:` isolation, workspace project automatic, family lanes a forward path); the file-metadata conventions (raw VoC format owned by the VoC skill, compiled-page front-matter owned here); save routing and refresh discipline; the Standard-spec format; setup, repair, and rollout; the validation loop; and not duplicating Cacheth content or live CLI metrics into files. +- **Decided per brand:** the tag vocabulary and naming decoder (segments/personas, products, campaigns, KPI), any future family-lane candidates; the contents of each spec; and what the org-understanding page says. These come from the probe, the interview answers, and the human's folders. + +Verify against the live configuration before finalizing: the lane cap, the config-declaration format, and whether the harness has begun layering configured lanes. The direction (global + tags today, family lanes as a forward path gated on the harness change; project = workspace; metadata for findability and provenance, not a Knoweth filter; content-first; harness stores not duplicated; validate) holds regardless. + +--- + +## How this actually governs Runneth (be honest about it) +This doc is findable reference knowledge. On its own it does not hard-enforce lanes or save-routing; the two `/agent/user.md` guard blocks are what make the lane-setup trigger fire and the save/maintenance discipline always-on, and that merge is admin-gated. The enforceable artifact is the Knoweth lane config; the guard blocks are the standing behavior; this doc is the human-readable contract the CSM, the customer, and Runneth can all point at. Without the guard merge, the method is followed by hand and drifts; with it, it holds. + +## Changelog +### v0.1 (July 2026) — first draft aligned to the packages +- Reframed the front to the Aligned Onboarding house style: version, one-line model, activation guard blocks, hard-gate prerequisites, scope, persistence, honesty section. +- Two sentinel guard blocks: `runneth:knoweth-organize` (post-questions organize) and `runneth:knoweth-brain` (standing save + maintenance). + +### v0.2 (July 2026) — corrected to the real retrieval wiring +- Traced the harness: the requested read set is `[user:, project:, global]`; `project` is the workspace, and family/custom lanes are not queried today. +- Reframed the lane model (section 4) to: everything in `global` + tags today; `user:` for isolation; workspace project is automatic; family lanes are a documented forward path gated on a harness change (option B). +- Guard 1 renamed lanes-setup -> organize (tags + naming decoder, not family lanes). +- Positioned as the last setup step of the combined run and the first line of ongoing maintenance; sequencing of lanes vs validation flagged for the package owner. +- Body (two-layer model, retrieval, lanes, front-matter, save routing, self-organization, packaging) unchanged. + +### v0.3 (July 2026) — review notes resolved +- VoC raw format, folders, and schema now defer to the voc-data-pull skill (one owner per fact); front-matter applies to compiled pages only; the compiled `-context.md` moved out of the items-only platform folders. +- Guard 1 (v2): `/agent/brain/_tag-vocabulary.md` existence is the durable done-marker (no double-fire); "content landed" requires the VoC backfill's coverage-complete report, not file existence. +- Cacheth is an assumed primitive: the deployment-dependent "files by default, Cacheth where flagged in" mode is removed. Nothing in the package writes per-creative files; ones in the brain exist only by a person's explicit ask (dated snapshots; the cache is the retrieval source of truth), and the sweep asks the person before archiving unknown-provenance files rather than moving them silently (gotchas, repair checklist, and the Guard 2 (v2) maintenance sweep). Counteth is NOT assumed: performance metrics are pulled live via the motion CLI (per the Motion CLI Data-Query Guide), never stored. +- Run order single-sourced in the package README; stale facts fixed (VoC setup is manual; the manifest is `package.json`). +- Verified: the lane model matches agent-builder's `resolveKnowethReadLanes`; the family-lane forward path is gated on it layering configured lanes (PDEC-9225). +- Made explicit that the winner metric / interpretation always comes from `account-context.md` (per the account-context guard), never from Motion workspace settings the CLI can return (answer standard, worked example). + +### v0.4 (July 2026) — answer standard upgraded +- Filter rules: read the naming decode (`account-context.md` Field 4, its only home) before any name-based filter; match the signal to the question (structural questions -> campaign/ad-set names via the decode; creative questions -> Cacheth tags and content); cross-check when both carry the signal and say so when they disagree. +- Performance and VoC framed as one system (performance shows what is winning, VoC explains why, ad comments connect the two), with a routing example. +- Show-the-work standard: analytical answers state the filter applied, the signal read (with Cacheth per-layer freshness when it matters), and what could not be confirmed. diff --git a/aligned-onboarding/meta/cacheth-command-reference.md b/aligned-onboarding/meta/cacheth-command-reference.md new file mode 100644 index 0000000..2d8ffb5 --- /dev/null +++ b/aligned-onboarding/meta/cacheth-command-reference.md @@ -0,0 +1,226 @@ +# Cacheth Command Reference + +All five `motion cache` commands, with every flag, option, and usage note. + +--- + +## Overview + +Cacheth is the local Motion cache for creative data. All five commands write their output to a +file under `./workdir/` and return a pointer plus compact metadata. Inspect the returned file +with a separate `jq` call — do not expect full data inline in the shell output. + +Every command accepts `--workspace-id ` to target a workspace other than the current +default. Omit it to use the default workspace. + +There is no section filtering within a record. `get-creative` always returns the full record. +Use `jq` on the returned file to extract only the layer you need. + +--- + +## Commands + +### `motion cache status` + +Reads the current cache state for the workspace. Use this to check whether the cache has been +built, when it was last refreshed, and how many creatives are in it. + +``` +motion cache status +motion cache status --workspace-id +``` + +**Options** + +| Flag | Required | Description | +|---|---|---| +| `--workspace-id ` | No | Target workspace. Omits for the current default. | + +**Returns:** Cache-level metadata only. No creative records. + +--- + +### `motion cache refresh` + +Triggers a fresh sync of the cache from Motion's platform data. Run this when you want to pull +in newly launched creatives or updated summaries. + +``` +motion cache refresh +motion cache refresh --workspace-id +``` + +**Options** + +| Flag | Required | Description | +|---|---|---| +| `--workspace-id ` | No | Target workspace. Omits for the current default. | + +**Returns:** Sync status. No creative content. + +--- + +### `motion cache get-creative` + +Pulls the complete record for one specific creative by ID. Returns every data layer in one shot +— no section filtering is available. + +``` +motion cache get-creative --creative-id +motion cache get-creative --creative-id --workspace-id +``` + +**Options** + +| Flag | Required | Description | +|---|---|---| +| `--creative-id ` | Yes | The Motion creative asset ID to retrieve. | +| `--workspace-id ` | No | Target workspace. Omits for the current default. | + +**What the full record contains:** + +| Layer | Fields | +|---|---| +| Identity | `creativeId`, `workspaceId`, `origin`, `format`, `url`, `launchDate` | +| Freshness timestamps | `inventoryRefreshedAt`, `adUnitsHydratedAt`, `summaryHydratedAt`, `transcriptHydratedAt`, `glossaryHydratedAt`, `transcriptSource` | +| Ad units | `adId`, `adName`, `adText` (primary copy), `adsetId`, `adsetName`, `campaignId`, `campaignName`, `thumbnailUrl`, `videoThumbnailUrl`, `adType`, `isActive`, `created`, `modified` | +| Glossary tags | Tags grouped by category: `asset-type`, `visual-format`, `messaging-angle`, `hook-tactic`, `intended-audience`, `seasonality`, `offer-type`. Each tag includes `name`, `definition`, and display colors. | +| Transcript | `language`, `durationMs`, `text` (full), `segments[]` with `start`/`end`/`text` timestamps, `status` | +| Summary | Six sections: `adDescription`, `adFormat`, `hookOrHeadline`, `creativeBreakdown`, `messagingAndPositioning`, `emotionalAndAudienceInsight` | + +**Useful `jq` extractions on the returned file:** + +```bash +# Transcript only +jq '.transcript' ./workdir/motion-cache-creative-.json + +# Glossary tags only +jq '.glossary' ./workdir/motion-cache-creative-.json + +# Ad names from all ad units +jq '[.adUnits[].adName]' ./workdir/motion-cache-creative-.json + +# Primary copy +jq '[.adUnits[].adText]' ./workdir/motion-cache-creative-.json + +# Hook section only +jq '.summary.hookOrHeadline' ./workdir/motion-cache-creative-.json + +# Messaging and positioning only +jq '.summary.messagingAndPositioning' ./workdir/motion-cache-creative-.json + +# All top-level fields (structure overview) +jq 'keys' ./workdir/motion-cache-creative-.json +``` + +--- + +### `motion cache export-summaries` + +Exports the entire creative corpus as a file. Use this for bulk extraction — getting all ad +names, all transcripts, all glossary tags across every creative in the cache. + +Note that one creative can have multiple ad names (one per ad unit it was served in), so the +export will show that many-to-one relationship. + +``` +motion cache export-summaries --format jsonl +motion cache export-summaries --format duckdb +motion cache export-summaries --format jsonl --workspace-id +``` + +**Options** + +| Flag | Required | Description | +|---|---|---| +| `--format ` | Yes | Export format. Must be `jsonl` or `duckdb`. | +| `--workspace-id ` | No | Target workspace. Omits for the current default. | + +**Format notes:** + +- `jsonl`: One JSON record per line. Easy to pipe through `jq` for extraction and filtering. +- `duckdb`: Queryable database file. Better for large corpora where SQL-style queries are useful. + +**Example `jq` extractions on a JSONL export:** + +```bash +# All ad names across every creative +jq -r '.adNames[]?' ./workdir/.jsonl + +# All creative IDs +jq -r '.creativeId' ./workdir/.jsonl + +# All unique glossary tag names +jq -r '.glossary | .. | objects | .name? // empty' ./workdir/.jsonl | sort -u +``` + +--- + +### `motion cache search-summaries` + +Text search across ad names, ad copy, and summary content. Returns matched records with a +summary excerpt and relevance score. Use this when you know part of an ad name, a hook phrase, +a messaging theme, or a transcript fragment. + +This is a qualitative search surface — not the source of truth for exact performance counts, +fresh live filtering, or metric-grounded ranking. + +``` +motion cache search-summaries --query "UGC founder" +motion cache search-summaries --query "extreme comfort" --limit 10 +motion cache search-summaries --query "bed rot" --workspace-id +``` + +**Options** + +| Flag | Required | Description | +|---|---|---| +| `--query ` | Yes | Search text. Matches against ad names, ad copy, and summary content. | +| `--limit ` | No | Maximum number of matches to return. | +| `--workspace-id ` | No | Target workspace. Omits for the current default. | + +**What each match contains:** + +| Field | Description | +|---|---| +| `creativeId` | The Motion creative asset ID | +| `adNames[]` | All ad names this creative was served under | +| `adsetNames[]` | Ad set names | +| `campaignNames[]` | Campaign names | +| `format` | `video`, `image`, or `carousel` | +| `launchDate` | When the creative launched | +| `origin` | Source platform (e.g. `metaCreativeAsset`) | +| `url` | Media file URL | +| `score` | Relevance score for the search query | +| `excerpt` | Short text snippet showing the match | +| `summaryText` | Concatenated summary sections for the matched creative | +| `workspaceId` | Workspace the creative belongs to | + +**Returns:** `matchCount`, `total`, and a `matches[]` array. Does not return the full creative +record — use `motion cache get-creative` if you need all layers for a specific match. + +--- + +## Choosing the right command + +| What you need | Command | +|---|---| +| Is the cache built? When was it last synced? | `motion cache status` | +| Pull in new creatives or updated summaries | `motion cache refresh` | +| Everything about one specific creative (by ID) | `motion cache get-creative` | +| All ad names, all transcripts, full corpus in bulk | `motion cache export-summaries` | +| Find a creative by name fragment, theme, hook, or copy | `motion cache search-summaries` | + +--- + +## Priority order for creative data retrieval + +When answering questions about creative summaries, transcripts, hooks, or tags: + +1. **Knoweth pre-injected context** — arrives automatically before the turn, no tool call needed. + If the matching creative context is already there, answer from it. +2. **`motion cache search-summaries`** — active local search, no Meta API call required. +3. **`motion cache get-creative`** — full record for a specific ID, still local, no API call. +4. **`motion meta insights --summary-sections`** — live pull from Motion/Meta. Use only when + the cache does not have the creative yet, when you need performance metrics alongside the + summary in the same call, or when a fresh re-analysis is explicitly needed. diff --git a/aligned-onboarding/meta/meta-account-context-brain-onboarding-package.md b/aligned-onboarding/meta/meta-account-context-brain-onboarding-package.md index d9acd39..b6ca84e 100644 --- a/aligned-onboarding/meta/meta-account-context-brain-onboarding-package.md +++ b/aligned-onboarding/meta/meta-account-context-brain-onboarding-package.md @@ -74,8 +74,8 @@ Confirmed answers do not live in this worksheet. Runneth writes them to a durabl 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/`). + to `/agent/brain/meta/account-context.md`. Per-creative content lives in Cacheth (surfaced + through Knoweth), not in brain files. **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 @@ -359,9 +359,12 @@ Captures whether the account uses naming conventions, what each level encodes, a each level is. **Auto-pull** -- Pull all campaign, ad set, and ad name strings. -- Detect structure per level and propose a decoder. +- If Step 1 (Creative Attribution) handed over a provisional decode table, start from it + instead of re-detecting. +- Otherwise: pull all campaign, ad set, and ad name strings, detect structure per level, and + propose a decoder. - Measure reliability per level (% of names fitting the detected pattern). +- Once confirmed, the decode lives in this file's saved result — it has no separate brain file. **What to understand** - For levels with a detected pattern: confirm what each position means. diff --git a/aligned-onboarding/meta/meta-creative-attribution-playbook.md b/aligned-onboarding/meta/meta-creative-attribution-playbook.md index eeaa2bf..aa64713 100644 --- a/aligned-onboarding/meta/meta-creative-attribution-playbook.md +++ b/aligned-onboarding/meta/meta-creative-attribution-playbook.md @@ -1,326 +1,174 @@ # Meta Creative Attribution Playbook ### Step 1 of the Meta Onboarding Package -**How Runneth builds and maintains a per-creative attribution record for a Meta account.** +**How Runneth gets per-creative facts for a Meta account — from the creative content layer +(Cacheth), not from brain files — and detects the account's naming conventions.** This is Step 1 of the Meta onboarding package. It runs before the Account Context Brain because -it collects raw creative facts — content, hooks, tags, transcripts, naming — without interpreting -them. Once built, it gives the Account Context Brain real material to work with. +it establishes where creative facts come from and detects naming patterns — without interpreting +anything. Once done, it gives the Account Context Brain real material to work with. -> **Deployment note (staging): do not auto-build creative files in the brain.** -> In staging, per-creative summaries live in **Cacheth** and are surfaced through **Knoweth**. -> Installing this package must never trigger this playbook on its own, and nothing in this file -> (including the Maintenance section) runs automatically. Do not auto-pull creatives and write -> summary files under `/agent/brain/meta/creatives/`. Run this playbook only when a person -> explicitly asks for brain-stored attribution files for a workspace. +> **Cacheth is the system of record for per-creative content.** +> Per-creative content (summaries, hooks, transcripts, AI tags) lives in **Cacheth**, the local +> creative cache, and is surfaced through **Knoweth**. This playbook writes no creative files, +> and nothing in the package does so on its own. Runneth saves a creative file to the brain only +> when a person explicitly asks for one — a dated snapshot that will not stay synced with the +> cache. When later citing such a file, prefer the cache for current facts. The one-line model: > The **Account Context Brain** tells Runneth **how to analyze** the account. The **Creative -> Attribution** gives Runneth **the per-creative facts it needs to actually do the job**: one -> enriched record per active creative. +> Attribution** gives Runneth **the per-creative facts it needs to actually do the job** — via +> the creative content layer, one enriched record per active creative. Creative Attribution does not interpret anything. Interpretation lives in the Account Context -Brain. This step only pulls from Motion what the Account Context Brain cannot tell it: the +Brain. This step only establishes access to what the Account Context Brain cannot tell it: the creative content itself. --- ## What this produces -- **Individual creative Markdown files**, one per active creative, with identity, summary, hook, - value props, transcript, AI tags, and naming. -- An optional **tagging taxonomy** file, only if a naming convention is detected. -- These files are automatically retrievable through Knoweth. Writing them is the index step. +- A working **creative content layer**: Runneth knows what Cacheth holds and how to query it. +- A provisional **naming decode**, handed to the Account Context Brain as Field 4 proposals. + Once confirmed, the decode lives in `/agent/brain/meta/account-context.md` — this step + persists nothing itself. +- **No creative files** — nothing here writes per-creative content to the brain (Cacheth is the + system of record; person-requested snapshot files are a separate, explicit ask). --- -## Step 1 - Start the onboarding +## The creative content layer: what Cacheth holds and how to query it + +Cacheth syncs each workspace's creative records from Motion automatically. A full record +(`motion cache get-creative`) holds: + +- **Identity:** creative ID, workspace ID, origin, format, launch date, media URL. +- **Ad units:** every ad running the creative — ad / ad set / campaign IDs and names, active + status, thumbnails, and the primary ad copy. +- **Glossary tags with definitions:** asset type, visual format, messaging angle, hook tactic, + intended audience, seasonality, offer type. +- **Transcript** (video only): full text plus timed segments, language, duration. +- **Summary sections:** ad description and format; spoken / text-overlay / visual hooks with + timestamps; a creative breakdown (scene-by-scene storyline, point of view, visuals, people, + music, fonts); messaging and positioning (features, benefits, value props, pain points, CTA, + offer, funnel stage); and emotional and audience insight (emotions with intensities, + persuasion tactics, cultural context, intended audience). +- **Per-layer freshness timestamps:** when inventory, ad units, summary, transcript, and + glossary were each last hydrated. Cite these when freshness matters to an answer. + +What it does **not** hold: performance metrics or spend state. Those are always pulled live +through the motion CLI per the Data-Query Guide. + +Runneth reaches this content two ways, cheapest first: + +1. **Knoweth pre-context injection (passive, first priority).** Before every turn, Knoweth + resolves the incoming query against the local index and injects matching creative chunks into + the "Knoweth Pre-LLM Context" block. If the injected context answers the question, answer + from it — no tool call. +2. **motion cache CLI (active, when injection is not enough).** Local, no API call: + - `motion cache search-summaries --query "" [--limit ]` — text search across ad + names, ad copy, and summary content. Each match carries `creativeId`, `adNames[]`, an + excerpt, and a relevance score — not the full record; follow up with `get-creative` for + that. + - `motion cache get-creative --creative-id ` — the complete record for one creative, + including `adUnits[].adName`. Always the full record (no section filtering); extract the + layer you need from the result file with `jq`. + - `motion cache export-summaries --format jsonl` — the whole synced corpus, one record per + creative, each carrying its `adNames[]`. `--format` is required (`duckdb` is the + alternative when SQL-style queries suit a large corpus). The bulk path when the question + spans the full account rather than a search match. + - `motion cache status` — when the cache last synced and how many creatives it holds. + - `motion cache refresh` — trigger a fresh sync from Motion to pull in newly launched + creatives or updated summaries (the one cache command that reaches out to Motion). + + Every cache command accepts `--workspace-id `; pass it explicitly per the Step 1 scope + rule. All of these write their output to a file under `./workdir/` and return a pointer plus + compact metadata; read the file with `jq`. Those result files are query scratch, not brain + content. + + Flag-level detail, the full-record field layout, and `jq` extraction recipes live in the + Cacheth Command Reference (`/agent/brain/aligned-onboarding/cacheth-command-reference.md`), + installed beside the Data-Query Guide. + +Freshness is the sync's job, not Runneth's: the cache bootstraps per workspace and keeps +hydrating in the background. If a creative seems to be missing, check `motion cache status` and +run `motion cache refresh`; if it is still absent, the live path is `motion meta insights +--summary-sections` per the Data-Query Guide (the same path that owns performance metrics) — +never reconstruct the record by hand. -This step confirms the account scope and opens the attribution build with the customer. +--- -1. Get the target `workspaceId`. Use `motion workspaces` if it is not already known. -2. Pull window defaults to `last_365d`. Only change this if the customer asks. -3. Open with a direct confirmation to the customer: +## Step 1 — Confirm the scope -> I'm starting the Meta Creative Attribution build for **[account name]**. This pulls every active -> creative from your account and builds a searchable record of what each one says, shows, and is -> tagged as — the foundation for every performance read and creative recommendation going forward. -> -> I'll pull the last 12 months by default. This is Step 1 of your Meta onboarding. Once this is -> done, we'll move to Step 2 (Account Context Brain) to confirm how you want to judge performance. +1. Get the target `workspaceId`. Use `motion workspaces` if it is not already known. Never + assume a default workspace — resolve it explicitly before any pull or cache query. +2. Open with a direct confirmation to the customer: -4. Record the scope: - - `workspaceId`: confirmed - - Pull window: `last_365d` (or customer-specified) - - Pull date: today's date as the "attribution as of" timestamp +> I'm starting the Meta Creative Attribution step for **[account name]**. Your creative content — +> what each ad says, shows, and is tagged as — is already synced and searchable. What I'll do now +> is read your ad naming conventions so I can decode them, then we'll move to Step 2 (Account +> Context Brain) to confirm how you want to judge performance. -No Account Context Brain is needed to run this step. Naming decodes are handled provisionally -in Step 3. Spend state is read directly from Motion. +3. Record the scope: `workspaceId` confirmed, and today's date as the "attribution as of" + timestamp. --- -## Step 2 - Pull the creative attribution from Motion - -### 2a. Identity pull - -Run this first. No summaries, no glossary. Returns every creative's identity, format, launch -date, status, spend state, campaign, and ad set. Completes quickly even for large accounts. - -``` -motion meta insights --date-range last_365d --include-metrics --workspace-id -``` - -Inspect the returned file with `jq`: -- Check `totalCount` vs `providerTotalCount`. If they differ, the pull is partial. -- Check `.creatives[0]` to confirm `id`, `adName`, `campaignName`, `adsetName`, `launchDate`, - `isActive`, `spendState`, and `format` are populated. -- Note `.adsWithoutCreativeAsset`. These are spend-bearing ads with no synced creative. Skip them. - -**Save all creative IDs from this pull.** You need them for the enrichment batches. - -### 2b. Enrichment pull - -Adds summaries and AI tags to the creative IDs from 2a. Run in batches of 50 IDs per call using -Python subprocess. Do not attempt on the full account without batching. - -```python -import json, subprocess - -with open('./workdir/corpus_ids.json') as f: - batches = json.load(f)['batches'] - -all_enriched = {} -for batch in batches: - cmd = ['motion', 'meta', 'insights', - '--scope', 'creative-asset-id', - '--date-range', 'last_365d', - '--summary-sections', 'adDescription', - '--summary-sections', 'hookOrHeadline', - '--summary-sections', 'messagingAndPositioning', - '--glossary-category', 'visual-format', - '--glossary-category', 'messaging-angle', - '--glossary-category', 'hook-tactic', - '--glossary-category', 'intended-audience', - '--workspace-id', ''] - for cid in batch: - cmd += ['--creative-asset-id', cid] - result = subprocess.run(cmd, capture_output=True, text=True, timeout=90) - envelope = json.loads(result.stdout) - if envelope.get('successful') and envelope.get('file'): - with open(envelope['file']) as f: - data = json.load(f) - for c in data.get('creatives', []): - if c.get('id') and (c.get('summary') or c.get('glossaryTags')): - all_enriched[c['id']] = { - 'summary': c.get('summary') or {}, - 'glossaryTags': c.get('glossaryTags') or [] - } -``` - -50 IDs per batch is the reliable limit. Larger batches time out on high-spend creatives. - -### 2c. Transcript pull - -Transcripts are pulled scoped, not in bulk. Two passes: - -1. **Top-spend videos** (end of the initial build): run a scoped transcript call covering the top - 50 video creatives by spend. -2. **On demand** for any specific creative later: - -``` -motion meta insights --scope creative-asset-id --creative-asset-id \ - --include-transcript --date-range last_365d --workspace-id -``` - -Only video creatives return a transcript. If a creative returns no transcript, record `"none"`. -Do not leave the field blank. - ---- +## Step 2 — Provisional naming decode -## Step 3 - Provisional naming decode +1. Export the synced corpus and extract the full ad-name list (local, no API call): -The identity pull (Step 2a) returns all ad names across the account. Use them to detect naming -patterns before writing any creative files. + ``` + motion cache export-summaries --format jsonl + ``` -1. Pull the full set of `adName` values from the identity pull result. -2. Look for structure: delimiters (underscores, hyphens, pipes), position-based encoding, - recurring prefixes, tag-like codes. + One record per creative, each carrying its associated ad names — extract them with + `jq -r '.adNames[]?'` on the returned file (a creative served in several ads carries that + many names). If the cache is still bootstrapping the workspace, the list may be incomplete — + `motion cache status` shows the sync state; run `motion cache refresh` and re-run the decode + once the sync settles. The export file is `./workdir/` scratch, not brain content. +2. Look for structure in the `adName` values: delimiters (underscores, hyphens, pipes), + position-based encoding, recurring prefixes, tag-like codes. 3. If a pattern is detected, build a provisional decode table: position or segment → meaning → example values. Mark it **provisional**. -4. Use the provisional decode when writing creative files in Step 5. Mark decoded fields - provisional in each file. - -**Pass findings to the Account Context Brain.** When the Account Context Brain runs (Step 2 of -the onboarding), pre-populate Field 4 (Naming conventions) with this provisional decode table. -The Account Context Brain confirms, corrects, or replaces it — it does not start from scratch. - -If no pattern is detected, record ad names raw in each creative file and note "no naming -convention detected" as the provisional finding for the Account Context Brain to confirm. - ---- - -## Step 4 - Tagging taxonomy - -Create this file only if a naming convention was detected in Step 3. - -**Location:** `/agent/brain/meta/creatives/_tagging-taxonomy.md` - -Contents: the provisional naming table (segment or position → meaning → example values) plus -the standard creative MD template from Step 5. Mark the naming table as provisional until the -Account Context Brain confirms it. The underscore prefix keeps it at the top of the folder and -signals it is a reference file, not a creative. - -Skip this step entirely if no naming convention was detected. - ---- - -## Step 5 - Generate individual creative MD files - -One file per creative. - -**File naming:** match the ad name exactly, `.md` extension. Replace slashes and special -characters with hyphens. Truncate to 200 characters before the `.md` extension. When two -creatives share the same ad name, append the last 6 characters of the `source_id` as a suffix -to prevent overwrites. - -**Location:** `/agent/brain/meta/creatives/.md` - -**Template:** - -```markdown ---- -title: -brand: -workspace: -source_id: -format: