Skip to content

Commit c0ce486

Browse files
committed
Fix index mode on the four single-file plugin payloads
brief-schema.md and eco-floors.yaml were still recorded as mode 120000 in both plugins. Replacing a symlink's content on a core.symlinks=false checkout swaps the bytes but leaves the index mode alone, so git was carrying a symlink whose target was the entire file body. A Linux checkout would have tried to create that link and produced a broken path where the ECO floor registry should be -- reintroducing the "ECO floor registry not found" failure this change set out to fix. Forced to 100644 via update-index --cacheinfo. No symlinks remain under plugins/.
1 parent bbe917b commit c0ce486

4 files changed

File tree

plugins/kai-marketing-os-v2/harness/brief-schema.md

Lines changed: 0 additions & 154 deletions
This file was deleted.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Content Brief Schema
2+
3+
Every content task requires a completed brief. No brief = no write.
4+
Save to `/tmp/harness_brief.json` before passing to write agent.
5+
6+
---
7+
8+
## Required Fields
9+
10+
```json
11+
{
12+
"target_site": "kaicalls | buildwithkai | abp | meetkai | connorgallic | vocalscribe",
13+
"target_keyword": "primary keyword exactly as it appears in title",
14+
"secondary_keywords": ["2-3 supporting terms"],
15+
"format": "blog | linkedin | email | tiktok | ad | press",
16+
"persona": "archetype name from knowledge/personas/",
17+
"persona_evidence_status": "evidence_backed | directional | hypothesis",
18+
"persona_evidence_sources": [
19+
{
20+
"source_type": "interview | sales_call | support_ticket | review | survey | analytics | third_party_research | hypothesis",
21+
"source": "URL, file path, CRM note, or research artifact",
22+
"retrieved_or_observed_date": "YYYY-MM-DD",
23+
"confidence": "high | medium | low"
24+
}
25+
],
26+
27+
"current_rank": "position for target keyword, or not ranking",
28+
"monthly_impressions": 0,
29+
"current_ctr": 0.0,
30+
"data_provenance_mode": "sales_external | onboarding_connected | internal_demo | not_applicable",
31+
"quantitative_claims": [
32+
{
33+
"claim": "exact claim that may appear in output",
34+
"source": "URL, file path, collector output, or internal measurement",
35+
"retrieved_or_observed_date": "YYYY-MM-DD",
36+
"evidence_tier": "official_requirement | official_best_practice | law_regulation_court_status | academic_study | vendor_platform_study | practitioner_benchmark | internal_measurement | inference_hypothesis | missing_data",
37+
"confidence": "high | medium | low"
38+
}
39+
],
40+
"data_gaps": ["known missing data that must not be guessed"],
41+
"competitor_url": "top-ranking URL we're competing against",
42+
"competitor_weakness": "specific gap in their content — not vague",
43+
44+
"angle": "specific frame — not AI for law firms, but why law firms lose 40% of leads after 5pm",
45+
"hook_options": [
46+
"Hook variant 1",
47+
"Hook variant 2",
48+
"Hook variant 3"
49+
],
50+
"audience_pain": "the single biggest frustration of this persona",
51+
"proof_available": "data, stories, or examples we can use",
52+
"proof_inventory": [
53+
{
54+
"proof_type": "customer_quote | product_data | case_study | demo | review | benchmark | legal_requirement | platform_requirement",
55+
"source": "URL, file path, collector output, or note",
56+
"claim_allowed": "what this proof can safely support"
57+
}
58+
],
59+
"cta": "what we want them to do after reading",
60+
61+
"ad_concept_bench": {
62+
"use_when": "required for paid ad batches; omit for non-ad content",
63+
"personas": ["3-5 situational or psychographic personas"],
64+
"desires": ["3-5 customer-language desired outcomes"],
65+
"angles": ["4-8 story, proof, or mechanism frames"],
66+
"concept_math": "personas x desires x angles = total possible concepts",
67+
"portfolio_rule": "60% winners, 30% adjacent tests, 10% experiments",
68+
"selected_concepts": [
69+
{
70+
"concept_id": "PDA-persona-desire-angle-01",
71+
"persona": "who this ad speaks to",
72+
"desire": "the progress they want",
73+
"angle": "the story/proof/frame",
74+
"awareness_stage": "unaware | problem-aware | solution-aware | product-aware | most-aware",
75+
"format": "video | static | carousel | UGC | founder | demo",
76+
"hook": "first line or first 3 seconds",
77+
"portfolio_bucket": "winner | adjacent | experiment",
78+
"kill_rule": "named threshold before launch"
79+
}
80+
]
81+
},
82+
83+
"word_count_target": 1400,
84+
"publish_date": "YYYY-MM-DD",
85+
"internal_links": [
86+
"https://site.com/existing-post-1",
87+
"https://site.com/existing-post-2"
88+
]
89+
}
90+
```
91+
92+
---
93+
94+
## Word Count Targets by Format
95+
96+
| Format | Target |
97+
|--------|--------|
98+
| Blog post | 1200–1800 |
99+
| LinkedIn article | 700–1000 |
100+
| Email | 300–500 |
101+
| TikTok script | 150–300 (spoken words) |
102+
| Meta ad | 50–150 |
103+
| Press release | 400–600 |
104+
105+
---
106+
107+
## Persona Reference
108+
109+
Load the matching file from `knowledge/personas/` before completing the brief.
110+
Available archetypes: check `ls knowledge/personas/` for current list.
111+
112+
Personas must be labeled:
113+
114+
- `evidence_backed`: supported by interviews, sales calls, support tickets, analytics, reviews, or credible research.
115+
- `directional`: supported by partial evidence but still needs validation.
116+
- `hypothesis`: useful for creative exploration only; not enough for client-facing strategy claims.
117+
118+
Do not present a persona pain, budget authority, buying trigger, or objection as fact unless the evidence source is listed.
119+
120+
---
121+
122+
## Outcome Declaration (ECO O1 — required before writing)
123+
124+
A baseline recorded after the piece ships is not a baseline, and a threshold chosen after seeing the result is not a threshold. Capture both here, before the first draft.
125+
126+
```yaml
127+
outcome:
128+
metric: organic_clicks # what this piece is supposed to move
129+
source: google_search_console # the authoritative system, not a dashboard screenshot
130+
baseline: 0 # the pre-state, measured now
131+
threshold: 120 # the number that counts as success
132+
window_days: 30 # when it gets read
133+
owner: Connor # who reads it
134+
attribution: observational # observational | control | holdout | geo_split | switchback
135+
```
136+
137+
This block becomes the `outcome_baseline` evidence entry on the piece's ECO record. Without it the work can reach SHIPPED but never CLOSED.
138+
139+
Floors per format: `harness/eco-floors.yaml` · Doctrine: `docs/system/eco-completion-standard.md`
140+
141+
---
142+
143+
## Brief Validation
144+
145+
Before write agent starts, validate:
146+
- `outcome` block is complete (metric, source, baseline, threshold, window, owner) and recorded before drafting
147+
- All required fields present and non-empty
148+
- `hook_options` has exactly 3 variants
149+
- `competitor_weakness` is specific (≥20 words), not generic
150+
- `angle` is differentiated from `target_keyword` (not just a restatement)
151+
- `proof_available` references actual data or a named example
152+
- `persona_evidence_status` is present and matches the sources
153+
- Every quantitative claim has a source, evidence tier, date, and confidence label
154+
- Missing data is listed in `data_gaps`, not replaced with a benchmark

0 commit comments

Comments
 (0)