Skill
/create-press
One trigger, two branches. If no workspace exists, bootstrap one from zero. If a workspace already exists, add another <Press> to it.
Detects whether the user is in a fresh directory or an existing OpenPress workspace, then runs the matching branch. Branch A scaffolds a workspace + first Press via @open-press/cli init. Branch B adds a second/third/Nth <Press> to an existing <Workspace>.
/create-press
Lives at skills/openpress-init/. The slash trigger
/create-press is matched by the skill's description field; an AI tool that has
loaded the OpenPress skill bundle will recognise it.
0. Environment preflight
Always runs first. Verify Node ≥20 via node -v; halt and instruct on install if
missing.
1. Detect the branch
test -f press/index.tsx && grep -q "<Workspace" press/index.tsx && echo BRANCH_B || echo BRANCH_A | Name | Type | Default | Description |
|---|---|---|---|
BRANCH_A | bootstrap | No press/index.tsx, or it doesn't wrap children in <Workspace>. The agent treats this as a fresh project and bootstraps a workspace from zero. | |
BRANCH_B | add | press/index.tsx already default-exports a <Workspace> root. The agent adds a new <Press> child to it. |
If press/index.tsx exists but is in the legacy v0.x shape (no <Workspace>),
the skill tells the user to run npx open-press upgrade first, then re-invoke
/create-press.
Branch A — bootstrap a fresh workspace
A.1 Target check
The CLI rejects non-empty targets automatically. A lone .git/,
.gitignore, .gitkeep, or .DS_Store is fine. If the
target has real content, the agent asks the user to clean it first — there is no
--force flag.
A.2 Intake (one batch)
Required
| Name | Type | Default | Description |
|---|---|---|---|
document type | string | Proposal / whitepaper / paper / teaching note / book / slide deck / social campaign — drives downstream skill selection. | |
audience | string | Who will read it. Often informs voice / level of detail. | |
primary language | string | Document language for writing skill routing (e.g. chinese-ai-writing-polish). | |
title | string | Written into <Press title="...">. | |
page geometry | preset | custom | Show the type's default page; let the user override. See table below. |
Page geometry — default by document type
| Name | Type | Default | Description |
|---|---|---|---|
report / paper / book | default | a4. Override examples: us-letter (custom), a5. | |
slide deck | default | slide-16-9. Override: slide-4-3 (custom). | |
social post | default | social-square. Override: story card (1080 × 1350 custom). | |
hybrid (mixed-format brief) | default | a4 — one geometry per Press. If the user truly needs two page sizes in the same project (A4 body + 16:9 cover), use a multi-Press <Workspace> with one Press per geometry. Per-<Frame> page override is not supported in 1.0. |
When the user opts for custom:
- width (e.g. 1080px)
- height (e.g. 1350px)
- units must match (mm / cm / in / pt / pc / px)
The agent builds { id, label, width, height } and passes via <Press page>. The skill does not ask for subtitle / organization / author / version / footer. Those are rendered text — they live in the Cover JSX, not on Press props.
A.3 Run init
npx @open-press/cli init <target> --title "<title>" A.4 Verify
npm run build
npm run dev -- --dry-run A.5 Handoff report
- Target path
- Workspace name (if set on
<Workspace name="...">) - The Press's
titleandpage - Next-owner skill (writing / design / deploy)
- Next editable paths:
press/index.tsx,press/chapters/,press/theme/,press/components/
Branch B — add a Press to an existing workspace
B.1 Read the workspace
Open press/index.tsx, parse the <Workspace> block to identify
existing Press children, their slugs, pages, and source roots. If only one Press exists and
has no slug prop, the workspace is in implicit single-Press mode — adding a
second Press promotes it to multi-Press, and the existing Press needs a slug too.
B.2 Intake (one batch)
Required
| Name | Type | Default | Description |
|---|---|---|---|
slug | string | URL segment + per-Press directory name. Slug-shaped (a-z, 0-9, hyphens). The agent asks explicitly; it never autogenerates. | |
title | string | For the new <Press title="...">. | |
page geometry | preset | custom | Same intake as Branch A — defaults by document type, custom on request. | |
source layout | own | shared | Default own — new Press gets press/<slug>/chapters/. shared means it reuses a source already registered on another Press; the agent confirms which one. |
B.3 Modify press/index.tsx
<Workspace name="Series A launch">
<Press
slug="proposal"
title="Series A 提案書"
page="a4"
sources={[mdxSource({ id: "proposal", preset: "section-folders", root: "proposal/chapters" })]}
>
{/* ...existing tree... */}
</Press>
{/* ↓ NEW — added by /create-press in Branch B */}
<Press
slug="pitch-deck"
title="Investor pitch"
page="slide-16-9"
sources={[mdxSource({ id: "pitch-deck", preset: "section-folders", root: "pitch-deck/chapters" })]}
>
{/* skeleton frames go here */}
</Press>
</Workspace>
Existing children are preserved exactly — the skill never reorders or rewrites siblings while
adding a new one. If the previous single-Press had no slug, the skill adds one
in the same edit.
B.4 Create per-Press folder structure
mkdir -p press/<slug>/chapters/01-intro/content
mkdir -p press/<slug>/components
Theme is shared at press/theme/ unless the user explicitly asked for per-Press
theme override. In that case the agent adds theme="./<slug>/theme"
to the new <Press> props and creates press/<slug>/theme/.
B.5 Verify
npm run build
# build output should show one bundle per Press;
# count must match the number of <Press> children B.6 Handoff report
- New slug + title + page
- Folder structure created
- Whether the prior Press received a slug as part of this operation
- Next editable paths under
press/<slug>/ - Next owning skill
Boundary
- Does not write document content. The first draft is the next skill's job.
- Does not pick a brand / theme. Theme intake is
/create-theme. - Does not deploy.
- Does not ask for subtitle / organization / author — those belong in Cover JSX.
- In Branch B, never modifies existing
<Press>siblings except to add a missingslugwhen promoting single-Press → multi-Press.