diff --git a/package-index.json b/package-index.json index ddfb614d..f837ff9d 100644 --- a/package-index.json +++ b/package-index.json @@ -1,5 +1,23 @@ { "schemaVersion": 1, - "indexRevision": "initial-empty", - "packages": [] + "indexRevision": "context-kit-1.0.1", + "packages": [ + { + "id": "context-kit", + "name": "Context Kit", + "description": "Builds the brand knowledge that makes every Runneth answer sharper. Seeds a brain skeleton, a Context Kit board app, and the Context Kit skill. Install first, then ad-naming for naming conventions and query contract, then creative-corpus for the full creative library.", + "version": "1.0.1", + "categories": ["baseline"], + "packageManagerVersion": 1, + "source": { + "type": "github", + "owner": "Motion-Creative", + "repo": "runneth-apps", + "ref": "main", + "path": "packages/context-kit" + }, + "updatePolicy": "manual", + "uninstallPolicy": "allowed" + } + ] } diff --git a/packages/context-kit/README.md b/packages/context-kit/README.md new file mode 100644 index 00000000..5e992bef --- /dev/null +++ b/packages/context-kit/README.md @@ -0,0 +1,27 @@ +# Context Kit package + +Builds the institutional knowledge that makes every Runneth answer sharper: brain scaffolds, a board app +(read-only mirror of completeness), and the "build my Context Kit" skill. + +## App build gotchas (learned in staging — read before editing the app) + +- **`buildeth.app.json` must be v3** with `name: "context-kit"`, `route: "/context-kit"`, + `conversationId`, `workspaceId`, `oauthEnabled: true`, `data: { "dir": "data" }`, and + `static: { "dist": "dist", "index": "index.html" }`. It ships as a template with + `__CONVERSATION_ID__` / `__WORKSPACE_ID__` tokens the skill substitutes before `app build`. +- **`astro.config.mjs` must set `base: "/context-kit"`** (and `trailingSlash: "never"`). Without a base, + Astro emits absolute `/_astro/...` asset URLs and `app build` rejects the static output. +- **Use ` + + +
+
+

Your Context Kit

+

Your brand, the way Runneth sees you. Confirm what we pulled, review what we drafted, and add the few things only you know. Everything gets saved to your brain and makes every answer better.

+
+
+
+
+ +
+
Already have this in Google Drive or Notion?
+
Say so in chat and Runneth pulls your brand docs directly.
+
+
+
+
+
+
+ + + + diff --git a/packages/context-kit/brain/context-kit/briefing-template.md b/packages/context-kit/brain/context-kit/briefing-template.md new file mode 100644 index 00000000..eb346694 --- /dev/null +++ b/packages/context-kit/brain/context-kit/briefing-template.md @@ -0,0 +1,11 @@ +# Briefing template + +> Status: not yet filled. This is the exact format Runneth returns creative briefs in. Drop your +> current brief template during onboarding and Runneth will match it, or edit this file directly. + +## How to fill +Best path: drop your existing brief doc during "build my Context Kit" and Runneth saves it here +as the exact-match template. Otherwise, paste your preferred structure below. + +## Your template +_(empty. until filled, Runneth uses its default briefing structure.)_ diff --git a/packages/context-kit/brain/context-kit/business-team.md b/packages/context-kit/brain/context-kit/business-team.md new file mode 100644 index 00000000..ce94a8a1 --- /dev/null +++ b/packages/context-kit/brain/context-kit/business-team.md @@ -0,0 +1,16 @@ +# Business & Team + +## Runneth Instructions + +_Fill this in so Runneth knows who is using it and how decisions get made._ + +--- + +**Thought starters:** +- Brand name and website URL. +- Who uses Runneth on the team, and what are their roles? +- Who makes the final call on creative concepts before they go into production? +- Who approves creative before launch? +- What is the typical launch cadence — how many new concepts per week/month? +- How are briefs delivered to creators or the production team (Notion, email, Slack)? +- Are there any external agencies or freelancers involved in creative production? diff --git a/packages/context-kit/brain/context-kit/context-kit-state.json b/packages/context-kit/brain/context-kit/context-kit-state.json new file mode 100644 index 00000000..c582b88c --- /dev/null +++ b/packages/context-kit/brain/context-kit/context-kit-state.json @@ -0,0 +1,244 @@ +{ + "version": 1, + "brandName": "", + "levels": [ + { + "id": "L1", + "name": "Answers questions", + "state": "passed" + }, + { + "id": "L2", + "name": "On-brand outputs", + "state": "current" + }, + { + "id": "L3", + "name": "Runs with full context", + "state": "locked" + } + ], + "items": [ + { + "id": "brand-context", + "label": "Brand context", + "bucket": "A", + "status": "missing", + "why": "Keeps every output unmistakably on-brand.", + "preview": "", + "dataFile": "brand-context.md" + }, + { + "id": "kpis-goal", + "label": "KPIs & goal", + "bucket": "A", + "status": "missing", + "why": "Every readout leads with the metric you care about.", + "preview": "", + "dataFile": "kpis-goal.md" + }, + { + "id": "spend-threshold", + "label": "Spend threshold", + "bucket": "A", + "status": "missing", + "why": "Separates a proven winner from early noise.", + "preview": "", + "dataFile": "spend-threshold.md" + }, + { + "id": "competitors", + "label": "Competitors", + "bucket": "B", + "status": "missing", + "why": "Angles to attack the gaps rivals leave open.", + "dataFile": "competitors.md", + "enrich": "Follow brands in Motion Inspo so Runneth can research their live ads and creative angles automatically." + }, + { + "id": "products", + "label": "Products & SKUs", + "bucket": "B", + "status": "missing", + "why": "Grounds every ad in real product facts.", + "dataFile": "products.md", + "enrich": "Connect your Shopify store for live product data, pricing, and bestseller rankings." + }, + { + "id": "positioning", + "label": "Positioning & personas", + "bucket": "B", + "status": "missing", + "why": "Right audience, right angle.", + "dataFile": "positioning.md" + }, + { + "id": "voice", + "label": "Voice & tone", + "bucket": "B", + "status": "missing", + "why": "Copy that sounds like you wrote it.", + "dataFile": "voice.md" + }, + { + "id": "voc", + "label": "Voice-of-customer", + "bucket": "B", + "status": "missing", + "why": "How your customers actually talk about the problem.", + "dataFile": "voc.md", + "enrich": "Connect your reviews platform (Yotpo, Okendo, Trustpilot) for real customer language, the richest VoC source available." + }, + { + "id": "legal", + "label": "Legal & compliance", + "bucket": "C", + "status": "missing", + "why": "Clears review on the first pass.", + "dataFile": "legal-compliance.md", + "thoughtStarters": [ + "Any claims you legally can't make? (clinically proven, #1, cures, guaranteed)", + "Required disclaimers or fine print on specific claims?", + "Regulated categories that apply? (health, finance, beauty, supplements, kids)", + "Words or comparisons legal has flagged before?" + ] + }, + { + "id": "briefing-template", + "label": "Briefing template", + "bucket": "C", + "status": "missing", + "why": "Briefs come back in your exact format.", + "dataFile": "briefing-template.md", + "thoughtStarters": [ + "Do you have an existing brief format you want matched? Drop it in chat.", + "What sections does every brief need? (hook, angle, format, CTA)", + "Who reads the brief, and what do they need from it?" + ] + }, + { + "id": "source-of-truth", + "label": "Source of truth", + "bucket": "C", + "status": "missing", + "why": "Reports never fight your dashboard.", + "dataFile": "source-of-truth.md", + "enrich": "Connect your attribution platform (Northbeam, Triple Whale, or similar) so Runneth always reports from your preferred source.", + "thoughtStarters": [ + "When the ad platform and your attribution tool disagree, which wins?", + "What's your primary success metric and attribution window?", + "Any metric you explicitly don't trust or want ignored?", + "Which dashboard does your team review in meetings?" + ] + }, + { + "id": "guardrails", + "label": "Guardrails", + "bucket": "C", + "status": "missing", + "why": "Always/never rules for creative.", + "dataFile": "guardrails.md", + "thoughtStarters": [ + "What should Runneth NEVER suggest in a creative concept?", + "Any visual styles or creative directions that are always off-limits?", + "Non-negotiables for claims, tone, or offers?", + "Any past ad types or messages to avoid repeating?" + ] + }, + { + "id": "media-buying", + "label": "Media buying model", + "bucket": "C", + "status": "missing", + "why": "Keeps creative recommendations aligned with how you actually buy.", + "dataFile": "media-buying.md", + "thoughtStarters": [ + "How do you primarily buy? (ABO, CBO, Advantage+)", + "What does a typical campaign structure look like?", + "Any budget rules or pacing preferences Runneth should know?" + ] + }, + { + "id": "business-team", + "label": "Business & team", + "bucket": "C", + "status": "missing", + "why": "Runneth works better knowing who is using it and how decisions get made.", + "dataFile": "business-team.md", + "thoughtStarters": [ + "Who reviews and approves creatives?", + "Who owns the brief-to-production pipeline?", + "Any team rules or review steps Runneth should respect?" + ] + }, + { + "id": "landing-pages", + "label": "Landing pages", + "bucket": "C", + "status": "missing", + "why": "Briefs land harder when Runneth knows what the ad is sending to.", + "dataFile": "landing-pages.md", + "thoughtStarters": [ + "What are your main landing page URLs or page types?", + "What is the primary CTA on your top pages?", + "Any pages that are off-limits for ads?" + ] + }, + { + "id": "integration-ad-platform", + "label": "Ad platform", + "bucket": "D", + "status": "missing", + "why": "How you want Runneth to read your ad data.", + "dataFile": "integrations/ad-platform.md", + "enrich": "Connect your ad platform (Meta, TikTok) so Runneth can draft this from your live account.", + "thoughtStarters": [ + "Which metric should Runneth grade on?", + "Any spend floor before a result counts?", + "Campaigns that are always-on and shouldn't be flagged as new?" + ] + }, + { + "id": "integration-asset-library", + "label": "Asset library", + "bucket": "D", + "status": "missing", + "why": "Which assets Runneth can safely use.", + "dataFile": "integrations/asset-library.md", + "enrich": "Connect your asset library (Google Drive, a DAM) so Runneth pulls only approved, brand-safe assets.", + "thoughtStarters": [ + "Which folder holds cleared, approved assets?", + "What's off-limits (WIP, legal review)?", + "How do you mark a final, shippable version?" + ] + }, + { + "id": "integration-data-warehouse", + "label": "Data warehouse", + "bucket": "D", + "status": "missing", + "why": "How Runneth should read your warehouse.", + "dataFile": "integrations/data-warehouse.md", + "enrich": "Connect your warehouse (Snowflake, BigQuery) for blended reporting Runneth can reconcile against.", + "thoughtStarters": [ + "Which table is the source of truth for revenue?", + "Net or gross of fees?", + "What should Runneth NOT pull from here?" + ] + }, + { + "id": "integration-reviews", + "label": "Reviews platform", + "bucket": "D", + "status": "missing", + "why": "How Runneth should use your reviews.", + "dataFile": "integrations/reviews.md", + "enrich": "Connect your reviews platform (Yotpo, Okendo, Trustpilot) so Runneth mines real customer language.", + "thoughtStarters": [ + "Which products' reviews matter most?", + "Any themes you already know customers repeat?", + "Anything to exclude (spam, off-topic)?" + ] + } + ] +} diff --git a/packages/context-kit/brain/context-kit/guardrails.md b/packages/context-kit/brain/context-kit/guardrails.md new file mode 100644 index 00000000..bcbd0bad --- /dev/null +++ b/packages/context-kit/brain/context-kit/guardrails.md @@ -0,0 +1,16 @@ +# Guardrails + +> Status: not yet filled. Runneth honors this before generating customer-facing output. Fill it +> through the Context Kit skill ("build my Context Kit") or tell Runneth here. + +## What belongs here +The always/never rules for how Runneth should and should not create for your brand. + +## Thought starters +- Anything Runneth should always do in creative? (a signature format, a required CTA, a mascot) +- Anything Runneth should never do? (a tone, a competitor mention, a discount level, an emoji style) +- Approval workflow: who signs off before something ships, and on what? +- Any internal targets or constraints beyond your Motion goal? + +## Your answers +_(empty)_ diff --git a/packages/context-kit/brain/context-kit/landing-pages.md b/packages/context-kit/brain/context-kit/landing-pages.md new file mode 100644 index 00000000..783f2f04 --- /dev/null +++ b/packages/context-kit/brain/context-kit/landing-pages.md @@ -0,0 +1,16 @@ +# Landing Pages + +## Runneth Instructions + +_Fill this in so Runneth knows where ads send traffic and what is being optimized for._ + +--- + +**Thought starters:** +- What are the main landing page URLs you drive traffic to? +- What is each page optimized for (trial signup, demo booking, purchase, lead form)? +- Have you run any landing page tests? What did you learn? +- Which landing pages correlate with your strongest-performing creative? +- Are there any pages that consistently underperform despite strong creative? +- Do different audiences or funnels go to different pages? +- Are there pages you want Runneth to avoid recommending traffic to? diff --git a/packages/context-kit/brain/context-kit/legal-compliance.md b/packages/context-kit/brain/context-kit/legal-compliance.md new file mode 100644 index 00000000..05e886d2 --- /dev/null +++ b/packages/context-kit/brain/context-kit/legal-compliance.md @@ -0,0 +1,18 @@ +# Legal & compliance + +> Status: not yet filled. Runneth reads this before any creative work. Fill it through the +> Context Kit skill ("build my Context Kit") or just tell Runneth the answers here. + +## What belongs here +The claims, words, and framings your brand is allowed and not allowed to make in ads and copy, +so creative clears review on the first pass. + +## Thought starters +- Any claims you legally cannot make? (e.g. "clinically proven", "#1", "cures", "guaranteed") +- Required disclaimers or fine print on specific claims? +- Regulated categories that apply to you? (health, finance, beauty, supplements, kids) +- Words or comparisons legal has flagged before? +- Anything you must always attribute or cite? + +## Your answers +_(empty)_ diff --git a/packages/context-kit/brain/context-kit/media-buying.md b/packages/context-kit/brain/context-kit/media-buying.md new file mode 100644 index 00000000..785c09b1 --- /dev/null +++ b/packages/context-kit/brain/context-kit/media-buying.md @@ -0,0 +1,20 @@ +# Media Buying Model + +## Latest Import From Motion + +_Not yet populated. The skill will attempt to infer from campaign structure on first run._ + +## Runneth Instructions + +_Fill this in so Runneth knows how budget decisions are made._ + +--- + +**Thought starters:** +- What is the bid strategy (lowest cost, cost cap, target ROAS)? +- How is budget structured — CBO, ABO, or mixed? +- What is the testing budget per concept? +- What spend threshold does a creative need to reach before you make a call on it? +- What does the campaign architecture look like — how many campaigns, how are ad sets organized? +- How do you handle audience targeting — broad, interest, retargeting? +- How often does budget get redistributed between campaigns? diff --git a/packages/context-kit/brain/context-kit/source-of-truth.md b/packages/context-kit/brain/context-kit/source-of-truth.md new file mode 100644 index 00000000..67557c41 --- /dev/null +++ b/packages/context-kit/brain/context-kit/source-of-truth.md @@ -0,0 +1,16 @@ +# Source of truth + +> Status: not yet filled. Runneth honors this before any performance or reporting answer. Fill it +> through the Context Kit skill ("build my Context Kit") or tell Runneth here. + +## What belongs here +Which numbers Runneth should trust when sources disagree, so reports never fight your dashboard. + +## Thought starters +- When the ad platform and your attribution tool disagree, which wins? (e.g. Triple Whale, Northbeam, GA4, platform-reported) +- What is your primary success metric, and over what attribution window? +- Any metric you explicitly do not trust or want ignored? +- Which dashboard is the one your team reviews in meetings? + +## Your answers +_(empty)_ diff --git a/packages/context-kit/instructions/behavior.md b/packages/context-kit/instructions/behavior.md new file mode 100644 index 00000000..55b4ca42 --- /dev/null +++ b/packages/context-kit/instructions/behavior.md @@ -0,0 +1,56 @@ +# Context Kit package instructions + +This package installs the Context Kit: brand knowledge that makes every Runneth answer sharper. It seeds structured-but-empty scaffolds, a status index, the Context Kit board app, and the Context Kit skill. + +Naming conventions, per-campaign KPI maps, and the Motion query contract are in the **ad-naming** companion package. Install Context Kit first, then ad-naming. + +## Knoweth lane model + +Context Kit registers three lanes on first run. The skill handles registration — do NOT use `user.md` guards. + +| Lane | What it injects | When it fires | +|---|---|---| +| `context-kit-core` | State, guardrails, legal, source-of-truth, briefing-template | Always | +| `context-kit-brand` | Brand-context, voice, voc, positioning, products, competitors | Creative, briefing, concept turns | +| `context-kit-performance` | KPIs-goal, spend-threshold | Performance and reporting turns | + +If **ad-naming** is installed, it registers its own `ad-naming` lane covering the naming decoder, KPI map, and query contract. If **creative-corpus** is installed, it registers its own `creative-corpus` lane. Neither is owned or registered by this package. + +## What Runneth should know from moment one + +- Board app at `agent_apps/context-kit`. Package sync stages files but does NOT build apps. Build: fill `buildeth.app.json`, then `app build context-kit`. +- Board is client-rendered: fetches `data/context-kit-state.json` and `data/*.md` at runtime. Rebuild only needed for source changes, not content. +- State: `/agent/brain/context-kit/context-kit-state.json` (source of truth), mirrored to `data/context-kit-state.json`. +- Lanes: registered by the skill on first run. Check `lanesRegistered` in state. +- Refresh: performed directly in an agent turn so trusted Motion tools are available. + Do not call Motion from `task.bash` or a script-mode routine. + +## Self-improvement loop (always on) + +Fires on every creative-strategy turn. + +1. The relevant lane files are already injected. Use them. +2. If a needed file was empty or thin, AFTER the answer: + - Say plainly what was missing. + - Make ONE specific offer to capture it. + - On yes: write the file, mirror to `data/`, update state, refresh INDEX. +3. Keep it to one offer per turn. + +## Bucket A import contract + +Each Auto-filled item uses two sections: +- `## Latest Import From Motion` — most recent value from Motion. +- `## Runneth Instructions` — customer corrections and rules. + +On conflict, follow `Runneth Instructions`. A refresh updates only `Latest Import From Motion`. + +## Integration source guides (Your tools tab, Bucket D) + +Files at `/agent/brain/context-kit/integrations/.md`, mirrored to `data/integrations/.md`. The ad-platform guide (the account-specific Motion query contract) is provided by ad-naming when installed — do not create it here. Other guides use thoughtStarters until the customer connects that source. + +## Rules + +- Never write into `user.md`. +- Prefer importing from Drive/Notion before asking the customer to type. +- Scaffolds are create-if-absent. Never overwrite a file the customer has filled. +- Refresh INDEX.md as each item is filled. diff --git a/packages/context-kit/package.json b/packages/context-kit/package.json new file mode 100644 index 00000000..b40dbe68 --- /dev/null +++ b/packages/context-kit/package.json @@ -0,0 +1,87 @@ +{ + "schemaVersion": 1, + "id": "context-kit", + "name": "Context Kit", + "description": "Builds the brand knowledge that makes every Runneth answer sharper. Seeds a brain skeleton, a Context Kit board app, and the Context Kit skill. Install first, then ad-naming for naming conventions and query contract, then creative-corpus for the full creative library.", + "version": "1.0.1", + "installPolicy": "manual", + "updatePolicy": "manual", + "uninstallPolicy": "allowed", + "resources": [ + { + "id": "context-kit-behavior", + "type": "package_instruction", + "sourcePath": "instructions/behavior.md" + }, + { + "id": "context-kit-state", + "type": "file", + "sourcePath": "brain/context-kit/context-kit-state.json", + "target": { "root": "agent_brain", "path": "context-kit/context-kit-state.json" }, + "executable": false + }, + { + "id": "legal-compliance", + "type": "file", + "sourcePath": "brain/context-kit/legal-compliance.md", + "target": { "root": "agent_brain", "path": "context-kit/legal-compliance.md" }, + "executable": false + }, + { + "id": "source-of-truth", + "type": "file", + "sourcePath": "brain/context-kit/source-of-truth.md", + "target": { "root": "agent_brain", "path": "context-kit/source-of-truth.md" }, + "executable": false + }, + { + "id": "guardrails", + "type": "file", + "sourcePath": "brain/context-kit/guardrails.md", + "target": { "root": "agent_brain", "path": "context-kit/guardrails.md" }, + "executable": false + }, + { + "id": "briefing-template", + "type": "file", + "sourcePath": "brain/context-kit/briefing-template.md", + "target": { "root": "agent_brain", "path": "context-kit/briefing-template.md" }, + "executable": false + }, + { + "id": "media-buying-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/media-buying.md", + "target": { "root": "agent_brain", "path": "context-kit/media-buying.md" }, + "executable": false + }, + { + "id": "business-team-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/business-team.md", + "target": { "root": "agent_brain", "path": "context-kit/business-team.md" }, + "executable": false + }, + { + "id": "landing-pages-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/landing-pages.md", + "target": { "root": "agent_brain", "path": "context-kit/landing-pages.md" }, + "executable": false + }, + { + "id": "context-kit-skill", + "type": "directory", + "sourcePath": "skills", + "target": { "root": "agent_skills", "path": "context-kit" }, + "executablePaths": [] + }, + { + "id": "context-kit-app", + "type": "directory", + "sourcePath": "apps/context-kit", + "target": { "root": "agent_apps", "path": "context-kit" }, + "executablePaths": [] + } + ] +} diff --git a/packages/context-kit/runneth-package.json b/packages/context-kit/runneth-package.json new file mode 100644 index 00000000..6bff8895 --- /dev/null +++ b/packages/context-kit/runneth-package.json @@ -0,0 +1,116 @@ +{ + "schemaVersion": 1, + "id": "context-kit", + "name": "Context Kit", + "description": "Builds the brand knowledge that makes every Runneth answer sharper. Seeds a brain skeleton, a Context Kit board app, and the Context Kit skill. Install first, then ad-naming for naming conventions and query contract, then creative-corpus for the full creative library.", + "version": "1.0.1", + "updatePolicy": "manual", + "uninstallPolicy": "allowed", + "resources": [ + { + "id": "context-kit-behavior", + "type": "package_instruction", + "sourcePath": "instructions/behavior.md" + }, + { + "id": "context-kit-state", + "type": "file", + "sourcePath": "brain/context-kit/context-kit-state.json", + "target": { + "root": "agent_brain", + "path": "context-kit/context-kit-state.json" + }, + "executable": false + }, + { + "id": "legal-compliance", + "type": "file", + "sourcePath": "brain/context-kit/legal-compliance.md", + "target": { + "root": "agent_brain", + "path": "context-kit/legal-compliance.md" + }, + "executable": false + }, + { + "id": "source-of-truth", + "type": "file", + "sourcePath": "brain/context-kit/source-of-truth.md", + "target": { + "root": "agent_brain", + "path": "context-kit/source-of-truth.md" + }, + "executable": false + }, + { + "id": "guardrails", + "type": "file", + "sourcePath": "brain/context-kit/guardrails.md", + "target": { + "root": "agent_brain", + "path": "context-kit/guardrails.md" + }, + "executable": false + }, + { + "id": "briefing-template", + "type": "file", + "sourcePath": "brain/context-kit/briefing-template.md", + "target": { + "root": "agent_brain", + "path": "context-kit/briefing-template.md" + }, + "executable": false + }, + { + "id": "media-buying-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/media-buying.md", + "target": { + "root": "agent_brain", + "path": "context-kit/media-buying.md" + }, + "executable": false + }, + { + "id": "business-team-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/business-team.md", + "target": { + "root": "agent_brain", + "path": "context-kit/business-team.md" + }, + "executable": false + }, + { + "id": "landing-pages-scaffold", + "type": "file", + "sourcePath": "brain/context-kit/landing-pages.md", + "target": { + "root": "agent_brain", + "path": "context-kit/landing-pages.md" + }, + "executable": false + }, + { + "id": "context-kit-skill", + "type": "directory", + "sourcePath": "skills", + "target": { + "root": "agent_skills", + "path": "context-kit" + }, + "executablePaths": [] + }, + { + "id": "context-kit-app", + "type": "directory", + "sourcePath": "apps/context-kit", + "target": { + "root": "agent_apps", + "path": "context-kit" + }, + "executablePaths": [] + } + ] +} diff --git a/packages/context-kit/skills/SKILL.md b/packages/context-kit/skills/SKILL.md new file mode 100644 index 00000000..48a08c93 --- /dev/null +++ b/packages/context-kit/skills/SKILL.md @@ -0,0 +1,163 @@ +--- +name: context-kit +description: Builds a customer's Context Kit, the brand knowledge that makes every Runneth answer sharper. Reads the Context Kit state index, confirms what Motion knows, drafts brand-context and every Bucket B item from Motion creative data before asking anything, imports what already lives in Google Drive or Notion, and collects what only the customer knows. Triggers on "build my context kit", "set up my context kit", "context kit", "build my brain", "sharpen Runneth", "what do you still need from me", "what does Runneth know about us". +--- + +# Context Kit skill + +Turn a fresh brain into a filled one. The board app is the mirror; this skill is the doer. Draft from Motion data first, then import, then collect. Never write to `user.md`. + +Naming conventions, per-campaign KPI maps, and the Motion query contract are handled by the **ad-naming** companion package. Install that after Context Kit when the account has a structured naming system. + +## Single source of truth + +Every one of the 15 files lives in `/agent/brain/context-kit/.md` and is mirrored to `/agent/apps/context-kit/data/.md` so the board can fetch it. + +Item ids: brand-context, kpis-goal, spend-threshold, competitors, products, positioning, voice, voc, legal (file legal-compliance.md), briefing-template, source-of-truth, guardrails, media-buying, business-team, landing-pages. + +Integration guides: `/agent/brain/context-kit/integrations/.md`, mirrored to `data/integrations/.md`. + +## Status meaning +- `confirmed` / `imported`: locked in by the customer (green). +- `drafted`: built from ACTUAL Motion data. Must carry real data, not general knowledge. +- `inferred`: written from general brand knowledge because Motion was unavailable. MUST carry a `sourceNote`. +- `missing`: nothing yet. + +## Step 0 — Load state + set brand name + +1. Read `/agent/brain/context-kit/context-kit-state.json`. +2. Set top-level `brandName` from `motion workspaces` or brand context before the first state write. +3. Run `motion brand-context --data-query "summary"`, `motion workspace-goal`, `motion spend-threshold`. +4. Note which context sources are connected (Google Drive, Notion, reviews platform). + +## Step 0b — Register Knoweth lanes (first run only) + +If `context-kit-state.json` shows `lanesRegistered: false` or the field is absent, register the three core lanes before any brain writes: + +| Lane ID | Path | Patterns | +|---|---|---| +| `context-kit-core` | `/agent/brain/context-kit/` | `context-kit-state.json`, `guardrails.md`, `legal-compliance.md`, `source-of-truth.md`, `briefing-template.md` | +| `context-kit-brand` | `/agent/brain/context-kit/` | `brand-context.md`, `voice.md`, `voc.md`, `positioning.md`, `products.md`, `competitors.md` | +| `context-kit-performance` | `/agent/brain/context-kit/` | `kpis-goal.md`, `spend-threshold.md` | + +Set `lanesRegistered: true` in state. Do not re-register on subsequent runs. + +## Step 0c — Keep Motion work in the agent turn + +Run every `motion` command directly in this agent turn. Do not put Motion calls in +`task.bash` or script-mode routines: task-scoped broker tokens cannot access the +trusted Motion tool. Deterministic local file processing may use bash. + +## Step 1 — Build and open the board (first run only) + +Fill `/agent/apps/context-kit/buildeth.app.json` (replace `__CONVERSATION_ID__` and `__WORKSPACE_ID__`), run `app build context-kit`, then `app list` for the URL. + +## Step 2 — Bucket A: confirm and auto-draft brand-context + +- **kpis-goal:** show the live Motion workspace-goal value. Present, confirm, write the full doc with `## Latest Import From Motion` and blank `## Runneth Instructions`. Mark `confirmed`. Note: the per-campaign KPI map is handled by the **ad-naming** package. +- **spend-threshold:** same pattern. +- **brand-context:** if `motion brand-context` has content, show and confirm; if empty, draft from `motion meta insights --date-range last_30d --sort topSpend --include-metrics`. Foundation only (brand name, origin story, positioning, product description, proof points, 2-sentence tone, 2-sentence audience). Present, confirm, write, save to workspace config, mirror, mark `confirmed`. + +## Step 3 — Proactive import + connect offers + +If any Bucket B/C item is missing: +- Drive/Notion connected: offer to search there first. +- No reviews platform: suggest connecting it (powers voice-of-customer). + +Import confirmed docs, mirror, mark `imported`. + +## Step 4 — Bucket B: glossary spine, then draft each item + +Pull the ground-truth spine once: +1. `motion ai-glossary` +2. Run: + ``` + motion meta insights \ + --date-range last_30d \ + --sort topSpend \ + --glossary-category intended-audience \ + --glossary-category messaging-angle \ + --glossary-category hook-tactic \ + --glossary-category visual-format \ + --glossary-category asset-type \ + --glossary-category offer-type \ + --glossary-category seasonality + ``` + Read the returned category data for each creative. +3. For VoC, take up to 20 top-spend creative asset IDs and enrich them in batches of + no more than 15: + ``` + motion meta insights \ + --scope creative-asset-id \ + --creative-asset-id \ + --date-range last_365d \ + --summary-sections hookOrHeadline \ + --summary-sections creativeBreakdown \ + --summary-sections messagingAndPositioning \ + --summary-sections emotionalAndAudienceInsight \ + --summary-sections adDescription + ``` + Repeat `--creative-asset-id` for each ID in the batch. + +Category-to-item mapping: +- `intended-audience` → positioning + voc +- `messaging-angle` → positioning + voice +- `hook-tactic` → voice + voc +- `visual-format` + `asset-type` → voice +- `offer-type` → products +- `seasonality` → products + competitors + +Per-item fallback chain (explicit, sequential): +1. Motion glossary spine + summary sections → draft, status `drafted`. +2. Motion empty → Drive/Notion if connected → status `imported`. +3. Neither → general brand knowledge → status `inferred` + `sourceNote`. +4. Still unreliable → leave `missing`, show thought starters. + +After each: mirror to `data/.md`, tell the user what was drafted. + +**voice**: 4-6 named characteristics with sounds-like/doesn't-sound-like pairs. +**voc**: 7-category swipe file (pain, emotional language, desire, before/after, +objections, competitor complaints, trigger events). Preserve exact customer-facing +language when present in summary sections; do not label generated prose as a transcript. + +## Step 5 — Bucket C: collect with depth + +legal, briefing-template, source-of-truth, guardrails, media-buying, business-team, landing-pages: file drop when they have it, thought starters when stuck. Write, mirror, mark `confirmed`. + +## Step 6 — Keep the map correct + +- Refresh `/agent/INDEX.md` for all `/agent/brain/context-kit/` files. +- Update BOTH state copies after every change. + +## Step 7 — Offer the weekly refresh routine + +After the completeness meter hits 100%, offer: + +``` +routine add \ + --name "Context Kit weekly refresh" \ + --cron "0 9 * * 1" \ + --delivery "Send a summary in a new web conversation." \ + --prompt "Start an agent turn and read the installed context-kit skill. Refresh Context Kit directly in that agent turn using its current Motion commands; never call Motion from task.bash. Preserve every Runneth Instructions section, update only Motion-derived content, mirror changed files and state, and open a new conversation summarising shifts in voice, VoC, or competitors plus anything stale for 3+ weeks." +``` + +Save routine ID to state as `refreshRoutineId`. + +## Rules +- Never touch `user.md`. +- Create-if-absent; edit-in-place on confirm. Never overwrite a filled file. +- Reserve `drafted` for real Motion data. Use `inferred` + `sourceNote` for general-knowledge drafts. +- Plain language with the customer. No file paths or JSON in chat. + +## Bucket A: two-section import contract + +- `## Latest Import From Motion` — current Motion value. +- `## Runneth Instructions` — customer corrections and rules. + +On conflict, follow `Runneth Instructions`. A refresh updates only the import section. + +## Bucket D: integration source guides + +Files at `/agent/brain/context-kit/integrations/.md`, mirrored to `data/integrations/.md`. The ad-platform guide (workspace ID, attribution windows, conversion events, metric gotchas) is provided by the **ad-naming** package when installed. Other guides (asset-library, data-warehouse, reviews) use their thoughtStarters until the customer connects that source. + +Bucket D excluded from completeness meter. diff --git a/scripts/validate-runneth-package-index.mjs b/scripts/validate-runneth-package-index.mjs index eef87b71..48bf8c3b 100644 --- a/scripts/validate-runneth-package-index.mjs +++ b/scripts/validate-runneth-package-index.mjs @@ -152,8 +152,14 @@ const assertPackageManifest = (manifest, label) => { `${label}.uninstallPolicy: invalid`, ) assert.ok(Array.isArray(manifest.resources), `${label}.resources: must be array`) + const resourceIds = new Set() manifest.resources.forEach((resource, index) => { assertPackageResource(resource, `${label}.resources[${index}]`) + assert.ok( + !resourceIds.has(resource.id), + `${label}.resources: duplicate resource id ${resource.id}`, + ) + resourceIds.add(resource.id) }) }