@aicopycoders/exodus 2026.6.2400 → 2026.6.2700-beta.3
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/assets/docs/CLAUDE.md +125 -0
- package/assets/docs/PIPELINES.md +202 -0
- package/assets/skills/exodus-genesis/SKILL.md +13 -5
- package/assets/skills/exodus-write/SKILL.md +2 -0
- package/dist/commands/genesis.js +17 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +6 -2
- package/dist/lib/assets.d.ts +1 -0
- package/dist/lib/assets.js +3 -0
- package/dist/lib/scaffold.d.ts +1 -0
- package/dist/lib/scaffold.js +20 -1
- package/package.json +11 -3
- package/assets/skills/genesis-bots/.env.example +0 -12
- package/dist/commands/__tests__/genesis.hookgate.test.d.ts +0 -1
- package/dist/commands/__tests__/genesis.hookgate.test.js +0 -12
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Creative Strategy Workspace
|
|
2
|
+
|
|
3
|
+
> **New here?** Your onboarding home is the Exodus dashboard (Settings → Claude Code) — it walks you through install and keys. If anything's broken at runtime, run `npx @aicopycoders/exodus doctor` from this directory — it diagnoses local and dashboard-side issues in one shot.
|
|
4
|
+
|
|
5
|
+
This is a creative-strategy workspace operated by the **exodus** CLI. It is brand-agnostic infrastructure serving **all of the account's brands**: each brand has its own subfolder here (marked by a `.exodus-brand.json` file) holding that brand's `state/` and `output/`. Which brand you're working on resolves **folder first, pointer second**: commands run from inside a brand's subfolder target that brand automatically; otherwise the `npx @aicopycoders/exodus brand use <slug>` pointer applies. (Older single-brand installs keep `state/` and `output/` at this root — same rules, one brand.)
|
|
6
|
+
|
|
7
|
+
**How to engage the system:** every skill here is namespaced `exodus-*`, and a front-door `exodus` hub skill routes generic asks. Members say "exodus" to engage ("exodus, write me some ads") or invoke a specific skill with `/exodus-<name>` (e.g. `/exodus-write`). This namespacing is deliberate: it lets these skills coexist with other skill packs (like the workshop pack) installed in the same folder, and it keeps the bare word "Genesis" unambiguous — on its own, "Genesis" always means the member's own Genesis API key/recipes, never Exodus. CLI commands are unchanged (`npx @aicopycoders/exodus genesis`, `npx @aicopycoders/exodus brand use`, etc.).
|
|
8
|
+
|
|
9
|
+
The strategist persona, the Luke Mills / Genesis frameworks, the operating rules and creative principles, and the operating discipline all live in **one skill** plus its references:
|
|
10
|
+
|
|
11
|
+
- `.claude/skills/exodus-strategist/SKILL.md` — the single always-on creative-strategy skill: persona, operating rules, creative principles, red flags, active-brand resolution, the quality bars, and a **Framework Index** that routes to the depth below
|
|
12
|
+
- `references/` — the framework depth, consulted from the skill when needed: `creative-strategy.md` (the encyclopedia + Genesis bot catalog), `segments.md`, `copy-blocks.md` (P3C2), `cast-video.md` (CAST), `iterations.md` (CASHED), `editing-rules.md`, `scrawls.md`, `hook-quality-checklist.md`, `awareness-framework.md`
|
|
13
|
+
|
|
14
|
+
If the persona isn't firing for you, check that the skill loaded. It is not optional reading.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Two systems in this folder: Exodus (automatic) + Genesis (manual)
|
|
19
|
+
|
|
20
|
+
This folder usually holds **two related products that share the same Genesis engine** — keep them straight. Think of it as a car: same engine underneath, two ways to drive it.
|
|
21
|
+
|
|
22
|
+
- **Exodus — the automatic transmission.** This workspace: the `exodus-*` skills and the `npx @aicopycoders/exodus` CLI. Pre-built, done-for-you pipelines (write, image, idea bank, brand onboarding) that drive the Genesis bots *for* you against your brand. You engage it by saying **"exodus"** ("exodus, write me some ads"). Its keys are `EXODUS_API_KEY` / `EXODUS_API_URL` in `.env`; Genesis access is internal — there's nothing to configure or debug about Genesis for Exodus to work.
|
|
23
|
+
|
|
24
|
+
- **Genesis (standalone) — the manual transmission.** A separate skill at `.claude/skills/genesis-bots` that calls the *same* Genesis copywriting / research / strategy bots **directly** with the member's own `gen_` key — you pick a bot and prompt it yourself. It reads `GENESIS_API_KEY` plus a provider key (`ANTHROPIC_API_KEY` or `OPENROUTER_API_KEY`) from `.env`. This is the member's own workflow, **not** owned by the `exodus-*` skills. (It may not be installed in every folder — check for the `genesis-bots` skill.)
|
|
25
|
+
|
|
26
|
+
**Routing rule:** "exodus …" → the Exodus pipelines below. Bare **"genesis"**, "run the bots", or a named bot slug → the `genesis-bots` skill (the member's direct workflow — never route it into Exodus). If someone clearly just wants ads and doesn't know which system they have, ask one question — "drive the Genesis bots directly, or run an Exodus pipeline?" — rather than guessing.
|
|
27
|
+
|
|
28
|
+
**Provider key:** the manual Genesis bots need a provider key in `.env`. `npx @aicopycoders/exodus keys pull` syncs your dashboard provider + image keys down for you (the install runs it; safe to re-run anytime keys change). Exodus's own pipelines don't need it locally — they run server-side.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Multi-Brand Operating Notes
|
|
33
|
+
|
|
34
|
+
Any user can create and own unlimited brands — `npx @aicopycoders/exodus brand create "<name>"` (or the dashboard); it is NOT admin-only, and brand names are scoped per user (two users can each have a "Matt Beard"). One account key then switches across every brand the user owns (admins: every brand). The only exception is a brand someone ELSE invited the user into — they don't own it, so their key stays pinned to just that one. Never tell a user they can't make brands or are "locked to one brand" just because their key shows `role: member`. The active brand resolves **folder > pointer > key default**: being inside a brand's subfolder wins, then the `brand use` pointer, then the key's default brand.
|
|
35
|
+
|
|
36
|
+
- **Identify the active brand:** `npx @aicopycoders/exodus brand current` (also says whether it came from the folder or the pointer)
|
|
37
|
+
- **List accessible brands:** `npx @aicopycoders/exodus brand list`
|
|
38
|
+
- **Create a new brand:** `npx @aicopycoders/exodus brand create "<name>"` — creates it server-side, switches you in, and sets up its local subfolder
|
|
39
|
+
- **Switch brand:** `npx @aicopycoders/exodus brand use <slug>` — or just work from inside that brand's subfolder
|
|
40
|
+
- **New brand created on the dashboard?** `npx @aicopycoders/exodus@latest init` creates its subfolder and pulls its profile
|
|
41
|
+
- **Brand voice / ICP / offer:** the active brand's `state/brand-profile.md` (inside its subfolder; at this root on older single-brand installs) — read this at session start and after any switch. If it doesn't match the active brand, the exodus-strategist skill will prompt to refresh.
|
|
42
|
+
|
|
43
|
+
Don't carry voice or proven angles across brands — each brand is its own creative universe.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Available Pipelines
|
|
48
|
+
|
|
49
|
+
### Exodus pipelines (automatic)
|
|
50
|
+
|
|
51
|
+
These are the **Exodus** pipelines — the automatic system that drives the Genesis bots for you. Use them to generate and analyze creative. Each has its own skill directory in `.claude/skills/`. Invoke them by saying "exodus" plus what you want, or directly with `/exodus-<name>`.
|
|
52
|
+
|
|
53
|
+
| Pipeline | Skill | When to Use |
|
|
54
|
+
|----------|-----------|-------------|
|
|
55
|
+
| **Write** | `exodus-write` | **Start here for copywriting.** Say what you want ("exodus, write me some ads"); it routes new-brand → foundation → brief → genesis → Doc and sequences the whole flow. |
|
|
56
|
+
| **Genesis** | `exodus-genesis` | Brief → ad copy in two voices (Mario + Infeed). Default 1 pass = 2 variants; scale with `--passes` (pass 2 adds the Top-Ads-biased primer). Also writes from a pasted reel (`--reel`). |
|
|
57
|
+
| **Idea** | `exodus-idea` | The Idea Bank — capture reels/brain-dumps/swipes into formed ideas, curate them, then write the keepers through Genesis. Use when collecting and curating ideas rather than writing one ad on the spot. |
|
|
58
|
+
| **Image** | `exodus-image` | **Start here for static images.** Say what you want; it reads the request and routes to the right engine — `exodus-creative` (renders from copy) or `exodus-template` (33 ad-type formats). |
|
|
59
|
+
| **Creative** | `exodus-creative` | A specific creative-suite engine (native / copy-derived renders from copy, or ref-match to a reference image) when you've already picked one. Otherwise start at **Image**. |
|
|
60
|
+
| **Template** | `exodus-template` | Finished ad copy → many static ads across 33 structured formats (testimonial, hero, UGC…). Otherwise start at **Image**. |
|
|
61
|
+
| **Meme** | `exodus-meme` | Meme ads — recommends formats for a brief, then one batched run renders AI-image and classic Imgflip-template memes server-side. |
|
|
62
|
+
| **Browse** | `exodus-browse` | View history and retrieve past outputs |
|
|
63
|
+
| **Drive** | `exodus-drive` | Read/write Google Docs, Sheets, and Drive files via `npx @aicopycoders/exodus drive` (uses the dashboard's Google OAuth — no local CLI) |
|
|
64
|
+
|
|
65
|
+
For the operator-facing quick reference on how to invoke these in Claude Code, see `PIPELINES.md` in the workspace root.
|
|
66
|
+
|
|
67
|
+
### Genesis bots (manual)
|
|
68
|
+
|
|
69
|
+
The same folder usually also carries **`genesis-bots`** — the *manual* way to drive the same Genesis bots. You pick a bot and prompt it yourself with the member's own `gen_` key, chaining bots by hand (buyer profile → creative brief → ad hooks → ads). It is **not** an `exodus-*` skill and is **never** invoked by saying "exodus".
|
|
70
|
+
|
|
71
|
+
| Skill | When to Use |
|
|
72
|
+
|-------|-------------|
|
|
73
|
+
| `genesis-bots` | The user says bare **"genesis"**, "run the bots", "openclaw", or names a bot slug, and wants to call a Genesis copywriting / research / strategy / image-prompt bot directly. Needs `GENESIS_API_KEY` plus a provider key (`ANTHROPIC_API_KEY` or `OPENROUTER_API_KEY`) in `.env` — see **Dashboard** below. May not be installed in every folder — check for the skill directory before assuming it's there. |
|
|
74
|
+
|
|
75
|
+
Route a bare-"genesis" ask to this skill and an "exodus …" ask to the pipelines above — never cross the two. If someone clearly just wants ads and doesn't know which system they have, ask one question ("drive the Genesis bots directly, or run an Exodus pipeline?") rather than guessing.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Awareness Level Routing
|
|
80
|
+
|
|
81
|
+
Every ad targets an audience at a specific awareness level. Getting this right is one of the highest-leverage decisions in creative strategy.
|
|
82
|
+
|
|
83
|
+
> `--awareness` sets the audience awareness level for a Genesis run (unaware / problem-aware / solution-aware / product-aware). Pick the level the idea is actually written for.
|
|
84
|
+
|
|
85
|
+
| Level | Audience State | Ad Approach |
|
|
86
|
+
|-------|---------------|-------------|
|
|
87
|
+
| **Unaware** | Doesn't know they have a problem | Shock, pattern interrupt, reveal |
|
|
88
|
+
| **Problem-Aware** | Knows the problem, not the solution | Educate, validate, agitate |
|
|
89
|
+
| **Solution-Aware** | Knows solutions exist, not ours | Compare, differentiate, position |
|
|
90
|
+
| **Product-Aware** | Knows the brand, hasn't bought yet | Offer, urgency, social proof |
|
|
91
|
+
|
|
92
|
+
Routing detail and signal patterns live in `.claude/skills/exodus-strategist/SKILL.md` and `references/creative-strategy.md`.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Dashboard
|
|
97
|
+
|
|
98
|
+
This workspace connects to a live dashboard for:
|
|
99
|
+
- Settings management (defaults, account connections)
|
|
100
|
+
- **Pipeline keys** — your provider LLM key (Anthropic or OpenRouter) plus Kie.ai, entered once in Settings → Pipeline Keys
|
|
101
|
+
- Google Drive credentials (where outputs are saved)
|
|
102
|
+
- Run history and output retrieval
|
|
103
|
+
- Ad account connections (e.g. the Genesis top-ads-biased track)
|
|
104
|
+
- Brand admin (switching, profile management)
|
|
105
|
+
|
|
106
|
+
The dashboard URL and your `EXODUS_API_KEY` live in `.env`.
|
|
107
|
+
|
|
108
|
+
**Keys & setup.** Exodus's own pipelines run server-side and need nothing beyond `EXODUS_API_KEY` — there's no provider key to configure for them. The **manual `genesis-bots` path** (and other local tools) *do* need a provider key in `.env`. Enter your keys once in the dashboard, then pull them down:
|
|
109
|
+
|
|
110
|
+
- `npx @aicopycoders/exodus keys pull` — writes your dashboard provider + Kie.ai keys into `.env` (the install runs this for you; safe to re-run anytime a key changes). It only upserts the keys and preserves the rest of the file.
|
|
111
|
+
- `npx @aicopycoders/exodus keys status` — shows which keys are set in the dashboard vs locally. Values are never printed.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Reviewing Run Output
|
|
116
|
+
|
|
117
|
+
When you need to review a run's creative output, always read it via `npx @aicopycoders/exodus read-doc <runId>`. This walks every tab of the Google Doc and gives you the full output as markdown.
|
|
118
|
+
|
|
119
|
+
Do **not** use the Drive MCP as your first choice — it only sees tab 1 and will misreport the run as empty. If `npx @aicopycoders/exodus read-doc` exits with code 2 (`unavailable`), fall back to the Drive MCP using the URL printed by the command, and warn the user in your summary that you only saw tab 1.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Tool Feedback
|
|
124
|
+
|
|
125
|
+
This workspace is also a testbed for the CLI and pipelines. When you run a pipeline and hit a gap — a missing input, missing output, missing filter, awkward flow — log it per the **Tool Feedback Protocol** in `.claude/skills/exodus-strategist/SKILL.md`. Your feedback drives the next round of pipeline improvements.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Pipelines Cheat Sheet
|
|
2
|
+
|
|
3
|
+
In Claude Code you don't click buttons. You say **"exodus"** plus what you want — "exodus, write me some ads" — and the `exodus` hub skill routes you to the right pipeline. You can also invoke a specific skill directly with a slash command: `/exodus-write`, `/exodus-image`, etc.
|
|
4
|
+
|
|
5
|
+
> This doc is the CLI/skill invocation reference for the active brand workspace. For the dashboard's clickable pipeline list, see the dashboard's Creative Suite.
|
|
6
|
+
|
|
7
|
+
## All skills at a glance
|
|
8
|
+
|
|
9
|
+
| Skill | What it does |
|
|
10
|
+
|-------|--------------|
|
|
11
|
+
| exodus-write | The front door — routes brand → foundation → brief → Genesis → Doc. Start here. |
|
|
12
|
+
| exodus-genesis | Brief → Ad Copy (two voices; 1 pass = 2 variants, scalable via --passes) |
|
|
13
|
+
| exodus-image | The front door for static images — routes to exodus-creative or exodus-template. Start here for "make me images / statics". |
|
|
14
|
+
| exodus-creative | Creative-Suite Engines (native / copy-derived / ref-match) — when you've already picked an engine |
|
|
15
|
+
| exodus-template | Ad-Type Format Variations across 33 structured formats |
|
|
16
|
+
| exodus-meme | Meme Ad Generator — recommend formats, one batched server-side run |
|
|
17
|
+
| exodus-browse | View History and Surface the Right Run |
|
|
18
|
+
| exodus-drive | Google Drive, Docs, Sheets via the Dashboard's OAuth |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## exodus-write (start here)
|
|
23
|
+
|
|
24
|
+
**What it does:** The guided front door for copywriting. You don't need to know which command to run — say "exodus" plus what you want and the exodus-write flow figures out where you are, helps shape the brief, sets up your foundation if needed, runs Genesis, and hands back the Google Doc.
|
|
25
|
+
|
|
26
|
+
```operator-guide
|
|
27
|
+
No command — say "exodus" plus what you want (or /exodus-write). It sequences
|
|
28
|
+
the existing commands (foundation, genesis, browse, read-doc) for you.
|
|
29
|
+
|
|
30
|
+
Say things like:
|
|
31
|
+
"exodus, I want to write some ads: <your idea>"
|
|
32
|
+
"exodus, turn this winning ad into copy: <paste>"
|
|
33
|
+
"exodus, set up a new brand and write my first ad"
|
|
34
|
+
"exodus, make a variant of that last run"
|
|
35
|
+
|
|
36
|
+
Routing:
|
|
37
|
+
new brand / no foundation → onboarding (foundation, optional primer prompt)
|
|
38
|
+
brief or idea in hand → straight to the Genesis writing pass
|
|
39
|
+
rerun / tweak → browse past runs + the editing menu
|
|
40
|
+
Works without a primer (defaults); sharper once your foundation has winning examples.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## exodus-genesis
|
|
46
|
+
|
|
47
|
+
**What it does:** Take a brief through Luke's full Genesis writing process — two voices (Mario × Brand + Infeed × Brand). Default is 1 pass per bot = 2 variants; add `--passes` to widen coverage (pass 2 brings in the Top-Ads-biased primer). Also accepts per-run seeds extracted from a source ad.
|
|
48
|
+
|
|
49
|
+
```operator-guide
|
|
50
|
+
Inputs:
|
|
51
|
+
--brief <file|"text"> (required) — path to a text file OR an inline brief string
|
|
52
|
+
Optional:
|
|
53
|
+
--seeds <file|"text"> — per-run creative seeds (file: one per line or JSON array; inline: one string)
|
|
54
|
+
--awareness — unaware | problem-aware (default) | solution-aware | product-aware
|
|
55
|
+
--passes <n> — writing passes per bot (1–5, default 1). 1 pass = 2 variants
|
|
56
|
+
(1 Mario×Brand + 1 Infeed×Brand); pass 2 adds the Top-Ads-biased primer
|
|
57
|
+
--variants <n> — advanced: raw total count (1–10) that overrides --passes
|
|
58
|
+
--ad-account <id> — Meta ad account for the top-ads-biased track (defaults to first active account)
|
|
59
|
+
--no-wait — return immediately with the run ID
|
|
60
|
+
Returns: Google Doc URL printed to stdout when the run completes
|
|
61
|
+
Examples:
|
|
62
|
+
exodus genesis run --brief brief.txt --seeds seeds.txt
|
|
63
|
+
exodus genesis run --brief "Grounding sheets help joint pain" --awareness problem-aware --passes 2
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## exodus-image (start here for statics)
|
|
69
|
+
|
|
70
|
+
**What it does:** The front door for static image ads. Just say "exodus" plus what
|
|
71
|
+
you want — "exodus, make me some statics from this ad", "exodus, render AD-001" —
|
|
72
|
+
and Claude reads the request and runs the right engine: **exodus-creative**
|
|
73
|
+
(renders straight from copy, or matches a reference image) or **exodus-template**
|
|
74
|
+
(one piece of copy spread across 33 ad-type formats). You don't pick the engine;
|
|
75
|
+
the request decides it. Use the engines below directly only when you already know
|
|
76
|
+
exactly which one you want.
|
|
77
|
+
|
|
78
|
+
**Say something like:** "exodus, make me some image ads from this copy" · "exodus,
|
|
79
|
+
render this ad as statics" · "exodus, spread AD-001 across ad formats" · "exodus,
|
|
80
|
+
make ads that look like this library image".
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## exodus-creative
|
|
85
|
+
|
|
86
|
+
**What it does:** Generate static creative images through the creative-suite engines — native (render image ads straight from ad copy), copy-derived (renders derived from copy variations), and ref-match (match the look of one or more reference images you've uploaded to the library).
|
|
87
|
+
|
|
88
|
+
```operator-guide
|
|
89
|
+
Subcommands:
|
|
90
|
+
exodus creative native --ad "<text>" [options] Render image ads from ad copy
|
|
91
|
+
exodus creative copy-derived --ad "<text>" [options] Renders derived from copy variations
|
|
92
|
+
exodus creative ref-match --refs <id,id,...> [options] Match the look of reference image(s)
|
|
93
|
+
exodus creative status --id <runId> Poll a run
|
|
94
|
+
|
|
95
|
+
Shared options (kickoffs):
|
|
96
|
+
--variations N Renders to generate (default: engine-specific)
|
|
97
|
+
--aspect 1:1|4:5|9:16 Image aspect ratio (default: 1:1)
|
|
98
|
+
--name "<label>" Custom run name (otherwise auto-generated)
|
|
99
|
+
--ad-group <id> Attach to an existing ad-group
|
|
100
|
+
|
|
101
|
+
ref-match additional options:
|
|
102
|
+
--refs <id,id,...> REQUIRED. Comma-separated creativeSuiteImages ids
|
|
103
|
+
(the images must already be in the dashboard library)
|
|
104
|
+
--subject "<text>" Optional subject hint
|
|
105
|
+
--objects <id,id,...> Optional object-overlay image ids
|
|
106
|
+
|
|
107
|
+
Returns: runId + dashboard URL (/creative-suite/runs/<runId>).
|
|
108
|
+
Status: `exodus creative status --id <runId>` → engine, status, completed/total, isTerminal.
|
|
109
|
+
Auth: Bearer (kickoff via Convex HTTP; status via dashboard route).
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## exodus-template
|
|
115
|
+
|
|
116
|
+
**What it does:** Turn finished ad copy into many static ad images spread across structured ad-type formats (testimonial, hero, UGC, logo, infographic, and 28 more). Runs Fernando's 5-stage Template pipeline — give it one brief or a numbered list of ads and it generates format variations, then renders them.
|
|
117
|
+
|
|
118
|
+
```operator-guide
|
|
119
|
+
Subcommands:
|
|
120
|
+
exodus template run --input "<text>" [options] Kick off a run
|
|
121
|
+
exodus template resume --id <runId> Finalize an orphaned run (#56)
|
|
122
|
+
exodus template ad-types Print the 33 AD_TYPES
|
|
123
|
+
exodus template reptile-triggers Print the 13 reptile triggers
|
|
124
|
+
|
|
125
|
+
run options:
|
|
126
|
+
--input "<text>" REQUIRED. One brief, or a numbered list of finished ads
|
|
127
|
+
("1. <ad copy> 2. <ad copy> ..."). Min 3 chars.
|
|
128
|
+
--mode auto|manual|hybrid Generation mode (default: auto)
|
|
129
|
+
--render-mode images|prompts prompts = skip render, return LLM prompts only (default: images)
|
|
130
|
+
--aspect 1:1|9:16 Image aspect ratio (default: 1:1)
|
|
131
|
+
--model gpt-image-2|nano-banana-pro Kie.ai model (default: gpt-image-2)
|
|
132
|
+
--realism off|realistic Realism enforcement (default: off)
|
|
133
|
+
--quantities "slug:N,slug:N" manual-mode per-type counts (e.g. "testimonial:3,hero:2")
|
|
134
|
+
--pairings '<JSON>' hybrid-mode host/modifier pairs: '[{"host":"testimonial","modifier":"hero"}]'
|
|
135
|
+
--requested-count N auto-mode total render target (optional)
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
runId + dashboard URL. POST-only — there is NO CLI status endpoint yet.
|
|
139
|
+
Live progress renders in the dashboard at /creative-suite/template/sessions/<runId>.
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## exodus-meme
|
|
145
|
+
|
|
146
|
+
**What it does:** Generate meme-style ad creative for the active brand — recommends meme formats for a brief, then renders the whole batch server-side in one run (AI image memes via Kie.ai, classic Imgflip-template memes on the member's Imgflip login).
|
|
147
|
+
|
|
148
|
+
```operator-guide
|
|
149
|
+
Subcommands:
|
|
150
|
+
exodus meme recommend --brief "<text>" [--avatar "<text>"]
|
|
151
|
+
exodus meme run --brief "<text>" --formats '<json>' [--avatar "<text>"] [--name "<label>"]
|
|
152
|
+
exodus meme regenerate --brief "<text>" --layer 1|2|3 <format fields> [--hint "<text>"] [--id <runId>]
|
|
153
|
+
|
|
154
|
+
Typical flow:
|
|
155
|
+
1. recommend → { recommendations: [...] } — 15 picks (5 per layer) with
|
|
156
|
+
name, layer, reasoning, ad_angle. Layer 1 = classic Imgflip
|
|
157
|
+
templates; layers 2/3 = AI-image formats.
|
|
158
|
+
2. run → pass the picked recommendation objects straight into
|
|
159
|
+
--formats (JSON array, 1–50). One enqueue; the batch renders
|
|
160
|
+
server-side via Trigger.dev — closing the session won't kill it.
|
|
161
|
+
3. poll → exodus status --id <runId> --type creative
|
|
162
|
+
(terminal: complete | partial-error | error)
|
|
163
|
+
4. regenerate → re-render a single miss (layer 1: --template-id
|
|
164
|
+
--template-name --boxes; layer 2/3: --format [--hint]).
|
|
165
|
+
|
|
166
|
+
Keys (strict BYOK, preflighted server-side): classic memes need the member's
|
|
167
|
+
Imgflip login; AI memes need their Kie.ai key; captions always need an LLM key.
|
|
168
|
+
Returns: runId + dashboard URL /creative-suite/runs/<runId> (results land in the library).
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## exodus-browse
|
|
174
|
+
|
|
175
|
+
**What it does:** View past pipeline runs and pull outputs from previous sessions.
|
|
176
|
+
|
|
177
|
+
```operator-guide
|
|
178
|
+
Inputs:
|
|
179
|
+
none required — defaults to recent runs across all pipelines
|
|
180
|
+
Flags:
|
|
181
|
+
--limit (default: 20) — max runs to list
|
|
182
|
+
--agent — filter by agent: genesis | creative | template | meme
|
|
183
|
+
Returns: terminal table of recent runs with timestamps, agents, statuses, and Doc URLs
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## exodus-drive
|
|
189
|
+
|
|
190
|
+
**What it does:** Read and write Google Drive / Docs / Sheets via the dashboard's existing OAuth, using `npx @aicopycoders/exodus drive` subcommands.
|
|
191
|
+
|
|
192
|
+
```operator-guide
|
|
193
|
+
Subcommands (use the one that matches intent):
|
|
194
|
+
get-doc <docId> Read a Google Doc by ID
|
|
195
|
+
get-sheet <sheetId> Read a spreadsheet range
|
|
196
|
+
list-files Search/list Drive files
|
|
197
|
+
create-doc <title> Create a new Google Doc
|
|
198
|
+
batch-update <docId> Apply Docs API requests (insertText, etc.)
|
|
199
|
+
For pipeline-run docs, use:
|
|
200
|
+
npx @aicopycoders/exodus read-doc <runId> — walks every tab, renders to markdown
|
|
201
|
+
Returns: structured JSON forwarded from Google's APIs (or markdown for read-doc)
|
|
202
|
+
```
|
|
@@ -92,6 +92,9 @@ Save to `/tmp/genesis-seeds.txt` (one per line, `#` comments allowed), or pass `
|
|
|
92
92
|
**Pass count is the user's knob** — if they didn't specify, surface a quick menu (1 pass / 2 variants recommended · 2 passes / 4 variants · more) rather than assuming. Always `run_in_background: true` — these runs are past the 10-min foreground cap.
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
+
# Resolve hook mode FIRST (see "Hook selection mode" below) — these commands
|
|
96
|
+
# assume a saved default exists, else add --stop-at-hooks or --auto-hooks or they error.
|
|
97
|
+
|
|
95
98
|
# Default — 1 pass per bot = 2 variants (1 Mario × Brand + 1 Infeed × Brand):
|
|
96
99
|
npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level>
|
|
97
100
|
|
|
@@ -110,12 +113,17 @@ npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level> --aut
|
|
|
110
113
|
|
|
111
114
|
`--brief` accepts inline text or a file path. `--passes <n>` (1–5) is the friendly knob; `--variants <n>` (1–10) is an advanced raw-total override that wins if both are given.
|
|
112
115
|
|
|
113
|
-
**Hook
|
|
114
|
-
The pipeline can pause after
|
|
116
|
+
**Hook selection mode — REQUIRED gate before EVERY run (do not skip):**
|
|
117
|
+
The pipeline can pause after hook generation so the user picks which hooks become body copy — the human quality gate. You MUST resolve the mode **before** firing a run. A `genesis run` with **no** `--stop-at-hooks`/`--auto-hooks` **and** no saved preference now **hard-errors** (`Hook-selection preference not set`) **by design** — so the gate can't be silently skipped. If you see that error, you skipped this step; do it now.
|
|
118
|
+
|
|
119
|
+
Resolve it in this order, every time, BEFORE you run:
|
|
120
|
+
1. **Check the saved default:** run `npx @aicopycoders/exodus genesis hook-pref` (no argument). It prints `manual`, `auto`, or `unset` on the first line.
|
|
121
|
+
2. **If it prints `manual` or `auto`:** just fire the run — the saved default applies, no flag needed.
|
|
122
|
+
3. **If it prints `unset`:** STOP and ask the user once, plainly — *"Want to choose the hooks yourself before I write the copy, or have me auto-pick and write straight through?"* Then fire the run with the matching flag (`--stop-at-hooks` = they choose, `--auto-hooks` = auto), and after it starts, offer to save it as their default so you never ask again: `npx @aicopycoders/exodus genesis hook-pref <manual|auto>`. **Do NOT fire the run before they answer.**
|
|
115
123
|
|
|
116
|
-
|
|
117
|
-
- **`--
|
|
118
|
-
-
|
|
124
|
+
Flags:
|
|
125
|
+
- **`--stop-at-hooks`** — pause after hook generation. The run lands in `awaiting_hook_selection` and the CLI prints a dashboard URL; the user picks hooks on the run-detail page and the pipeline continues automatically to body copy.
|
|
126
|
+
- **`--auto-hooks`** — auto-pick the strongest hooks and write straight through (also overrides a saved "manual" default for this one run).
|
|
119
127
|
|
|
120
128
|
> "Genesis run started at problem-aware — 1 pass per bot (2 variants: Mario × Brand + Infeed × Brand). I'll surface the Doc when it lands."
|
|
121
129
|
|
|
@@ -122,6 +122,8 @@ Skip the menu only if the user already said how many ("just give me two", "run a
|
|
|
122
122
|
|
|
123
123
|
Hand off to the `exodus-genesis` skill — it owns the run (double-pass hooks, the built-in 15-point QA, the editing menu). Always background it; even the default run is ~12–15 min, past the 10-min foreground cap.
|
|
124
124
|
|
|
125
|
+
**Before firing, resolve the hook-selection gate** (the `exodus-genesis` skill's "Hook selection mode" step): run `npx @aicopycoders/exodus genesis hook-pref` — if it prints `unset`, ask the user *"choose the hooks yourself, or auto-pick and write straight through?"* and pass `--stop-at-hooks` or `--auto-hooks` accordingly (offer to save the choice). A run with no flag and no saved default hard-errors by design — don't skip this.
|
|
126
|
+
|
|
125
127
|
```bash
|
|
126
128
|
# Default — 1 pass per bot = 2 variants:
|
|
127
129
|
npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level>
|
package/dist/commands/genesis.js
CHANGED
|
@@ -446,8 +446,24 @@ async function waitForGenesisRun(runId) {
|
|
|
446
446
|
async function runHookPref() {
|
|
447
447
|
const positionals = parsePositional();
|
|
448
448
|
const pref = positionals[1];
|
|
449
|
+
if (pref === undefined) {
|
|
450
|
+
const res = await apiGet("/api/v2/genesis/hook-pref");
|
|
451
|
+
if (!res.ok) {
|
|
452
|
+
console.log(`Error: ${res.data.error ?? "Unknown error"}`);
|
|
453
|
+
process.exit(1);
|
|
454
|
+
}
|
|
455
|
+
const cur = res.data.preference ?? null;
|
|
456
|
+
if (cur === null) {
|
|
457
|
+
console.log("unset");
|
|
458
|
+
console.log("No saved hook preference. Runs require --stop-at-hooks or --auto-hooks until one is set.");
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
console.log(cur);
|
|
462
|
+
}
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
449
465
|
if (pref !== "manual" && pref !== "auto") {
|
|
450
|
-
console.error('Usage: exodus genesis hook-pref
|
|
466
|
+
console.error('Usage: exodus genesis hook-pref [manual|auto] (no arg prints the current value)');
|
|
451
467
|
console.error(' manual Pause each run at hook selection so you choose hooks.');
|
|
452
468
|
console.error(' auto Skip hook selection and let the pipeline pick automatically.');
|
|
453
469
|
process.exit(1);
|
package/dist/commands/init.d.ts
CHANGED
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { writeEnvScaffold, ensureGitignore, writeSkills, writeReferences, ensureBaseDirs, } from "../lib/scaffold.js";
|
|
3
|
+
import { writeEnvScaffold, ensureGitignore, writeSkills, writeReferences, writeDocs, ensureBaseDirs, } from "../lib/scaffold.js";
|
|
4
4
|
import { loadWorkspaceEnv } from "../lib/load-env.js";
|
|
5
5
|
import { ensureBrandDir } from "../lib/layout.js";
|
|
6
6
|
export const helpText = `
|
|
@@ -22,7 +22,8 @@ export function scaffoldInit(root) {
|
|
|
22
22
|
ensureGitignore(root);
|
|
23
23
|
const skills = writeSkills(root);
|
|
24
24
|
writeReferences(root);
|
|
25
|
-
|
|
25
|
+
const docs = writeDocs(root);
|
|
26
|
+
return { existing, envCreated, skills, docs };
|
|
26
27
|
}
|
|
27
28
|
export async function syncBrands(root) {
|
|
28
29
|
loadWorkspaceEnv(root);
|
|
@@ -48,6 +49,9 @@ export async function run(flags) {
|
|
|
48
49
|
const r = scaffoldInit(root);
|
|
49
50
|
console.log(`${r.existing ? "Refreshed" : "Initialized"} Exodus workspace at ${root}`);
|
|
50
51
|
console.log(` Installed ${r.skills.length} skills into .claude/skills/`);
|
|
52
|
+
if (r.docs.length) {
|
|
53
|
+
console.log(` Installed workspace docs: ${r.docs.join(", ")}`);
|
|
54
|
+
}
|
|
51
55
|
const brands = await syncBrands(root);
|
|
52
56
|
if ("synced" in brands && brands.synced.length) {
|
|
53
57
|
console.log(` Synced ${brands.synced.length} brand folder(s): ${brands.synced.join(", ")}`);
|
package/dist/lib/assets.d.ts
CHANGED
package/dist/lib/assets.js
CHANGED
package/dist/lib/scaffold.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export declare function writeEnvScaffold(root: string): {
|
|
|
5
5
|
export declare function ensureGitignore(root: string): void;
|
|
6
6
|
export declare function writeSkills(root: string, srcOverride?: string): string[];
|
|
7
7
|
export declare function writeReferences(root: string, srcOverride?: string): void;
|
|
8
|
+
export declare function writeDocs(root: string, srcOverride?: string): string[];
|
|
8
9
|
export declare function ensureBaseDirs(root: string): void;
|
package/dist/lib/scaffold.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { skillsDir, referencesDir } from "./assets.js";
|
|
3
|
+
import { skillsDir, referencesDir, docsDir } from "./assets.js";
|
|
4
4
|
export const ENV_SCAFFOLD = `# Exodus config — paste your dashboard .env block below this line.
|
|
5
5
|
# Get it from your Exodus dashboard -> Settings -> Claude Code -> "Copy .env block".
|
|
6
6
|
# ONE key covers every brand you own; switch brands with brand subfolders or
|
|
@@ -51,6 +51,25 @@ export function writeReferences(root, srcOverride) {
|
|
|
51
51
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
52
52
|
fs.cpSync(src, dest, { recursive: true });
|
|
53
53
|
}
|
|
54
|
+
export function writeDocs(root, srcOverride) {
|
|
55
|
+
let src;
|
|
56
|
+
try {
|
|
57
|
+
src = docsDir(srcOverride);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
if (!fs.existsSync(src))
|
|
63
|
+
return [];
|
|
64
|
+
const names = [];
|
|
65
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
66
|
+
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
67
|
+
continue;
|
|
68
|
+
fs.copyFileSync(path.join(src, entry.name), path.join(root, entry.name));
|
|
69
|
+
names.push(entry.name);
|
|
70
|
+
}
|
|
71
|
+
return names.sort();
|
|
72
|
+
}
|
|
54
73
|
export function ensureBaseDirs(root) {
|
|
55
74
|
const out = path.join(root, "output");
|
|
56
75
|
fs.mkdirSync(out, { recursive: true });
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicopycoders/exodus",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.2700-beta.3",
|
|
4
4
|
"description": "CLI + Claude Code skills for the Copycoders Exodus ad pipeline",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/aicopycoders/exodus.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/aicopycoders/exodus#readme",
|
|
5
10
|
"type": "module",
|
|
6
11
|
"bin": {
|
|
7
|
-
"exodus": "
|
|
12
|
+
"exodus": "dist/bin/exodus.js"
|
|
8
13
|
},
|
|
9
|
-
"files": [
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"assets"
|
|
17
|
+
],
|
|
10
18
|
"engines": {
|
|
11
19
|
"node": ">=20"
|
|
12
20
|
},
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Genesis Bots credentials. Keep this file private — never commit or share it.
|
|
2
|
-
# Easiest: replace this ENTIRE file with what the portal's "Copy .env" button
|
|
3
|
-
# gives you (https://genesis.copycoders.ai/portal), then add your provider key.
|
|
4
|
-
|
|
5
|
-
GENESIS_BASE_URL=https://gas.copycoders.ai/api/v1
|
|
6
|
-
GENESIS_API_KEY=gen_your_key_here
|
|
7
|
-
|
|
8
|
-
# Your provider key (you pay usage). Use ONE of these — match the name to your key:
|
|
9
|
-
# Anthropic → ANTHROPIC_API_KEY=sk-ant-...
|
|
10
|
-
# OpenRouter → OPENROUTER_API_KEY=sk-or-...
|
|
11
|
-
# (`npx @aicopycoders/exodus keys pull` writes these names for you from the dashboard.)
|
|
12
|
-
ANTHROPIC_API_KEY=sk-ant-your_provider_key_here
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { buildBriefBody } from "../genesis.js";
|
|
3
|
-
describe("buildBriefBody stopAtHooks", () => {
|
|
4
|
-
it("omits stopAtHooks when unset", () => {
|
|
5
|
-
const b = buildBriefBody("brief text", { awarenessLevel: "problem-aware" });
|
|
6
|
-
expect("stopAtHooks" in b).toBe(false);
|
|
7
|
-
});
|
|
8
|
-
it("includes stopAtHooks:true when set", () => {
|
|
9
|
-
const b = buildBriefBody("brief text", { awarenessLevel: "problem-aware", stopAtHooks: true });
|
|
10
|
-
expect(b.stopAtHooks).toBe(true);
|
|
11
|
-
});
|
|
12
|
-
});
|