Skip to content
Back to skills

Cce Init

BSecurity

First-time onboarding for a freshly-cloned Chrome Extension Factory. Orients the user on the factory's philosophy, walks through extension-shape profile selection (deleting unused entrypoints), delegates to `cws-content` for listing copy, optionally runs `cws-screens` for screenshots, optionally walks through OAuth setup, confirms structural green, and drops a `.cce-init-done` marker. Idempotent — re-invoking on an already-initialized factory offers a sub-recipe menu instead of re-running the...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 24, 2026
developmenttypescriptrustgoshellbashnextjsnodegitapi

Works with

  • claude code
  • terminal
  • cli
  • api

Security analysis

B77/100
  • highPerforms destructive filesystem operations
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 24, 2026

npx -y skills add codyhxyz/create-chrome-extension --skill cce-init --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cce Init?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cce Init
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/codyhxyz-cce-init/badge)](https://www.skillsdirectory.com/skills/codyhxyz-cce-init)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cce-init
description: First-time onboarding for a freshly-cloned Chrome Extension Factory. Orients the user on the factory's philosophy, walks through extension-shape profile selection (deleting unused entrypoints), delegates to `cws-content` for listing copy, optionally runs `cws-screens` for screenshots, optionally walks through OAuth setup, confirms structural green, and drops a `.cce-init-done` marker. Idempotent — re-invoking on an already-initialized factory offers a sub-recipe menu instead of re-running the whole flow.
triggers:
  - "user just cloned the chrome extension factory"
  - "fresh factory clone"
  - "first time setup"
  - "initialize the extension factory"
  - "onboard me to this repo"
  - "what do I do first"
  - "help me get started with this extension template"
  - "strip down the factory for my use case"
  - "/cce-init"
invokes:
  - "cws-content"                                      # skill delegation for listing copy (Phase D)
  - "cws-screens"                                      # skill delegation for screenshots (Phase E, optional)
  - "cws-video"                                        # skill delegation for launch video (Phase E2, optional)
  - "npm run check:cws"                                # structural validator (Phase G)
  - "npx wxt prepare"                                  # regenerate WXT types after profile-strip (Phase C)
writes:
  - ".cce-init-done"                                   # marker file dropped at Phase H
  - ".gitignore"                                       # add the marker to gitignore (Phase H)
  - "CLAUDE.md"                                        # inject/refresh publishing-directive marker block (Phase H)
  - ".claude/publishing-directive.md"                  # canonical directive body, imported by CLAUDE.md (Phase H)
  - "entrypoints/"                                     # delete unused entrypoints during profile selection (Phase C)
  - "entrypoints/*/App.tsx"                            # bespoke UI skeletons in Phase C2
  - "entrypoints/content.ts"                           # bespoke DOM hook in Phase C2
  - "entrypoints/background.ts"                        # bespoke message/storage wiring in Phase C2
  - "wxt.config.ts"                                    # only to remove orphaned permissions flagged in Phase C
---

# cce-init skill

You are driving the `cce-init` skill. Your single responsibility is to orient a brand-new user of the Chrome Extension Factory: explain the philosophy briefly, strip the factory to their extension shape, delegate to other skills for content and screenshots, optionally walk OAuth setup, confirm `check:cws` stays green, and drop a marker file so subsequent runs know init is done.

You do NOT write listing copy yourself (that's `cws-content`). You do NOT generate screenshots yourself (that's `cws-screens`). You do NOT submit or zip (that's `cws-ship`). You DO:

- Detect whether this is a fresh clone.
- Walk profile selection (4 profiles) and delete the entrypoints that don't belong to the user's chosen profile.
- Delegate to `cws-content` for initial listing/welcome copy.
- Delegate to `cws-screens` for screenshot scaffolding (if `screenshots/` still exists).
- Walk the OAuth setup stepwise, linking to `docs/06-keepalive-publish.md` rather than duplicating it.
- Run `npm run check:cws` at the end to confirm the factory invariant holds.
- Drop `.cce-init-done` and add it to `.gitignore`.

The factory invariant after a fresh-clone run: `npm run check:cws` stays green; `npm run check:cws:ship` drops from 4 content errors to 0 (modulo `ship-ready-screenshots` if the user skipped Phase E, which is expected and fine).

---

## Phase 0 — Locate the factory

Before anything else, figure out whether the current working directory IS a factory repo. A factory repo has BOTH of:

- `wxt.config.ts` at the repo root
- `scripts/validate-cws.ts`

**If both present:** you're in a factory. Proceed to Phase A.

**If `manifest.json` is present at the repo root but `wxt.config.ts` is NOT:** the user ran `/cce-init` from inside an existing vanilla MV3 extension. This is a different flow. Offer:

> This looks like an existing vanilla MV3 extension, not a fresh factory clone. You probably want `/cce-import` — it converts a vanilla extension into the factory layout in one pass (auto-detects your profile, moves files into `entrypoints/`, wraps `background.js` in `defineBackground`, and runs `check:cws` at the end).
>
> 1. Delegate to `/cce-import` now.
> 2. Cancel — I'll exit.

On choice 1: hand off to `/cce-import` with the current working directory as the source argument.

**If `wxt.config.ts` AND `manifest.json` are both missing:** the user invoked `/cce-init` outside a factory. Offer to clone:

> This directory isn't a Chrome Extension Factory. Want me to clone one?
>
> 1. Clone into a new subdirectory of the current working directory (recommended). Ask for a name.
> 2. Clone into an existing empty directory. Ask for the path.
> 3. Cancel — I'll exit and the user can run `npx create-chrome-extension <name>` themselves.

On choice 1: ask for the name, then run `git clone --depth 1 <factory-repo-url> ./<name>` + `rm -rf ./<name>/.git` + `git init ./<name>` + switch the skill's working directory to `./<name>` (use the Bash tool's `cwd` for subsequent calls). Then run `npm install` in the new directory. Then proceed to Phase A from the new directory.

On choice 2: validate the target is empty; same sequence.

On choice 3: exit cleanly with instructions:

> Run `npx create-chrome-extension <name>` to scaffold the factory, then re-invoke `/cce-init` inside the new directory.

The factory repo URL is fixed — use the canonical URL documented in `packages/cli/bin/cli.mjs` (`REPO_URL`, overridable via `CCE_REPO_URL` env var). Do not invent a different URL.

---

## Phase A — Detect state

**Before anything else**, figure out whether this is a fresh clone or a re-invocation.

Run these three checks (all three must indicate "fresh" for the factory to count as fresh):

1. **Marker file check.** Does `.cce-init-done` exist at the repo root? If yes → not fresh.
2. **Manifest name check.** Read `wxt.config.ts`. Is `manifest.name` still `'My Extension'`? If no → not fresh.
3. **Welcome config check.** Read `entrypoints/welcome/config.ts` (if it exists). Does it contain any of these factory placeholder strings?
   - `"A brief one-sentence description"`
   - `"your-org"`
   - `"your-extension"`
   If none present AND welcome/config.ts still exists → not fresh. (If the file doesn't exist, the user stripped welcome/ in a previous init — treat that as "not fresh" even if the other signals are ambiguous.)

**If fresh** (marker absent AND default name AND welcome placeholders present): continue to Phase B.

**If not fresh**: do NOT re-run the full flow. Print:

> Looks like you've already run `cce-init` on this factory (marker file present / name customized / welcome copy filled in). I won't re-delete entrypoints or overwrite your config.
>
> Want to re-run a specific step? Pick one:
>
> 1. **Profile selection** — re-strip entrypoints (destructive; only if you changed your mind about the extension shape).
> 2. **Listing content** — re-run `cws-content` to rewrite name / description / welcome copy.
> 3. **Screenshots** — run `cws-screens` to add or update your 5 CWS screenshots.
> 4. **OAuth setup** — walk through the 4 CWS secrets so `npm run ship` can auto-publish.
> 5. **Exit** — no action.

Then branch based on the user's pick:

- `1` → jump to **Phase C** (profile selection). Warn first: "This will delete entrypoints. You've already customized this factory — are you sure?"
- `2` → delegate to `cws-content` (Phase D).
- `3` → delegate to `cws-screens` (Phase E).
- `4` → run Phase F only.
- `5` → stop cleanly.

Do NOT run Phases B, G, or H on a re-invocation. The marker already exists; no need to re-drop it.

---

## Phase B — Orient

The user is looking at a factory clone for the first time. They need a short, honest orientation before you start deleting things. Keep it tight — 3 to 5 sentences, not a blog post. Say roughly:

> This factory leans on **scripts, not model recall**. The rules for "is this extension well-formed" and "is this ready to ship" live in `scripts/validate-cws.ts` — the model's job is to interview you and translate your answers into edits that satisfy those rules.
>
> There are two gates:
> - `npm run check:cws` — structural. Green by design on a fresh clone. Catches regressions you introduce (broad permissions, remote code, CSP holes).
> - `npm run check:cws:ship` — structural + content-ready. Red by design on a fresh clone. Goes green after you fill in your listing / welcome / screenshots.
>
> `npm run zip` gates on `check:cws:ship`, so you literally cannot produce a submittable artifact until you're ready. You don't have to memorize any of these commands — `npm run ship` chains everything when you're ready to publish.
>
> More on the philosophy in `ARCHITECTURE.md`. When in doubt, run the script.

Then show the short command table:

| Command | What it does | Factory state |
|---|---|---|
| `npm run check:cws` | Structural validator | Green |
| `npm run check:cws:ship` | Structural + content-ready | Red (by design) |
| `npm run zip` | Build + package (gated on ship-ready) | Refuses (by design) |
| `npm run ship` | The whole pipeline: validate → version-sync → zip → publish | Halts at first red gate |

End with: "OK — let's customize this to your extension. First question is about the shape."

---

## Phase B2 — Front-loaded interview

Collect every answer needed for Phases C, C2, D, E, E2, F in one pass. No scaffolding, no deletions, no delegation yet — just questions.

Ask in this order, one at a time (wait for each answer before the next):

1. **Pitch** — "In one or two sentences, what are you building?" (feeds Phase C recommendation + Phase C2 bespoke code)
2. **Target sites** — "What URLs will this run on? Be specific (e.g., `https://news.ycombinator.com/*`) or say 'no host access needed' if you're only using `activeTab`." (feeds Phase C welcome-page decision + `wxt.config.ts` permissions)
3. **Welcome page** — inferred from (2): if host access needed, keep welcome; if not, ask "delete the welcome page?" and default to yes.
4. **Features** — ask once, comma-separated: "Any of: auth / persistent storage / keyboard shortcuts / background alarms / none?"
5. **Listing basics** — "What's the extension's public name? (3–45 chars)" and "One-line tagline? (used as the CWS summary)"
6. **Screenshots** — "Scaffold 5 CWS screenshots now, or defer? (now / defer)"
7. **Video** — "Scaffold a launch video now, or defer? (now / defer)"
8. **OAuth** — "Set up automated publishing credentials now, or defer? (now / defer)"

After the user answers all 8, show a one-screen summary of what's about to happen:

> Here's the plan:
>
> - Profile: <picked>
> - Deletes: <list>
> - Bespoke code in: <kept entrypoints>
> - Listing: name "<name>", tagline "<tagline>"
> - Screenshots: <now | defer>
> - Video: <now | defer>
> - OAuth: <now | defer>
>
> Run the plan? (yes / change something / cancel)

On "yes": execute Phases C → C2 → D → E → E2 → F in order without re-interviewing.

On "change something": ask which answer to revise, update it, re-show the summary.

On "cancel": exit cleanly, no changes.

**Important:** when delegating to `cws-content`, `cws-screens`, `cws-video` in later phases, pass the answers already collected here as context so those skills don't re-ask. If a sub-skill insists on re-interviewing, accept it — don't fight it — but prefer skills that accept pre-filled answers.

---

## Phase C — Profile selection (pitch-driven)

Use the pitch already collected in Phase B2. If for any reason it's missing (skill was invoked directly into Phase C), ask now: "In one or two sentences — what are you building?"

Based on the pitch, **recommend** one of the 4 profiles from `docs/01-extension-type-profiles.md`. Heuristics:

- "page enhancer / injector / modifier / block / highlight / modify the DOM" → **content-script-only**
- "quick action from the toolbar / popup / click the icon to ___" → **popup-based**
- "persistent panel / research / reference / chat with a page" → **sidepanel**
- "everything / I need it all / let me decide later" → **full hybrid**

Present the recommendation with a clear exit:

> Sounds like **<profile name>** fits best: <one-sentence why>. That means I'll delete:
>
> <exact delete list from the profile-strip semantics below>
>
> Does that match? (yes / show the other options / keep everything)

On "yes": proceed to the welcome follow-up (below) and then profile-strip semantics.

On "show the other options": present the 4-option menu (see `### Fallback: menu selection` below) and let the user pick.

On "keep everything": treat as full-hybrid (profile 4, no deletions).

### Fallback: menu selection

If the user asks to see the options, show this menu verbatim:

> What's the shape of your extension? Pick one:
>
> **1. Content-script-only** — page enhancer / injector / modifier. No toolbar UI.
> *Deletes:* `entrypoints/popup/`, `entrypoints/options/`, `entrypoints/sidepanel/`.
> Keeps: `entrypoints/content.ts`, `entrypoints/welcome/` (optional — keep if you need host permissions at install time; delete if your extension works with smart defaults).
>
> **2. Popup-based** — quick-action tool triggered from the toolbar icon.
> *Deletes:* `entrypoints/content.ts`, `entrypoints/sidepanel/`, `utils/dom.ts`, `utils/observer.ts`.
> Keeps: `entrypoints/popup/`, `entrypoints/background.ts`, `entrypoints/options/`, `entrypoints/welcome/` (optional).
>
> **3. Sidepanel** — persistent panel alongside the page (research / reference tool).
> *Deletes:* `entrypoints/popup/`, `entrypoints/content.ts`, `utils/dom.ts`, `utils/observer.ts`.
> Keeps: `entrypoints/sidepanel/`, `entrypoints/background.ts`, `entrypoints/options/`, `entrypoints/welcome/` (optional).
>
> **4. Full hybrid** — content script + popup + sidepanel + options. The kitchen sink.
> *Deletes:* nothing. This is the factory default.
> Keeps: everything.

For each profile except "Full hybrid," **also** ask a follow-up:

> Do you need a welcome / onboarding page? Keep it if your extension requests host permissions (the welcome page is where the user grants them from a button click — the pattern that avoids the CWS "in-depth review" banner). Delete it if your extension works with smart defaults and no host permissions.
>
> Answer: keep / delete.

### Profile-strip semantics (exact rules)

These are the exact delete sets per profile — use these verbatim. Never delete anything outside this list in a single pass.

**Content-script-only (profile 1):**
- `entrypoints/popup/`
- `entrypoints/options/`
- `entrypoints/sidepanel/`
- If welcome = delete: also `entrypoints/welcome/`, `utils/permissions.ts`, and the `tabs.create` block in `entrypoints/background.ts`. If no other background logic is kept (messaging, alarms), delete `entrypoints/background.ts` too.

**Popup-based (profile 2):**
- `entrypoints/content.ts`
- `entrypoints/sidepanel/`
- `utils/dom.ts`
- `utils/observer.ts`
- If welcome = delete: also `entrypoints/welcome/`, `utils/permissions.ts`, and the `tabs.create` block in `entrypoints/background.ts`.

**Sidepanel (profile 3):**
- `entrypoints/popup/`
- `entrypoints/content.ts`
- `utils/dom.ts`
- `utils/observer.ts`
- If welcome = delete: same as above.

**Full hybrid (profile 4):**
- Delete nothing. Skip to Phase D.

### Execute the deletions

Before deleting, summarize the plan and ask for explicit confirmation:

> About to delete:
> - `entrypoints/content.ts`
> - `entrypoints/sidepanel/`
> - `utils/dom.ts`
> - `utils/observer.ts`
>
> This is destructive. Proceed? (y/n)

On confirmation, delete each path. After all deletions, run:

```bash
npx wxt prepare
```

This regenerates `.wxt/` types to match the new entrypoint set. WXT will complain loudly if a deleted entrypoint is still imported somewhere; if that happens, surface the error and ask the user to help disambiguate (usually it means a file you kept still imports from a file you deleted — `utils/messaging.ts` importing from `utils/dom.ts` would be a typical case).

### Permission cleanup

After entrypoints are deleted, check `wxt.config.ts` for orphaned permissions:

- Deleted `entrypoints/sidepanel/` → `'sidePanel'` in `manifest.permissions` is now orphaned. Remove it. Also remove `minimum_chrome_version: '114'` if that was only there for sidePanel.
- Deleted `entrypoints/background.ts` entirely → `'alarms'` in `manifest.permissions` is orphaned. Remove it. Also remove `optional_host_permissions` if nothing requests them.
- Kept background but no messaging/alarms usage → let the user decide; don't auto-remove, just flag.

Edit `wxt.config.ts` to remove the orphaned permissions. Show the diff to the user before writing. The structural validator rule `unused-permission` will catch anything you miss, so a second pass is cheap.

**Important:** after profile-strip, re-run `npm run check:cws`. It must stay green. If it doesn't (e.g., `unused-permission` fires), fix whatever it flags before moving on. This is the only place in the init flow where `check:cws` might break, and fixing it here is the user's investment in a clean factory.

---

## Phase C2 — Bespoke first-run code

The kept entrypoints still contain factory templates (generic hello-world popups, placeholder content-script DOM hooks). Now tailor them to the user's pitch so the first `npm run dev` shows something resembling their idea, not a stock demo.

**Scope:** only the entrypoint files that were kept. Do NOT touch `utils/`, `scripts/`, `wxt.config.ts` (already handled in Phase C), or any test file.

**What "bespoke" means, per kept entrypoint:**

- `entrypoints/content.ts` — replace the demo DOM-manipulation with a skeleton that matches the pitch. If the user said "highlight headlines on news sites," write a `queryAllDeep('h1, h2, h3')` loop with a `background: yellow` application. If they said "block tracker scripts," write a `MutationObserver` that looks for `<script src="...">` and removes matches. Do not leave `console.log('hello')` placeholders.
- `entrypoints/popup/App.tsx` — replace the demo counter with the minimal UI implied by the pitch. "Save the tab to a list" → a button + a list component reading from `chrome.storage.local`. "Translate selected text" → a textarea + a button + a result div. Keep it short (~50 LOC), functional, and compile-clean.
- `entrypoints/sidepanel/App.tsx` — same as popup, but laid out for a taller persistent panel.
- `entrypoints/background.ts` — if the pitch implies message-passing or storage, wire the minimal handler. Keep the factory's typed-messaging pattern (`@webext-core/messaging`).
- `entrypoints/options/App.tsx` — leave as a minimal settings stub unless the pitch explicitly calls for settings (e.g., "let users configure which sites to run on").

**Do not** fabricate features the user didn't ask for. Do not add auth, analytics, or third-party integrations unless they came up in the interview.

**After writing bespoke code, run `npm run check:cws`.** It must stay green. If it goes red, most likely you imported a browser global incorrectly or referenced a deleted util — fix before moving on.

**If the pitch is too vague to generate real code** (e.g., "I'll figure it out later"): skip this phase. Leave the factory templates in place. Tell the user:

> Leaving the factory templates in `entrypoints/` — you can flesh them out once you know what you're building. Moving on to listing content.

---

## Phase D — Listing content

State the delegation plainly:

> Now invoking the `cws-content` skill to fill in listing metadata. It'll ask you about name, description, host permissions, and welcome-page copy. That skill runs `npm run check:cws:ship` under the hood and writes to `wxt.config.ts` and `entrypoints/welcome/config.ts`.

Invoke the `cws-content` skill. Wait for it to report back — specifically, wait for it to confirm that all four content rules it owns (`listing-ready-name`, `listing-ready-description`, `ship-ready-optional-host`, `ship-ready-welcome-config`) are cleared, OR to report which ones it couldn't clear (e.g., the user didn't have a privacy policy URL yet — that's a legitimate partial state).

Do NOT duplicate `cws-content`'s recipes. Do NOT re-interview the user yourself. That skill is the source of truth for listing content.

If the user deleted `entrypoints/welcome/` in Phase C, `cws-content`'s Recipe D (`ship-ready-welcome-config`) won't fire — the validator rule is keyed on the file existing. That's correct; move on.

---

## Phase E — Screenshots (optional)

Check whether `screenshots/` still exists at the repo root. It's a Next.js subproject the factory ships with.

**If `screenshots/` exists**: offer to delegate to `cws-screens`:

> Want to scaffold your 5 Chrome Web Store screenshots now? I'll hand off to the `cws-screens` skill. You don't have to finalize copy today — but even draft screenshots clear the `ship-ready-screenshots` validator rule. You can always come back and tweak.
>
> yes / skip

If yes: invoke `cws-screens` and wait for it to report back. Like Phase D, do NOT duplicate its recipes.

If skip: note that `ship-ready-screenshots` will stay red until the user runs `cws-screens` later. That's fine; the factory allows shipping-adjacent states. Move on.

**If `screenshots/` was deleted** (the user stripped it previously — cce-init doesn't delete it in Phase C, but it may have been removed in a prior session): skip this phase silently. Don't tell the user to re-add it; if they wanted screenshots they'd have kept the subproject.

---

## Phase E2 — Launch video (default-on)

The factory ships a launch-video workflow by default. Taste decision documented in ARCHITECTURE.md: CWS listings with a promo video convert markedly better, and the same asset doubles as a launch asset for ProductHunt / Twitter / LinkedIn. One asset, many surfaces.

Check whether `video/` still exists at the repo root.

**If `video/` exists**: offer to delegate to `cws-video`:

> Want to scaffold a launch video now? I'll hand off to the `cws-video` skill. It'll interview you for a 30-second hook + beats, then invoke `heygen-com/hyperframes` (an external skill — `npx skills add heygen-com/hyperframes` if you haven't) to generate the actual video. The same file works for CWS embed, ProductHunt, and socials.
>
> yes / skip

If yes: invoke `cws-video` and wait for it to report back. Do NOT duplicate its recipes. If `cws-video`'s Phase A reports hyperframes is missing and the user opts to defer the install, accept that — cws-video handles the graceful skip.

If skip: note that `ship-ready-video` will stay red until the user runs `cws-video` later. That's fine; matches how screenshots work.

**If `video/` was deleted** (the user genuinely doesn't want a video — explicit opt-out): skip this phase silently. The `ship-ready-video` rule no-ops on absent `video/`, matching the `screenshots/` escape hatch.

---

## Phase F — OAuth setup (optional)

Ask:

> Want to enable automated publishing? This unlocks `npm run ship` to submit your extension directly to the Chrome Web Store API without manually uploading the zip through the dashboard. It requires 4 OAuth secrets and takes ~15 minutes one time.
>
> yes / defer

### If "defer"

> Fine — you can still ship manually: `npm run zip` produces a zip in `.output/` (once ship-mode is green), and you drag-and-drop it into the CWS developer dashboard. The `ship` skill will walk you through that path too. Come back and re-run `cce-init` option 4 when you're ready for automation.

Move on to Phase G.

### If "yes"

Delegate to the `setup-cws-credentials` skill. That skill owns:
- The `gcloud` automation (project create, API enable, best-effort OAuth brand)
- The manual wall (OAuth Desktop Client ID) with computer-use + GUI-wizard fallbacks
- Refresh token harvesting via `npx chrome-webstore-upload-keys`
- Persistence to `.secrets.local.json` (gitignored)
- End-to-end verification via `npm run check:cws:ship --json`

Invoke it and wait for it to report back. Do NOT re-explain the Google Cloud Console flow here — `setup-cws-credentials` and `docs/08-google-cloud-setup.md` are the source of truth. If the user defers any sub-step (e.g. doesn't have a CWS listing yet), accept that and move on; the skill is safe to re-run to fill in missing pieces.

---

## Phase G — Confirm structural green

Run:

```bash
npm run check:cws
```

Expected: green. This is the factory invariant. If it's red, something went wrong in Phase C — most likely an orphaned permission or a broken import from a deleted file.

**If green:** Report the pass briefly and move on:

> `check:cws` is green. Structural invariant holds. Moving to finalize.

**If red:** do NOT proceed to Phase H. Surface the exact validator output to the user and help them fix it. Typical root causes from Phase C:

- `unused-permission` fired → a permission in `wxt.config.ts` isn't used by any kept entrypoint. Remove it.
- TypeScript compile error → a kept file imports from a deleted file. Fix the import (usually `utils/messaging.ts` importing from `utils/dom.ts`, or `entrypoints/background.ts` importing from `utils/permissions.ts`).
- `.output/` missing → `wxt build` didn't run. The `check:cws` script wraps it; re-run `npm run check:cws` after fixing.

After fixing, re-run `npm run check:cws` until it's green. Only then continue to Phase H.

---

## Phase H — Finalize

Four things happen here: inject the publishing directive into `CLAUDE.md`, drop the marker, update `.gitignore`, print the summary.

### Inject the publishing directive (idempotent)

This is the "set-it-and-forget-it" contract with future Claude Code sessions: whenever the user mentions publish / ship / Chrome Web Store / CWS / store listing / screenshots / launch video / OAuth credentials, the session MUST invoke the matching skill (`cws-ship`, `cws-content`, `cws-screens`, `cws-video`, `setup-cws-credentials`) instead of hand-rolling a zip-and-dashboard walkthrough. Without it, Claude defaults to manual pre-flight checklists and asks the user for guidance — the exact failure mode we are preventing.

**Source of truth.** The canonical directive body lives inside this skill at:

```
skills/cce-init/templates/publishing-directive.md
```

Phase H treats that file as authoritative. It does NOT read from the factory's own `CLAUDE.md`, because in a scaffolded child project the factory checkout is gone (the CLI does `rm -rf .git`) — so "read from factory sources" has no meaning. Reading from the skill's own template works everywhere: fresh scaffold, retrofit of a pre-fix scaffold, or one-off invocation on an unrelated repo.

**Algorithm (runs every `cce-init` invocation, including re-runs):**

1. **Load the canonical body.** Read `<skill-dir>/templates/publishing-directive.md` where `<skill-dir>` is the directory containing this `SKILL.md`.
2. **Write the child project's directive file.** Write the canonical body byte-for-byte to `<repo>/.claude/publishing-directive.md`, creating `.claude/` if needed. Overwrite unconditionally — the template is authoritative.
3. **Splice the marker block into `<repo>/CLAUDE.md`.** The block is exactly:

   ```
   <!-- CCE:publishing-directive:begin v2 -->
   @.claude/publishing-directive.md

   <!--
     The directive body lives at `.claude/publishing-directive.md` (imported above).
     This block is managed by `cce-init` Phase H. Do not hand-edit between the
     markers — edits get overwritten on the next `/cce-init` run.
   -->
   <!-- CCE:publishing-directive:end -->
   ```

   Then:
   - If `CLAUDE.md` does not exist: create it with the child project's name as an `# H1` heading, a blank line, then the marker block.
   - If `CLAUDE.md` exists and contains any line starting with `<!-- CCE:publishing-directive:begin` and a later `<!-- CCE:publishing-directive:end -->`: splice out everything from the begin-line through the end-line (inclusive) and replace with the block above. Match on the begin-marker *prefix* (not the exact version suffix) so a stale `v0`/`v1` block is replaced cleanly when the version bumps.
   - If `CLAUDE.md` exists with no markers: insert the block immediately after the first top-level `#` heading (or at top if none). Leave the rest of the file untouched — no reformatting, no deleting.

4. **Do not** paraphrase or shorten the template body. Do not embed the body inline in `CLAUDE.md`. The `@.claude/publishing-directive.md` import is load-bearing — it survives CLAUDE.md regeneration by other tools far better than an inline block.

5. **Verify.** Run `npm run check:cws`. The `claude-md-publishing-directive-present` rule will be red if either the marker block or `.claude/publishing-directive.md` is missing/corrupt. Green = the injection succeeded.

**Version bumps.** To evolve the directive: edit `skills/cce-init/templates/publishing-directive.md` and bump the marker suffix (`v1` → `v2`) in this skill's splice block above. Phase H's prefix match (`<!-- CCE:publishing-directive:begin`) will replace the older block on the next run. Old scaffolds self-heal on the next `/cce-init`.

### Drop the marker

Write a single-line file at the repo root: `.cce-init-done`

Content is just the current date in ISO 8601 (e.g., `2026-04-16`). This file is purely a signal to future `cce-init` invocations that initialization is complete; it has no other consumer.

### Update `.gitignore`

Read the current `.gitignore`. If it doesn't already contain `.cce-init-done`, add a section:

```
# cce-init marker (local-only; signals init has been run)
.cce-init-done
```

Add it above the existing `# Secrets` section or near the bottom — order doesn't matter, grouping does. Don't accidentally reformat the rest of the file.

### Print the summary

> **Init complete.** Factory customized to your profile.
>
> What you did:
> - Profile: `<profile name>` (deleted: `<list of deleted paths>`)
> - Listing: name `<name>`, description `<N>` chars. (Run `cws-content` to rewrite.)
> - Screenshots: `<done via cws-screens>` | `<skipped — run cws-screens later>`
> - OAuth: `<configured — 4 secrets in env>` | `<deferred — use manual zip upload>`
>
> Current state:
> - `npm run check:cws` — green (structural is clean)
> - `npm run check:cws:ship` — `<green>` | `<still flagging ship-ready-screenshots, which is expected since you skipped Phase E>`
>
> Next steps:
> - To rewrite listing copy later: invoke `/cws-content`.
> - To scaffold screenshots later: invoke `/cws-screens`.
> - When ready to submit: invoke `/cws-ship` — it runs the whole pipeline end-to-end.

If Phase F was run (OAuth configured), add:

> `npm run ship` is wired for auto-publish. The secrets are in your shell env.

If Phase F was deferred:

> When you want to flip `npm run ship` on, re-run `/cce-init` and pick option 4 (OAuth setup).

Stop. Do not re-run anything else.

---

## Worked example — "popup-based" profile, full run

This traces a complete fresh-clone run so you can see the shape of a good session.

### Starting state

User runs `/cce-init` on a freshly-cloned factory. Phase A checks:

- `.cce-init-done` — absent.
- `wxt.config.ts` `manifest.name` — `'My Extension'`.
- `entrypoints/welcome/config.ts` — contains `"A brief one-sentence description"` and `"your-org"`.

All three signals say fresh. Continue to Phase B.

### Phase B — orient

Skill prints the 4-sentence philosophy summary + the command table. User says "got it."

### Phase C — profile selection

Skill asks which shape fits. User says:

> I'm building a quick-action tool triggered from the toolbar — a popup that lets me save the current tab's URL to a list.

Skill suggests **profile 2 (popup-based)** and confirms. User confirms.

Skill asks: "Do you need a welcome page? You're asking for host access (reading the current tab) — so probably yes."

User: "I'm only using `chrome.tabs.query()` for the active tab's URL, which just needs the `activeTab` permission — I don't need broad host access. Delete the welcome page."

Skill summarizes the delete plan:

```
About to delete:
  entrypoints/content.ts
  entrypoints/sidepanel/
  utils/dom.ts
  utils/observer.ts
  entrypoints/welcome/
  utils/permissions.ts

Also removing the `tabs.create` welcome-open block from entrypoints/background.ts.

Proceed? (y/n)
```

User: "y."

Skill deletes each path. Then runs:

```bash
npx wxt prepare
```

Output: WXT regenerates types without `entrypoints/welcome/` in the entrypoint set.

Skill inspects `wxt.config.ts`. Orphaned permissions:

- `'sidePanel'` — no sidepanel entrypoint anymore.
- `'alarms'` — background still exists but alarms block is unused; user confirms they don't need alarms → remove.
- `optional_host_permissions: ['https://example.com/*']` — welcome page was the only consumer → remove.
- `minimum_chrome_version: '114'` — only needed for sidePanel → remove.

Skill edits `wxt.config.ts`. The manifest now reads:

```ts
manifest: {
  name: 'My Extension',
  description: 'A brief description of what this extension does.',
  permissions: ['storage'],
},
```

Skill also trims `entrypoints/background.ts`: removes the `browser.runtime.onInstalled` tabs.create block (welcome is gone) and the `browser.alarms.create` block (alarms permission removed). Leaves the `onMessage('ping', ...)` block so the popup can message the background.

Skill runs `npm run check:cws`. Green. Phase C is done.

### Phase D — listing content

Skill says:

> Now invoking `cws-content` to fill in listing metadata. It'll ask you about name, description, and welcome-page copy. (Welcome's deleted for your profile, so it'll skip the welcome recipe.)

Skill delegates to `cws-content`. That skill runs its validator check, finds 3 content errors (name, description, optional-host — no welcome since it was deleted), runs its Recipes A, B, C with the user:

- **A (name)**: user describes "save the current tab to a reading list"; skill drafts 3 candidates; user picks "Tab Stash."
- **B (description)**: skill drafts 3 descriptions; user picks a feature-framed one ~110 chars.
- **C (optional-host)**: user clarifies the extension uses `activeTab` rather than broad host access — no origins needed. Skill writes `optional_host_permissions: []` (empty array; the rule only fires on the `https://example.com/*` placeholder specifically).

`cws-content` re-runs the validator, reports: 0 content errors remaining (welcome was deleted, so `ship-ready-welcome-config` doesn't fire; `ship-ready-screenshots` still fires because screenshots haven't been generated, but that's Phase E's problem, not cws-content's).

`cws-content` hands control back.

### Phase E — screenshots

Skill checks: `screenshots/` exists (default factory state; user didn't delete it). Offers:

> Want to scaffold your 5 CWS screenshots now? (yes / skip)

User: "skip. Coming back to this later."

Skill notes: `ship-ready-screenshots` will stay red until `/cws-screens` runs. Moving on.

### Phase F — OAuth setup

Skill asks:

> Want to enable automated publishing? (yes / defer)

User: "defer."

Skill: "OK — manual zip upload via the CWS dashboard is fine. `npm run zip` produces the zip; drag-and-drop into the developer console. Come back and re-run `/cce-init` option 4 when you want automation."

### Phase G — confirm green

Skill runs:

```bash
npm run check:cws
```

Green. Phase G passes.

### Phase H — finalize

Skill writes `.claude/publishing-directive.md` by copying byte-for-byte from `skills/cce-init/templates/publishing-directive.md`.

Skill splices the marker block into `CLAUDE.md` (idempotent — prefix-matches `<!-- CCE:publishing-directive:begin` so stale versions get replaced cleanly):

```
<!-- CCE:publishing-directive:begin v2 -->
@.claude/publishing-directive.md

<!--
  The directive body lives at `.claude/publishing-directive.md` (imported above).
  This block is managed by `cce-init` Phase H. Do not hand-edit between the
  markers — edits get overwritten on the next `/cce-init` run.
-->
<!-- CCE:publishing-directive:end -->
```

Skill writes `.cce-init-done`:

```
2026-04-16
```

Skill edits `.gitignore` to add:

```
# cce-init marker (local-only; signals init has been run)
.cce-init-done
```

Skill runs `npm run check:cws` to confirm `claude-md-publishing-directive-present` is green.

Skill prints summary:

> **Init complete.** Factory customized to your profile.
>
> What you did:
> - Profile: popup-based (deleted: `entrypoints/content.ts`, `entrypoints/sidepanel/`, `utils/dom.ts`, `utils/observer.ts`, `entrypoints/welcome/`, `utils/permissions.ts`; trimmed `entrypoints/background.ts` and `wxt.config.ts`)
> - Listing: name "Tab Stash," description 110 chars.
> - Screenshots: skipped — run `/cws-screens` later.
> - OAuth: deferred — use manual zip upload via CWS dashboard.
>
> Current state:
> - `npm run check:cws` — green
> - `npm run check:cws:ship` — red on `ship-ready-screenshots` (expected; run `/cws-screens` to clear).
>
> Next steps:
> - To scaffold screenshots later: invoke `/cws-screens`.
> - When you want auto-publish: re-run `/cce-init` and pick option 4 (OAuth setup).
> - When ready to submit: invoke `/cws-ship`.

### Final filesystem state (diff from fresh clone)

Deleted:
- `entrypoints/content.ts`
- `entrypoints/sidepanel/` (directory + contents)
- `entrypoints/welcome/` (directory + contents)
- `utils/dom.ts`
- `utils/observer.ts`
- `utils/permissions.ts`

Modified:
- `wxt.config.ts` — permissions trimmed, optional_host_permissions removed, minimum_chrome_version removed, name + description filled in.
- `entrypoints/background.ts` — welcome tab-create block removed, alarms block removed.
- `.gitignore` — added `.cce-init-done` entry.
- `CLAUDE.md` — publishing-directive marker block (re-)injected.

Created:
- `.cce-init-done` — one-line ISO date.
- `.claude/publishing-directive.md` — canonical CWS-publishing directive (~3KB), imported by CLAUDE.md. Enforced by the `claude-md-publishing-directive-present` validator rule.

This is the end state cce-init is responsible for. `cws-content` owns `wxt.config.ts`'s name/description and (if it still existed) `welcome/config.ts`; `cce-init` owns the profile-strip, the marker, and the publishing directive.

---

## Failure-mode notes

- **User picks a profile, you delete, then `wxt prepare` fails.** The user kept a file that imports from something you deleted. Surface the WXT error, identify the bad import, offer to edit the kept file to remove it. Do NOT re-add the deleted file — that defeats the strip.

- **User changes their mind mid-Phase-C.** If they say "actually I want the sidepanel," stop, apologize, offer to restore from git: `git checkout -- entrypoints/` (if nothing's been committed yet) or `git restore entrypoints/` (more modern). Do not try to manually re-create the files. After restore, re-confirm the profile choice and re-do the delete.

- **`cws-content` fails mid-run** (user refused to answer, network issue, etc.). That's `cws-content`'s problem to handle, not yours. Accept whatever state it reports back in and move to Phase E. The factory invariant tolerates a partial `check:cws:ship` state — `check:cws` is the one that must stay green, and that's structural, not content.

- **User already ran init once, then deleted `.cce-init-done` by accident, then re-invokes.** Phase A's three signals will still detect "not fresh" because the manifest name won't be `'My Extension'` anymore. Good — the skill won't destructively re-run. If the user insists ("no really, it's a fresh start"), they should re-clone the repo rather than fight the detector.

- **`check:cws` is red in Phase G and the user can't figure out why.** Don't guess — read the validator's JSON output. Each finding has a `fix` field naming the exact file and change. Show the user the full finding verbatim and work through one at a time. The rule ids are stable contracts; trust them.

- **User is on Windows.** Delete commands and path separators differ (`rmdir /s` vs `rm -rf`; backslashes vs forward slashes). Use cross-platform approaches where possible; `npx wxt prepare` works either way. Node's `fs.rmSync` with `{ recursive: true }` is a portable alternative if shell commands misbehave.

---

## What this skill does NOT do

- Does not write listing copy, welcome config, or any content the user is responsible for. Delegates to `cws-content`.
- Does not generate screenshots. Delegates to `cws-screens`.
- Does not submit, zip, or publish. That's `cws-ship` (future skill).
- Does not modify `scripts/`, validator rules, or any deterministic-substrate file. It only touches entrypoints/ (profile-strip), `wxt.config.ts` (orphan-permission cleanup), `.gitignore` (marker entry), and the `.cce-init-done` marker itself.
- Does not duplicate the OAuth setup walkthrough — `docs/06-keepalive-publish.md` is the source of truth; this skill references it and just runs the terminal side.
- Does not fabricate defaults. If the user deflects a question, the skill delegates or skips, it does not fill in plausible-looking values.
- Does not run on an already-initialized factory. Phase A's detector short-circuits to the sub-recipe menu.

Files in this skill

  • SKILL.md40.6 KB
  • templates/publishing-directive.md5.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.