@easysociable/cli 0.1.12 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easysociable/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Agent-first CLI for EasySociable: Content Engine, Template, Slideshow, and MCP",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -16,12 +16,26 @@
16
16
  },
17
17
  "keywords": [
18
18
  "easysociable",
19
- "cli",
20
19
  "mcp",
20
+ "mcp-server",
21
+ "model-context-protocol",
22
+ "claude",
23
+ "claude-code",
24
+ "cursor",
25
+ "carousel",
26
+ "social-carousel",
27
+ "slideshow",
28
+ "slideshow-generator",
21
29
  "social-media",
30
+ "tiktok",
31
+ "linkedin",
32
+ "instagram",
33
+ "threads",
34
+ "xiaohongshu",
22
35
  "templates",
23
- "slideshow",
24
- "agent"
36
+ "agent",
37
+ "content-engine",
38
+ "cli"
25
39
  ],
26
40
  "engines": {
27
41
  "node": ">=20.0.0"
@@ -37,13 +51,6 @@
37
51
  "LICENSE",
38
52
  "README.md"
39
53
  ],
40
- "scripts": {
41
- "typecheck": "tsc --noEmit",
42
- "test": "vitest run",
43
- "build": "tsup",
44
- "prepack": "node scripts/prepack.mjs && pnpm build",
45
- "pack:check": "npm pack --dry-run"
46
- },
47
54
  "publishConfig": {
48
55
  "access": "public",
49
56
  "registry": "https://registry.npmjs.org/"
@@ -52,13 +59,19 @@
52
59
  "commander": "^11.1.0"
53
60
  },
54
61
  "devDependencies": {
55
- "@easysociable/mcp-server": "workspace:*",
56
- "@easysociable/template-gateway-client": "workspace:*",
57
- "@easysociable/tsconfig": "workspace:*",
58
- "@easysociable/vitest-config": "workspace:*",
59
62
  "@types/node": "^22.14.0",
60
63
  "tsup": "^8.0.2",
61
64
  "typescript": "^5.8.3",
62
- "vitest": "^1.3.1"
65
+ "vitest": "^1.3.1",
66
+ "@easysociable/mcp-server": "0.0.0",
67
+ "@easysociable/template-gateway-client": "0.0.0",
68
+ "@easysociable/tsconfig": "0.0.0",
69
+ "@easysociable/vitest-config": "0.0.0"
70
+ },
71
+ "scripts": {
72
+ "typecheck": "tsc --noEmit",
73
+ "test": "vitest run",
74
+ "build": "tsup",
75
+ "pack:check": "npm pack --dry-run"
63
76
  }
64
- }
77
+ }
@@ -23,7 +23,7 @@ export const PLATFORM_CAPS = {
23
23
  const FORBIDDEN_PACK_KEYS = ['deck_template_id', 'deckTemplateId']
24
24
 
25
25
  const PACK_KEYS = new Set(['schemaVersion', 'platform', 'title', 'pages'])
26
- const PAGE_KEYS = new Set(['pageTemplateId', 'role', 'slots'])
26
+ const PAGE_KEYS = new Set(['layoutFamilyId', 'pageTemplateId', 'role', 'slots'])
27
27
  export const RUN_FILE_STATUSES = [
28
28
  'RUN_OPEN', 'BRIEF_WAIT', 'DRAFTED', 'EDIT_WAIT', 'SCORED',
29
29
  'READY_TO_POST', 'PUBLISHED', 'HOLD', 'KILLED', 'SUPERSEDED',
@@ -97,8 +97,9 @@ export function validateContentPack(pack, options = {}) {
97
97
  }
98
98
  pushUnknownKeys(errors, page, PAGE_KEYS, label)
99
99
  if (!PAGE_ROLES.includes(page.role)) errors.push(`${label}.role: invalid page role`)
100
- if (typeof page.pageTemplateId !== 'string' || page.pageTemplateId.length === 0) {
101
- errors.push(`${label}.pageTemplateId: required and must be a non-empty string`)
100
+ const layoutRef = page.layoutFamilyId ?? page.pageTemplateId
101
+ if (typeof layoutRef !== 'string' || layoutRef.length === 0) {
102
+ errors.push(`${label}.layoutFamilyId: required (or pageTemplateId) and must be a non-empty string`)
102
103
  }
103
104
  if (!isRecord(page.slots)) {
104
105
  errors.push(`${label}.slots: must be an object`)
@@ -51,17 +51,13 @@ V1 expects an Agent (Grok Bot, Codex, Claude Code, …) to drive setup. The webs
51
51
  ## Lazy auth (Agent script)
52
52
 
53
53
  When a Gateway call returns `AUTH_REQUIRED`, `API_KEY_INVALID`, or the CLI says
54
- `Run easysociable auth login`, respond with:
54
+ `Run easysociable auth login`, run `easysociable auth login` yourself (it waits
55
+ up to 5 minutes for the browser approval) and tell the user:
55
56
 
56
57
  ```text
57
- EasySociable needs a workspace API key before it can create Brands, images, drafts or Slideshow Runs on the Gateway.
58
-
59
- 1. Open https://my.easysociable.com/auth/signup (or sign in with Google).
60
- 2. Verify your email if you used password signup (required before API keys).
61
- 3. Dashboard → API Keys → Create API key → copy the secret once.
62
- 4. Run: easysociable auth login --api-key <paste-key> --gateway-url https://gateway.easysociable.com
63
-
64
- Tell me when that is done and I will continue.
58
+ EasySociable needs to connect to your account. I'm running `easysociable auth login` —
59
+ a browser tab will open: sign in (Google works, free) and click "Authorize Agent".
60
+ I'll continue as soon as you approve.
65
61
  ```
66
62
 
67
63
  After `auth login` succeeds, retry the failed operation with the same
@@ -1,21 +1,20 @@
1
1
  ---
2
2
  name: easysociable-content
3
3
  description: >
4
- Operate the EasySociable Content Engine (profile, needs, products, recommendations, topics, runs, workbench).
4
+ Operate the EasySociable Content Engine: Knowledge (Karpathy LLM Wiki), hook-led
5
+ Topics, formula-led Runs, profile, brand, media, workbench.
5
6
  Triggers: 采访我, 完善人设, interview me, who am I as a creator, 建立 profile
6
7
  — follow workflows/INTERVIEW.md (engine CLAUDE.md § Interview wins if present).
7
- Triggers: 记需求, 扫需求选题, 扫关键词, 路由 Hit, capture audience quotes, user needs, 调研需求, 需求落库
8
- — follow workflows/NEEDS.md + engine CLAUDE.md § Keywords / § Hits / § Needs.
9
- Triggers: 更新产品, 产品库, product facts, product pricing, product offer
10
- — follow the engine CLAUDE.md § Products and edit `products/`.
11
- Triggers: 推荐产品, 评测工具, compare tools, review an AI product
12
- — edit `recommendations/`; do not treat third-party subjects as owned Products.
13
- Triggers: 做成选题, 开一单, 出图
14
- — follow engine CLAUDE.md (§ Topics / § Open a run / § PagePack: Page Contracts → Media → Template Selection before templates).
8
+ Triggers: 记一下, 存资料, ingest, 问知识库, what do we know about, lint 知识库, 整理知识
9
+ — follow engine CLAUDE.md § Knowledge (Ingest / Query / Lint).
10
+ Triggers: 列出 hooks, 选 hook, 用 H-… 生成选题, 做成选题
11
+ — follow engine CLAUDE.md § Topics (Hook → Formula → Knowledge).
12
+ Triggers: 开一单, 用 T-… 开一单, 出图
13
+ — follow engine CLAUDE.md § Open a run (content straight from the Topic's Formula).
15
14
  If no engine exists, copy/clone the Content Engine core (see Create below;
16
15
  `easysociable engine init` is optional offline scaffold). Then follow
17
16
  Content Engine/CLAUDE.md. Render handoff: easysociable-template (1 page) or
18
- easysociable-slideshow (2+). Never publish or post.
17
+ easysociable-slideshow (2+, Formula handoff). Never publish or post.
19
18
  ---
20
19
 
21
20
  # EasySociable Content
@@ -24,62 +23,33 @@ Entry card for agents. **Do not invent a parallel workflow.** Instance SoT is th
24
23
 
25
24
  ## Product boundary
26
25
 
27
- - Teach a **Content Engine** (signal → decision → draft → review → reusable learning).
28
- - **EasySociable** is the **visual production layer** inside that engine — not the content brain, not the whole system.
29
- - For `easysociable-builder` needs research, prefer **L1 system / L2 judgment-review** pains (sustainable publishing) over **L3 visual-tool** friction, unless the user asks for L3.
26
+ - Teach a **Content Engine**: knowledge you own → a hook-led decision → formula-led content → feedback that updates knowledge.
27
+ - **EasySociable** supplies the **Hooks / Formulas catalog** and the **visual production layer** (Studio). It is not the content brain.
30
28
 
31
- ## Pipeline (do not collapse stages)
29
+ ## Three loops (do not collapse)
32
30
 
33
31
  ```text
34
- Profile / Audience
35
- → Needs (verbatim audience quotes)
36
- → optional Product (owned offer facts) or Recommendation (third-party review subject)
37
- → Pillar (what this profile discusses) + Lane (how it publishes)
38
- → Topic (decision summary + readable judgment + Score appendix)
39
- → Run → Pack → Publish / feedback
32
+ Knowledge raw/ (immutable) → knowledge/pages (agent-maintained wiki) → index.md + log.md
33
+ Topics Hook (H-…) → one of its Formulas (F-…) → angle from knowledge pages → T-…
34
+ Runs Topic's Formula beats → content.md + content-pack.v1 → Studio → feedback
40
35
  ```
41
36
 
42
37
  | Stage | Owns | Does not |
43
38
  |-------|------|----------|
44
- | Needs `N-` | Verbatim reader/operator quotes | Watchlist hooks, Agent rewrites |
45
- | Products `P-` | Owned offer facts, pricing, boundaries | Audience demand or third-party reviews |
46
- | Recommendations `R-` | Third-party subject, evidence, limits, disclosure | Owned product claims |
47
- | Pillars / lanes | Durable subject / publishing mode | A replacement for Needs or evidence |
48
- | Topic `T-` | Human judgment card + opp gate | Being auto-created from heat |
49
- | Workbench | Read-only observatory | Source of truth (markdown indexes are) |
39
+ | `raw/` | Verbatim sources + URL | Ever get edited after save |
40
+ | `knowledge/pages` | `source` / `concept` / `entity` / `synthesis` pages with `[[links]]` | Viral-post teardowns; facts no raw source supports |
41
+ | Topic `T-` | `hook_id` + `formula_id` + `knowledge_ids` + Beat plan | Exist without a hook and a formula |
42
+ | Run | One platform; one page per formula beat | Re-pick hook/formula; idea → brief → packet → draft → editor → rubric chain |
43
+ | Workbench | Read-only observatory (Knowledge graph, Topics, Runs) | Source of truth (markdown is) |
50
44
 
51
45
  ## Hard rules
52
46
 
53
- 1. **No invented quotes** — Needs quote cell = verbatim only. Gloss is separate (`layer=L1|L2|L3` allowed in gloss).
54
- 2. **Heat ≠ topic** — External source metrics never make `ready`.
55
- 3. **Never invent `N-` from a product, vendor claim, or headline.** Match captured needs only.
56
- 4. **Topic decision card first** — start with Verdict / Why this status / Who it’s for / Core judgment / Next step, then explain the problem, current belief, angle, timing, expected belief change, evidence gap, and recommended form. **Language:** readable judgment + `one_liner` = profile `voice.md` Language (else pillars / `engine.json` locale); verbatim Needs stay untranslated. Keep scores and IDs in the appendix. Chat output is the readable decision card, not a score walkthrough.
57
- 5. **`N-` never in `capture_id`** — needs go in `need_ids` only.
58
- 6. **Rebuild workbench** after markdown writes in the engine vault.
59
- 7. **Keep ownership explicit** — `products/` is for offers we own or provide;
60
- `recommendations/` is for third-party tools and products. A Topic may cite
61
- `product_ids`, `recommendation_ids`, both, or neither.
62
- 8. **Ask for Topic `generation_mode` before any `produce` write** — present the
63
- six modes; recommend `demand` when Need-led; do not silently assume.
64
- Product/recommendation inputs do not prove audience demand.
65
- 9. **Scan stages Hits, not Needs/Topics** — default keyword scan is
66
- `track=listen` only → `hits/` (`triage`); route to `needs/` or library
67
- only after confirm. `search` = SEO, `ask` = GEO questions — not default
68
- social scan. Hits are never Topic inputs.
69
- 10. **Generate keywords from evidence** — propose listen/search/ask candidates
70
- from Needs/audience in chat; write `keywords.md` only after confirm;
71
- set `seed_from`. Google volume never gates listen.
72
-
73
- Topic modes (ask before `produce`; recommend `demand` when Need-led):
74
-
75
- ```text
76
- demand = Needs + Profile
77
- demand_to_offer = Needs + Product + Profile
78
- demand_to_review = Needs + Recommendation + Profile
79
- review = Recommendation + evidence + Profile
80
- offer_education = Product + mechanism + Profile
81
- profile_thesis = Profile + Pillar
82
- ```
47
+ 1. **No invented facts or quotes** — slot text and Beat plans come from knowledge pages only; gaps go in **Do not claim**.
48
+ 2. **No hook → no topic.** Never invent `H-` / `F-` ids; read them from `easysociable hooks list` / `formulas get`.
49
+ 3. **Knowledge is compiled, not re-derived** — ingest updates every touched page, records contradictions instead of overwriting, regenerates `knowledge/index.md`, appends `knowledge/log.md`.
50
+ 4. **Runs follow the Formula** — same beat count, order and roles; `layoutFamilyId = look.slides[n] ?? look.layouts[role]`.
51
+ 5. **Rebuild workbench** after markdown writes in the engine vault (`python3 workbench/build.py`); after knowledge writes also `python3 scripts/lint-knowledge.py --engine .`.
52
+ 6. Hook link for the user: `https://easysociable.com/hooks/<hook_id>`.
83
53
 
84
54
  ## Create / serve / build
85
55
 
@@ -102,56 +72,39 @@ repo into `<parent>/Content Engine` (never overwrites an existing engine).
102
72
  ```bash
103
73
  easysociable engine serve --engine <parent>/Content Engine --no-open
104
74
  easysociable engine build --engine <parent>/Content Engine
105
- # --sync-workbench refreshes workbench files from the public core checkout
106
75
  ```
107
76
 
108
- On a dedicated agent computer (e.g. Grok Bot), prefer `/workspace` + clone or
109
- `engine init`. Mixed→split vault: see `scripts/migrate-split-vault.py` in the
110
- public repo.
111
-
112
- `python3` is required for the workbench. Observatory: `http://127.0.0.1:8765/workbench/` — top tabs include **需求库 / Needs**. If `serve.py` is already up, do not start a second server; rebuild only.
113
-
114
- Engine methodology updates: `git pull` on the core (or `--sync-workbench`), not
115
- CLI republishes.
77
+ `python3` is required for the workbench. Observatory: `http://127.0.0.1:8765/workbench/` — tabs **Knowledge** (graph) / Topics / Runs. If `serve.py` is already up, do not start a second server; rebuild only.
116
78
 
117
79
  ## Operate
118
80
 
119
81
  1. Resolve account → profile (engine `CLAUDE.md`).
120
82
  2. Route by intent (table below). Prefer engine `CLAUDE.md` sections; use `workflows/*` when that file is newer or the § is missing.
121
- 3. Always return the structured chat card the section defines.
83
+ 3. Always return a short result card in chat.
122
84
  4. Rebuild workbench after writes.
123
85
 
124
86
  | Intent | Action |
125
87
  |--------|--------|
126
88
  | 采访我 / interview me / 完善人设 / 建立 profile | **workflows/INTERVIEW.md** (not a render) |
127
- | 记需求 / 用户原话 / capture audience quotes / 调研需求 / 需求落库 | **workflows/NEEDS.md** (not a render) |
128
- | 加关键词 / 生成 listen\|search\|ask 词 / 扫关键词 / 路由 Hit | Engine **§ Keywords** + **§ Hits** — three-track recipes; scan listen→Hits |
129
- | 更新产品 / 产品库 / product facts | Engine **§ Products** — update owned offer facts and dated pricing |
130
- | 推荐产品 / 评测工具 / compare or review | `recommendations/` — collect evidence and disclosure before Topic |
131
- | 扫需求选题 | **NEEDS.md** then Topics from `needs/` `status=captured` — **ask `generation_mode` first** |
132
- | 做成选题 / 生成 topic | engine **§ Topics** — explicit input; **ask `generation_mode` before write** |
133
- | 开一单 / 用 T-… 开一单 | engine **§ Open a run** (ask platform; multi → N runs) |
134
- | 1 page / `media_mode=single_visual` | **easysociable-template** (after hard gate) |
135
- | 2+ pages / `media_mode=multi_page_pack` (any platform, incl. X + `pack_hook`) | **easysociable-slideshow** (after hard gate + **ADR-0036 identity chain**: Studio login → API key → `easysociable auth login` → create) |
136
- | X / xiaohongshu text-only | No render skill — ship copy from the Run |
89
+ | 记一下 / 存资料 / ingest + link or file | Engine **§ Knowledge · Ingest** |
90
+ | 问知识库 / what do we know about X | Engine **§ Knowledge · Query** (offer to file back as `synthesis`) |
91
+ | lint 知识库 / 整理知识 | Engine **§ Knowledge · Lint** |
92
+ | 列出 hooks / 选 hook / 用 H-… 生成选题 | Engine **§ Topics** |
93
+ | 开一单 / 用 T-… 开一单 | Hard gate → engine **§ Open a run** (ask platform; multi → N runs) |
94
+ | 1 page | **easysociable-template** with `Formula: <id>` (after hard gate) |
95
+ | 2+ pages (any platform) | **easysociable-slideshow** *Formula handoff* (after hard gate + **ADR-0036 identity chain**: Studio login → API key → `easysociable auth login` → create) |
96
+ | X / xiaohongshu text-only | No render skill — ship copy from `content.md` |
137
97
 
138
98
  ## Render hard gate
139
99
 
140
- **Before any template/slideshow call:** Identity in `profiles/<active>/voice.md` — Role / What I build / Point of view — no `(fill)` and non-empty; `boundaries.md` exists with Not covering and Never claim both non-empty. If `needs/` exists, `needs/_index.md` ≥ **3** `N-` rows; if `needs/` is absent, skip that count. Public handle MAY stay `(fill)`.
100
+ **Before any template/slideshow call:** Identity in `profiles/<active>/voice.md` — Role / What I build / Point of view — no `(fill)` and non-empty; `boundaries.md` exists with Not covering and Never claim both non-empty. Public handle MAY stay `(fill)`.
141
101
 
142
102
  On fail: **stay in this skill**. List missing files. Do not call template or slideshow. User must say **强制继续** / **force continue** to proceed.
143
103
 
144
104
  ```bash
145
- easysociable engine validate --run <run-dir> --require-pack --require-knowledge
105
+ easysociable engine validate --root <engine> --require-knowledge
146
106
  ```
147
107
 
148
- Slideshow packs need an **Arc** line, then **Page Contracts** (no `templateId`), then Media, then Template Selection. Do not default Cover → Point → Steps → Recap → CTA. Page 1 is cover/hook class; later pages are not. Handoff: **easysociable-slideshow** (`references/ARC.md`). Validate with `python3 scripts/validate-pack.py`.
149
-
150
- ## Research (Needs)
151
-
152
- - Prefer host research tools. On **X**: built-in `x_*` first; fall back to agent-reach / `twitter` only if insufficient.
153
- - Store **commenter** words when scraping threads. Do not invent `N-` when a platform tool is missing—stop and ask for paste.
154
-
155
108
  ## Out of scope
156
109
 
157
110
  No social posting, Content MCP, Local API, or SQLite content library.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Not a fourth skill. If the engine `CLAUDE.md` already has **§ Interview**, follow that section. Otherwise follow this file.
4
4
 
5
- Do **not** ingest needs / quotes here. Do **not** scan the watchlist. Do **not** create a slideshow or call template/slideshow.
5
+ Do **not** ingest sources into Knowledge here. Do **not** create a slideshow or call template/slideshow.
6
6
 
7
7
  ## Triggers
8
8
 
@@ -59,9 +59,9 @@ Do **not** ingest needs / quotes here. Do **not** scan the watchlist. Do **not**
59
59
 
60
60
  | Level | Condition | Behavior |
61
61
  |-------|-----------|----------|
62
- | **Hard gate** (refuse slideshow handoff / `create_run`) | Identity **only** Role / What I build / Point of view have no `(fill)` and are non-empty (Public handle and Not claiming MAY stay `(fill)` / starter copy) **and** `boundaries.md` exists with Not covering **and** Never claim both non-empty. If `needs/` exists, also `needs/_index.md` ≥ 3 `N-` rows; if `needs/` is absent, skip that count. | Refuse 出图 / PagePack handoff / `slideshows create`. List missing files. User must say **强制继续** / **force continue** to proceed. |
63
- | **First-session goal** | Hard gate **and** Persona has at least one personalized line **and** needs **target 5** (under 5 still passes the hard gate) **and** `stories.md` may be 0–1 | Open card `profile: partial`. May 扫需求选题. Still no graphics unless forced. |
64
- | **Complete seven dimensions** | Identity + Experience (≥2) + Values (≥3) + Persona/Do not say + `stories.md` ≥1 + `boundaries.md` + `expression.md` likes/dislikes ≥3 each + needs ≥5 | Open card `profile: complete`. Remaining gaps are draft reminders only — **not** a hard-stop on graphics. |
62
+ | **Hard gate** (refuse slideshow handoff / `create_run`) | Identity **only** Role / What I build / Point of view have no `(fill)` and are non-empty (Public handle and Not claiming MAY stay `(fill)` / starter copy) **and** `boundaries.md` exists with Not covering **and** Never claim both non-empty. | Refuse 出图 / run handoff / `slideshows create`. List missing files. User must say **强制继续** / **force continue** to proceed. |
63
+ | **First-session goal** | Hard gate **and** Persona has at least one personalized line **and** `stories.md` may be 0–1 | Open card `profile: partial`. May pick a hook and write Topics. Still no graphics unless forced. |
64
+ | **Complete seven dimensions** | Identity + Experience (≥2) + Values (≥3) + Persona/Do not say + `stories.md` ≥1 + `boundaries.md` + `expression.md` likes/dislikes ≥3 each | Open card `profile: complete`. Remaining gaps are draft reminders only — **not** a hard-stop on graphics. |
65
65
 
66
66
  Experience / Values / expression are **not** the hard gate. Missing `stories.md` / `expression.md` = partial. Missing `boundaries.md` file = hard-gate fail.
67
67
 
@@ -3,9 +3,10 @@ name: easysociable-slideshow
3
3
  description: >
4
4
  Create, list, update and review durable multi-page Slideshow Runs for
5
5
  EasySociable from a local Content Pack. Name the argument (arc) first, then
6
- pick a Page Template per page by platform, canvas, slotSummary and density —
7
- never default Cover→Point→Steps→Recap→CTA. Page 1 must be a cover or hook
8
- class template; those templates must not appear on later pages. Use the
6
+ pick a Layout Family per page (one layout, adapted to every platform) by
7
+ role, slotSummary and density — never default Cover→Point→Steps→Recap→CTA.
8
+ A Formula with a Look already fixes each page's Layout Family. Page 1 must
9
+ be a cover or hook class family; those must not appear on later pages. Use the
9
10
  unified `easysociable` CLI or MCP, open Studio to preview and edit, then
10
11
  ask the user to click Download for a PNG ZIP. CLI/MCP must not call
11
12
  render/export or create_render_job for final pixels. Runs remain in the
@@ -14,7 +15,9 @@ description: >
14
15
 
15
16
  # EasySociable Slideshow Skill
16
17
 
17
- A Slideshow Run is a composition of explicit single-page Templates.
18
+ A Slideshow Run is a composition of explicit Layout Families, one per page.
19
+ A Layout Family is one layout whose templates differ only by platform canvas,
20
+ so one Run yields the carousel for every platform (Studio switches variants).
18
21
  It is not a reusable Carousel/Deck Template and it is not a public post.
19
22
  Page order is the argument of **this pack**, not a catalog recipe.
20
23
 
@@ -23,12 +26,15 @@ Page order is the argument of **this pack**, not a catalog recipe.
23
26
  1. Read a local `content-pack.v1` from the Content Engine.
24
27
  2. Use the unified `easysociable` CLI or the unified MCP server. All hosted
25
28
  calls go through Gateway; never call Directus, R2, Stripe or private services.
26
- 3. Choose a Brand (or Profile/Theme) and an explicit Page Template for every
27
- page. The server never silently chooses or replaces a Page Template.
28
- Prefer templates already chosen on the Content Engine pack (**Template
29
- Selection** after **Page Contracts**). Otherwise get a shortlist from
29
+ 3. Choose a Brand (or Profile/Theme) and an explicit Layout Family for every
30
+ page, sent as `layoutFamilyId` in the pack (Gateway resolves it to the
31
+ family's template on the Run's native canvas; `pageTemplateId` is still
32
+ accepted). The server never silently chooses or replaces a layout.
33
+ Order of precedence: (a) a Formula **Look** (see Formula handoff),
34
+ (b) families already chosen on the Content Engine pack (**Template
35
+ Selection** after **Page Contracts**), (c) a shortlist from
30
36
  `easysociable slideshows recommend --file contracts.json --seed <slug>`
31
- (MCP `recommend_slideshow_templates`) and pick one per page with a reason.
37
+ (MCP `recommend_slideshow_templates`) — pick one `familyId` per page with a reason.
32
38
  The recommender filters platform + native canvas + slotSummary + cover rule,
33
39
  demotes Layout Families used in the owner's recent Runs, and keeps one
34
40
  unused family per page. `role` / `supportedRoles` are weak retrieval tags,
@@ -41,8 +47,10 @@ Page order is the argument of **this pack**, not a catalog recipe.
41
47
  use metric / quote / compare / value / steps / cta / etc. Do not put a
42
48
  Point or metric-only template on page 1 to “open with a number” — pick a
43
49
  cover or hook template whose slots fit the opening copy.
44
- 5. A Run has up to 8 pages on Free and 20 on paid, one supported platform
45
- (`tiktok`, `instagram`, `linkedin` or `threads`) and one Brand across pages.
50
+ 5. A Run has up to 8 pages on Free and 20 on paid, one native platform
51
+ (`tiktok`, `instagram`, `linkedin` or `threads`; it sets the page cap and
52
+ the canvas edited first) and one Brand across pages. Studio renders the
53
+ same Run for every platform its Layout Families support.
46
54
  6. Topology is fixed after creation: no add, copy, delete, reorder or template
47
55
  switch. Page-instance slot/layout/type/style/decoration edits remain allowed
48
56
  in Studio.
@@ -51,8 +59,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
51
59
  or MCP `render_slideshow_run` / `create_render_job`. Those return
52
60
  `HEADLESS_RENDER_DISABLED`.
53
61
  8. Before creating a new Run, list/find prior Runs by `contentSlug`. **Update**
54
- the same Run only when page count, pageTemplateIds, and intended sequence
55
- still match. A different arc or template set is a **new Run** — never PATCH
62
+ the same Run only when page count, Layout Families, and intended sequence
63
+ still match. A different arc or family set is a **new Run** — never PATCH
56
64
  new copy into a locked Cover-Point-Steps-Recap-CTA skeleton.
57
65
  8b. **Knowledge hard gate (every create, not only the first Run):** before
58
66
  `create_run` / `slideshows create`, read Identity (Role / What I build /
@@ -62,13 +70,16 @@ Page order is the argument of **this pack**, not a catalog recipe.
62
70
  If `needs/` exists, `needs/_index.md` ≥ 3 `N-` rows; if `needs/` is absent, skip that count. Fail → hand back to
63
71
  **easysociable-content** / refuse create; list missing files. Do not add
64
72
  Gateway or MCP params. User must say **强制继续** / **force continue**
65
- to call Gateway.
73
+ to call Gateway. **Exempt:** Formula handoff Runs (prompt names
74
+ `Formula: F-…`) — the Formula supplies the arc and the user supplies the
75
+ topic, so a first-time user with no Content Engine is not blocked.
66
76
  8c. **Identity chain (ADR-0036, hard):** before create, the CLI must be
67
77
  logged in with the **user's Dashboard Workspace API key** (same account
68
78
  that will open Studio). Refuse fixture `workspace_local` / local
69
79
  `test-key` unless the user explicitly asked for a local fixture
70
- (`--allow-local-fixture`). Order: Studio login → create API key →
71
- `easysociable auth login --api-key <key>` → create Run → open
80
+ (`--allow-local-fixture`). Order: `easysociable auth login` (opens the
81
+ browser; the user approves once and the key is stored — use
82
+ `--api-key <key>` only when headless) → create Run → open
72
83
  `studioUrl` while logged in as that user. If Studio shows “belongs to
73
84
  another account”, recreate with the current key — do not invent
74
85
  cross-workspace access.
@@ -87,10 +98,10 @@ Page order is the argument of **this pack**, not a catalog recipe.
87
98
  `python3 scripts/validate-pack.py runs/<slug>/pack.md` (in the Content Engine).
88
99
  Refuse create if contracts are empty or contain `templateId`.
89
100
  3. Resolve or create the user's Brand through the unified CLI/MCP.
90
- 4. Prefer pack **Template Selection** ids. Otherwise run
101
+ 4. Use the Formula Look's families, else pack **Template Selection**. Otherwise run
91
102
  `easysociable slideshows recommend --file contracts.json --seed <slug> --json`
92
- and choose from each page's `candidates`; never place a cover/hook class
93
- template after page 1. Report `gaps` (pages with < 2 role-matching
103
+ and choose a `familyId` from each page's `candidates`; never place a cover/hook class
104
+ family after page 1. Report `gaps` (pages with < 2 role-matching
94
105
  templates) to the user as authoring backlog. Record Layout Family evidence
95
106
  as `hypothesis` unless published comparable results support `tested` /
96
107
  `supported` — a template having been used before is not evidence.
@@ -108,7 +119,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
108
119
  ```
109
120
 
110
121
  Fail → refuse; return to **easysociable-content**. **强制继续** / **force continue**
111
- is the only override (conversational — not a CLI flag). Then:
122
+ is the only override (conversational — not a CLI flag). Formula handoff
123
+ Runs skip this knowledge check (rule 8b) but not the identity gate. Then:
112
124
 
113
125
  ```bash
114
126
  easysociable slideshows create --file ./pack.json --json
@@ -119,6 +131,29 @@ Page order is the argument of **this pack**, not a catalog recipe.
119
131
  9. After explicit user confirmation, tell them to click **Download** in Studio.
120
132
  Do not render or export from CLI/MCP.
121
133
 
134
+ ## Formula handoff (prompt names a `Formula: F-…` id)
135
+
136
+ 1. `easysociable formulas get --id <id> --json` (falls back to the hosted
137
+ catalog). Not found → tell the user; do not guess a structure.
138
+ 2. The formula's `beats` are the page order: one page per beat, same roles,
139
+ same count. Its `title_template` with `{X}` = the user's topic is the arc
140
+ line, so rule 10 is satisfied by the formula, not by P0 family names.
141
+ 3. Write each page's copy from `beat.fill` and the user's topic. Ask at most
142
+ one question when tip/point pages need facts the topic doesn't supply.
143
+ Never copy sentences from the formula's viral example posts.
144
+ 4. **Look = copy the layout.** If the prompt names `Look: L-…` (else use the
145
+ formula's first entry in `looks`), set each page's `layoutFamilyId` to
146
+ `look.slides["<1-based slide number>"]` if present, else
147
+ `look.layouts[beat.role]`. Do not run `slideshows recommend` for those
148
+ pages and ignore the "demote recently used families" preference — the
149
+ user asked for this layout. Only roles missing from the Look fall back to
150
+ the recommender. Copy layout only: colours and fonts come from the user's
151
+ Brand. If a Look family has image slots, ask the user for images (or say
152
+ which slots are empty) instead of delivering blank image slots.
153
+ 5. Turn beats into Page Contracts, then continue at Workflow step 3
154
+ (Brand → families → identity gate → create → Studio). The knowledge gate
155
+ (rule 8b) does not apply to Formula handoff Runs.
156
+
122
157
  ## Failure handling
123
158
 
124
159
  - If the knowledge hard gate fails, do not create the Run. Hand back to
@@ -128,6 +163,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
128
163
  class template, stop and rebuild the Pack. Do not create the Run.
129
164
  - If a page template, slot or image is invalid, return the structured Gateway
130
165
  error to the Agent; do not substitute another template.
166
+ - `LAYOUT_FAMILY_NOT_FOUND`: the family has no template for the Run's
167
+ platform. Tell the user and pick another platform or family; do not guess.
131
168
  - If Download is exhausted (`USAGE_LIMIT_REACHED`) or past due, tell the user
132
169
  to upgrade or update billing.
133
170
  - If a Run was deleted, or Gateway returns `RUN_TOPOLOGY_LOCKED` because the
@@ -1,8 +1,11 @@
1
1
  # ContentPack v1
2
2
 
3
3
  Page `role` is a **weak retrieval tag** (layout-ish), not sequence position.
4
- `pageTemplateId` is the explicit published single-page template chosen by the
5
- Agent. `slots` are public values only. Do not add a `deck_template_id`,
4
+ `layoutFamilyId` is the explicit Layout Family chosen by the Agent (from a
5
+ Formula Look or the recommender's `familyId`); Gateway resolves it to that
6
+ family's template on the pack platform's canvas, and Studio derives the other
7
+ platforms from the same family. `pageTemplateId` (one exact template) is still
8
+ accepted and wins when both are sent. `slots` are public values only. Do not add a `deck_template_id`,
6
9
  `bindingMap`, AST, ContentDocument, or product `arc` / `pageSequence`.
7
10
 
8
11
  The Gateway validates each `role` against the closed enum and that slots exist.
@@ -21,10 +24,10 @@ Opening beat is cost; page 1 is still a hook-class template.
21
24
  "platform": "tiktok",
22
25
  "title": "Stop briefing a blank canvas",
23
26
  "pages": [
24
- { "role": "hook", "pageTemplateId": "tpl_hook_001", "slots": { "text_0": "You finish the copy. Then you start over.", "text_1": "The design file kept none of the argument." } },
25
- { "role": "point", "pageTemplateId": "tpl_stack_001", "slots": { "text_0": "Roles, Brand, Layouts persist" } },
26
- { "role": "steps", "pageTemplateId": "tpl_stair_001", "slots": { "text_0": "Use them in that order" } },
27
- { "role": "cta", "pageTemplateId": "tpl_close_001", "slots": { "text_0": "Don't brief a blank canvas" } }
27
+ { "role": "hook", "layoutFamilyId": "fam_hook_001", "slots": { "text_0": "You finish the copy. Then you start over.", "text_1": "The design file kept none of the argument." } },
28
+ { "role": "point", "layoutFamilyId": "fam_stack_001", "slots": { "text_0": "Roles, Brand, Layouts persist" } },
29
+ { "role": "steps", "layoutFamilyId": "fam_stair_001", "slots": { "text_0": "Use them in that order" } },
30
+ { "role": "cta", "layoutFamilyId": "fam_close_001", "slots": { "text_0": "Don't brief a blank canvas" } }
28
31
  ]
29
32
  }
30
33
  ```
@@ -44,10 +47,10 @@ Opening beat is cost; page 1 is still a hook-class template.
44
47
  }
45
48
  ```
46
49
 
47
- Pick templates by **platform + canvas + slotSummary + density**, not by matching
48
- the beat name to a family named Cover / Point / Steps / Recap / CTA. Page 1
49
- must still be cover/hook class.
50
+ Pick families by **slotSummary + density** (or take them from a Formula Look),
51
+ not by matching the beat name to a family named Cover / Point / Steps / Recap /
52
+ CTA. Page 1 must still be cover/hook class.
50
53
 
51
54
  The renderer accepts any supported page count within the platform cap. A newly
52
- published Page Template can be selected in a new Run without creating a
55
+ published Layout Family can be selected in a new Run without creating a
53
56
  carousel asset.
@@ -7,22 +7,23 @@
7
7
  stop and hand back to **easysociable-content** — do not invent page
8
8
  purposes from catalog family names.
9
9
  3. Build `content-pack.v1` from that argument. Page count follows the beats
10
- (TikTok often 4–8), not the number of P0 families. Carry the chosen
11
- `pageTemplateId`s from Template Selection (explicit — server must not
12
- silent-replace).
10
+ (TikTok often 4–8), not the number of P0 families. Each page carries an
11
+ explicit `layoutFamilyId` (explicit — server must not silent-replace):
12
+ Formula handoff with a Look → `look.slides[slideNumber] ?? look.layouts[beat.role]`; else the pack's
13
+ Template Selection. One Run covers every platform the families support.
13
14
  4. Check platform hardMin/hardMax.
14
- 5. No Template Selection on the pack → shortlist with
15
+ 5. No Look and no Template Selection → shortlist with
15
16
  `easysociable slideshows recommend --file contracts.json --seed <slug> --json`
16
17
  (MCP `recommend_slideshow_templates`). Input is the Page Contracts:
17
18
  `{ platform, pages: [{ role, density?, slotSummary?: { text, number, image }, requiresImage? }] }`.
18
- Pick one candidate per page and record the reason; `supportedRoles` is a
19
+ Pick one candidate `familyId` per page and record the reason; `supportedRoles` is a
19
20
  weak tag. `pages[0]` must be cover/hook class. Do not use that class on
20
21
  later pages. W- judgments (`fits` / `avoid`) with comparable evidence may
21
22
  override the recommender's order. Surface `gaps` to the user.
22
23
  6. If `contentSlug` already has a Run: update only when topology matches
23
- (same page count and `pageTemplateId`s). Otherwise create a new Run.
24
- 7. **Before** `create_run` / `slideshows create` (every create, not only the
25
- first Run): check the knowledge hard gate — Identity Role / What I build /
24
+ (same page count and Layout Families). Otherwise create a new Run.
25
+ 7. **Before** `create_run` / `slideshows create` (every create except
26
+ Formula handoff Runs): check the knowledge hard gate — Identity Role / What I build /
26
27
  Point of view have no `(fill)` and are non-empty; `boundaries.md` exists
27
28
  with Not covering and Never claim non-empty; if `needs/` exists, ≥3 `N-`
28
29
  rows, else skip. Read the files or run
@@ -31,12 +32,13 @@
31
32
  files. User must say **强制继续** / **force continue** to call Gateway.
32
33
  No new Gateway or MCP params.
33
34
  7b. **Identity chain (ADR-0036):** confirm CLI auth is the user's Dashboard
34
- Workspace API key (not `workspace_local` / `test-key`). If needed:
35
- Studio login → Dashboard create key →
36
- `easysociable auth login --api-key <key>`. Refuse create on fixture
35
+ Workspace API key (not `workspace_local` / `test-key`). If needed run
36
+ `easysociable auth login` (browser approval; `--api-key <key>` only when
37
+ headless). Refuse create on fixture
37
38
  identity unless the user asked for `--allow-local-fixture`.
38
39
  8. Call `create_run` / `slideshows create` through Gateway with the explicit
39
- template ids from the pack.
40
+ `layoutFamilyId`s from the pack. `LAYOUT_FAMILY_NOT_FOUND` → the family has
41
+ no template for this platform; tell the user, do not guess.
40
42
  9. Save `runId`, `studioUrl`, and `status=draft`. Tell the user to open
41
43
  `studioUrl` **while logged into the same Studio account**.
42
44
  10. Do not call a Deck API, create a carousel template, or send a product