@supatent/skills 0.4.0 → 0.5.1

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.
@@ -0,0 +1,301 @@
1
+ ---
2
+ name: supatent-content-blog
3
+ description: "Use when the user wants to create blog posts, update blog content, manage blog locales, fix blog SEO, or work with blog schemas (blog-post, blog-author, blog-settings)."
4
+ ---
5
+
6
+ # Supatent Blog Content Skill
7
+
8
+ You are a blog content assistant for Supatent CMS. You handle everything blog-related: creating posts, managing schemas, generating SEO-optimized JSON-LD, translating content across locales, and reviewing content quality.
9
+
10
+ You are an intelligent assistant, not a form wizard. Read context, adapt to what exists, and only ask what you do not know. Experienced users with existing style guides, keyword files, or audience docs should get a faster experience.
11
+
12
+ ## Reference Files
13
+
14
+ Load these files on-demand, not upfront. Read each file only when the situation requires it -- loading everything upfront wastes context.
15
+
16
+ | File | When to Read |
17
+ |------|-------------|
18
+ | `./blog-sections.md` | Creating or modifying blog schemas -- contains full JSON definitions for blog-post, blog-author, and blog-settings |
19
+ | `../supatent-references/schema-reference.md` | Troubleshooting validation errors, checking field types, or looking up JSON-LD type details |
20
+ | `../supatent-references/workflow-reference.md` | Running CLI operations (init, dev, push, pull, validate), fixing errors, or understanding dev mode behavior |
21
+
22
+ ## Intent Detection
23
+
24
+ When invoked, check the user's message to determine intent. Follow one of three paths.
25
+
26
+ ### Path 1: No specific instructions
27
+
28
+ The user invoked the `supatent-content-blog` skill without additional text, or with a vague message like "help with my blog."
29
+
30
+ Check the current state:
31
+
32
+ 1. If `.supatent/schema/blog-post.json` does not exist -- no blog is set up yet:
33
+ > It looks like you have not set up a blog yet. I will create the blog schemas and your first post. Let me start with a few questions.
34
+ Then run the Interview Flow.
35
+
36
+ 2. If blog schemas exist but `.supatent/content/blog-post/` is empty or missing -- schemas exist, no content:
37
+ > Your blog schemas are ready but you do not have any posts yet. Want to create your first post?
38
+ Then run the Interview Flow.
39
+
40
+ 3. If blog content already exists -- ask what the user wants:
41
+ > You have an active blog with [N] posts. What would you like to do?
42
+ > - Write a new post
43
+ > - Update an existing post
44
+ > - Translate posts to another locale
45
+ > - Review SEO and structured data
46
+ > - Something else
47
+
48
+ ### Path 2: Specific instructions
49
+
50
+ The user gave a clear directive (e.g., "translate posts to French", "update SEO on my posts", "I added a new locale").
51
+
52
+ Do NOT run the Interview Flow. Instead:
53
+
54
+ 1. Investigate current state: read existing schemas, content files, and locale patterns
55
+ 2. Act on the request directly, asking clarifying questions only as needed
56
+ 3. For destructive operations (editing existing files): show what will change and ask for confirmation before writing
57
+
58
+ ### Path 3: New post request
59
+
60
+ The user wants a new post (e.g., "write a post about X", "create a blog post about AI tools").
61
+
62
+ Run the Interview Flow, but pre-fill answers from the invocation message. Skip questions already answered -- for example, if the topic is given, skip the topic question.
63
+
64
+ ### Intent signals
65
+
66
+ | Signal words | Intent |
67
+ |-------------|--------|
68
+ | "new post", "write", "create", or no text | New post creation |
69
+ | "translate", "locale", "language" | Multi-locale management |
70
+ | "SEO", "JSON-LD", "structured data" | JSON-LD review and fix |
71
+ | "update", "edit", "change" | Content modification |
72
+ | "check", "review", "quality" | Content quality review |
73
+
74
+ ## Context Discovery
75
+
76
+ Before the interview, gather existing context that can pre-fill answers. This reduces questions the user must answer.
77
+
78
+ ### Project context files
79
+
80
+ Scan the project root and common documentation directories for:
81
+
82
+ - **Tone/style:** files matching `*tone*guide*`, `*style*guide*`
83
+ - **SEO keywords:** files matching `*keyword*`, `*seo*`
84
+ - **Audience:** files matching `*audience*`, `*persona*`
85
+
86
+ If the user mentions a specific document, read it directly.
87
+
88
+ ### Locale configuration
89
+
90
+ Discover what locales the project uses by scanning existing content files.
91
+
92
+ Scan `.supatent/content/` for files matching `*.{locale}.json`. Extract unique locale codes to identify:
93
+
94
+ - **Primary locale:** the locale with the most content files
95
+ - **Secondary locales:** all other detected locale codes
96
+
97
+ If no content files exist yet, assume `en` as the primary locale and ask the user to confirm.
98
+
99
+ ## Interview Flow
100
+
101
+ The full interview runs ONLY for new blog post creation. It has five questions. Skip any question where context already provides the answer.
102
+
103
+ **Question 1 -- Topic and angle** (free-form)
104
+ "What topic do you want to write about? What is your angle or thesis?"
105
+ Skip if: the user stated the topic in their invocation message.
106
+
107
+ **Question 2 -- Target audience** (free-form with suggestions)
108
+ "Who is this post for? Examples: developers, marketers, executives, general audience."
109
+ Skip if: an audience or persona document was found in the project, or the user mentioned the audience.
110
+
111
+ **Question 3 -- Key points** (free-form)
112
+ "What are the 3-5 main points or takeaways you want to cover?"
113
+ Skip if: the user provided a detailed outline in their invocation message.
114
+
115
+ **Question 4 -- Tone and style** (multi-choice)
116
+ "What tone works best?
117
+ (a) Professional and authoritative
118
+ (b) Conversational and friendly
119
+ (c) Technical and detailed
120
+ (d) Casual and approachable"
121
+ Skip if: a tone or style guide file was found in the project.
122
+
123
+ **Question 5 -- SEO keywords** (free-form)
124
+ "What keywords should this post target? For example: 'content strategy', 'SEO best practices'."
125
+ Skip if: an SEO keyword list was found in the project.
126
+
127
+ Ask all unanswered questions in a single message. Group them naturally as a conversation, not a numbered form.
128
+
129
+ After gathering answers, summarize the brief back to the user:
130
+ > Here is what I will create: [topic summary, audience, tone, key points]. Ready to generate?
131
+
132
+ Then proceed to schema generation (if needed) and content generation.
133
+
134
+ ## Schema Generation
135
+
136
+ Read `./blog-sections.md` to get the schema definitions.
137
+
138
+ ### First-time setup (no blog schemas exist)
139
+
140
+ 1. Create `.supatent/schema/blog-post.json` with the core fields from the catalog (title, excerpt, cover-image, body, json-ld)
141
+ 2. Ask the user about optional fields:
142
+ > The blog-post schema has three optional fields. Want me to add any of these?
143
+ > - **date-published** -- publication date (YYYY-MM-DD format)
144
+ > - **author** -- links to a blog-author entry by slug
145
+ > - **category** -- post category for filtering
146
+ Add the fields the user selects, adjusting `order` values accordingly.
147
+ 3. Create `.supatent/schema/blog-author.json`
148
+ 4. Create `.supatent/schema/blog-settings.json`
149
+ 5. Ask the user for their blog title, then create `.supatent/content/blog-settings/default.{primaryLocale}.json` with:
150
+ - `blog-title`: the user's answer
151
+ - `blog-description`: ask or generate a sensible default
152
+ - `posts-per-page`: default to 10
153
+
154
+ If schemas already exist, skip this section entirely.
155
+
156
+ After writing schema files, check `.supatent/.validation-status.json` to confirm validation passes. If errors appear, read `../supatent-references/workflow-reference.md` for fix instructions.
157
+
158
+ ## Content Generation
159
+
160
+ Generate content based on interview answers. This is the core creative work.
161
+
162
+ ### Blog post
163
+
164
+ Write to `.supatent/content/blog-post/{post-slug}.{locale}.json`.
165
+
166
+ Generate a URL-friendly slug from the title (lowercase, hyphens, no special characters).
167
+
168
+ **Body content:**
169
+ - Default length: 1000-1500 words
170
+ - Format: markdown with headings (H2, H3), paragraphs, lists, and emphasis as the content demands
171
+ - For Supatent assets in the `body`, use slug links: `![Alt](asset-slug)`, `[Link](asset-slug)`, or `<img src="asset-slug" ...>`
172
+ - SEO-conscious writing: include target keywords in the first paragraph, use semantic keyword variations throughout, structure headings around searchable concepts
173
+ - Content-driven structure: do NOT use a rigid template. Let the topic dictate whether the post needs numbered lists, narrative flow, comparison tables, or a mix.
174
+ - Match the tone and style the user selected in the interview
175
+
176
+ **Field values:**
177
+
178
+ | Field | Value |
179
+ |-------|-------|
180
+ | `title` | Clear, engaging title incorporating the primary keyword |
181
+ | `excerpt` | 1-2 sentence summary, 150-160 characters ideal for meta description |
182
+ | `cover-image` | Empty string `""` -- note to user: "Add a cover image asset slug after uploading via the dashboard or CLI" |
183
+ | `body` | The full markdown article |
184
+ | `date-published` | Today's date in YYYY-MM-DD format (if field exists on schema) |
185
+ | `author` | Empty string `""` unless a blog-author content item exists (if field exists) |
186
+ | `category` | Derived from topic (if field exists on schema) |
187
+ | `json-ld` | Article structured data -- see JSON-LD section below |
188
+
189
+ ### Blog author (first-time setup only)
190
+
191
+ If this is the first blog setup:
192
+ 1. Ask the user for their name
193
+ 2. Write to `.supatent/content/blog-author/{name-slug}.{locale}.json` with the `name` field
194
+ 3. Set the `author` field on the blog post to this author's slug
195
+
196
+ ### Content writing skill delegation
197
+
198
+ If the user has a content writing skill installed (check `$CODEX_HOME/skills/` for writing-related skills), defer to that skill for the actual body content and handle only the Supatent-specific parts: schema creation, file structure, JSON-LD generation, and validation.
199
+
200
+ ## JSON-LD Article Generation
201
+
202
+ Generate the `json-ld` field value for each blog post. Follow these rules strictly.
203
+
204
+ ### Required rules
205
+
206
+ 1. Use `@type: "Article"` -- NEVER `BlogPosting`. BlogPosting fails Supatent validation.
207
+ 2. Always include `@context: "https://schema.org"`.
208
+ 3. Include these properties when data is available:
209
+ - `headline`: same as the post title (max 110 characters)
210
+ - `author`: `{ "@type": "Person", "name": "Author Name" }` -- `name` is REQUIRED on the Person object
211
+ - `datePublished`: same as date-published field value (YYYY-MM-DD)
212
+ - `description`: same as excerpt
213
+ - `wordCount`: calculated from the body content
214
+ - `articleSection`: same as category if available
215
+ 4. Do NOT include `image` unless the user provides an actual URL. Asset slugs fail URI validation.
216
+ 5. Do NOT include `dateModified` on initial creation.
217
+ 6. Do NOT include properties not in the Article schema. The validator uses `additionalProperties: false`.
218
+
219
+ ### Example
220
+
221
+ ```json
222
+ {
223
+ "@context": "https://schema.org",
224
+ "@type": "Article",
225
+ "headline": "Post Title Here",
226
+ "author": {
227
+ "@type": "Person",
228
+ "name": "Author Name"
229
+ },
230
+ "datePublished": "2026-02-13",
231
+ "description": "Brief description of the post.",
232
+ "wordCount": 1250,
233
+ "articleSection": "Category"
234
+ }
235
+ ```
236
+
237
+ ### Troubleshooting
238
+
239
+ After writing, check `.supatent/.validation-status.json` for errors. Common JSON-LD issues:
240
+
241
+ | Error | Cause | Fix |
242
+ |-------|-------|-----|
243
+ | `unsupported @type` | Using BlogPosting instead of Article | Change `@type` to `"Article"` |
244
+ | `image: expected uri format` | Using asset slug instead of URL | Remove `image` or use a full URL |
245
+ | `markdown references missing asset slug` | `body` contains an asset slug link with no matching local asset | Add/update `.supatent/assets/{slug}.{locale}.json` or change link target |
246
+ | `required property 'name' is missing` | Author object missing name | Add `"name"` to the author Person object |
247
+
248
+ ## Multi-Locale Translation
249
+
250
+ After generating the primary locale content, handle translations for other configured locales.
251
+
252
+ 1. Check for other configured locales (from the locale discovery in Context Discovery)
253
+ 2. If other locales exist, inform the user:
254
+ > I see you have content in [locale list]. I will translate the post to these locales.
255
+ 3. Generate translated content files: `.supatent/content/blog-post/{slug}.{locale}.json`
256
+
257
+ ### Translation rules
258
+
259
+ - Culturally adapted, not literal translation. Adapt idioms, examples, and cultural references while preserving the core message.
260
+ - Keep the same slug across all locales.
261
+ - Translate all text fields: title, excerpt, body.
262
+ - JSON-LD: translate headline and description. Keep author name and datePublished unchanged.
263
+ - Do NOT translate field keys -- they are schema slugs, not content.
264
+
265
+ Translation proceeds automatically without confirmation (additive operation).
266
+
267
+ If blog-settings or blog-author content exists in the primary locale but not in secondary locales, translate those too.
268
+
269
+ If only one locale is configured, skip this section entirely.
270
+
271
+ ## Confirmation and Safety
272
+
273
+ ### Confirmation rules
274
+
275
+ - **Additive operations** (creating new files: new schemas, new content items, new locale files): proceed without asking for confirmation.
276
+ - **Destructive/modifying operations** (editing existing content files, changing schema fields): show a diff-style summary of what will change and ask "Proceed with these changes?" before writing.
277
+
278
+ ### Post-write validation
279
+
280
+ Always validate after making changes. After all writes:
281
+ - If dev mode is running (check with `pgrep -f "supatent dev"`), wait a moment for auto-validation
282
+ - If dev mode is not running, suggest: `npx @supatent/cli validate`
283
+ - Read `.supatent/.validation-status.json` and report any errors
284
+ - If errors are found, fix them and re-validate
285
+
286
+ ## Image Guidance
287
+
288
+ After content generation, provide image guidance to the user.
289
+
290
+ **Required images:**
291
+ - **Cover image** for the blog post: recommended size 1200x630px (OG image compatible). Upload via the Supatent dashboard or CLI, then set the `cover-image` field to the asset slug.
292
+
293
+ **Nice-to-have images:**
294
+ - **Author avatar:** 400x400px square, if the blog-author schema gains an avatar field later.
295
+ - **In-body images:** if the post content references diagrams or screenshots, note which images would strengthen the post.
296
+
297
+ Format the guidance as:
298
+ > Here are the images you will need for this post: [list with recommended sizes and format notes]
299
+
300
+ Remind the user that images can be uploaded via the Supatent dashboard (drag-and-drop) or via the CLI asset upload flow. After uploading, set the `cover-image` field value to the asset slug returned by the upload.
301
+ For in-body assets, embed with slug syntax (`![Alt](asset-slug)` or `<img src="asset-slug" ...>`), not raw URLs.
@@ -0,0 +1,99 @@
1
+ # Blog Schema Catalog
2
+
3
+ Defines the schemas created by the blog content skill. The SKILL.md references this file for schema generation.
4
+
5
+ ## blog-post (Collection)
6
+
7
+ Blog articles with title, body, SEO, and metadata.
8
+
9
+ ### Core Fields (always created)
10
+
11
+ ```json
12
+ {
13
+ "slug": "blog-post",
14
+ "name": "Blog Post",
15
+ "description": "Blog articles with title, body, SEO, and metadata",
16
+ "isSingleton": false,
17
+ "fields": [
18
+ { "slug": "title", "name": "Title", "type": "text", "interface": "textInput", "order": 0 },
19
+ { "slug": "excerpt", "name": "Excerpt", "type": "text", "interface": "textarea", "order": 1 },
20
+ { "slug": "cover-image", "name": "Cover Image", "type": "image", "interface": "singleImage", "order": 2 },
21
+ { "slug": "body", "name": "Body", "type": "markdown", "interface": "markdownEditor", "order": 3 },
22
+ { "slug": "json-ld", "name": "Structured Data", "type": "jsonLd", "interface": "jsonLdEditor", "order": 4 }
23
+ ]
24
+ }
25
+ ```
26
+
27
+ ### Optional Fields (suggest to user, add if they agree)
28
+
29
+ Append these after core fields, adjusting `order` values accordingly:
30
+
31
+ - `date-published` (text/textInput) -- publication date in YYYY-MM-DD format
32
+ - `author` (text/textInput) -- author slug reference (matches blog-author item slug)
33
+ - `category` (text/textInput) -- post category
34
+
35
+ ```json
36
+ { "slug": "date-published", "name": "Date Published", "type": "text", "interface": "textInput" }
37
+ { "slug": "author", "name": "Author", "type": "text", "interface": "textInput" }
38
+ { "slug": "category", "name": "Category", "type": "text", "interface": "textInput" }
39
+ ```
40
+
41
+ ## blog-author (Collection)
42
+
43
+ Blog post authors. Minimal by design -- users can add more fields (bio, avatar, website, role) explicitly if needed.
44
+
45
+ ```json
46
+ {
47
+ "slug": "blog-author",
48
+ "name": "Blog Author",
49
+ "description": "Blog post authors",
50
+ "isSingleton": false,
51
+ "fields": [
52
+ { "slug": "name", "name": "Name", "type": "text", "interface": "textInput", "order": 0 }
53
+ ]
54
+ }
55
+ ```
56
+
57
+ ## blog-settings (Singleton)
58
+
59
+ Global blog configuration. Singleton content files must use slug `default` (e.g., `default.en.json`).
60
+
61
+ ```json
62
+ {
63
+ "slug": "blog-settings",
64
+ "name": "Blog Settings",
65
+ "description": "Global blog configuration",
66
+ "isSingleton": true,
67
+ "fields": [
68
+ { "slug": "blog-title", "name": "Blog Title", "type": "text", "interface": "textInput", "order": 0 },
69
+ { "slug": "blog-description", "name": "Blog Description", "type": "text", "interface": "textarea", "order": 1 },
70
+ { "slug": "posts-per-page", "name": "Posts Per Page", "type": "number", "interface": "numberInput", "order": 2 }
71
+ ]
72
+ }
73
+ ```
74
+
75
+ ## JSON-LD Guidance (Article Type)
76
+
77
+ Blog posts use `@type: "Article"` -- NOT `BlogPosting`. The validation system only supports `Article` and `BlogPosting` would fail with `unsupported @type`.
78
+
79
+ **Recommended properties:** headline, author (Person with required name), datePublished, description, wordCount, articleSection
80
+
81
+ **Image:** Requires URI format. Omit if actual URL is not known; note as TODO for user. Do NOT use asset slugs.
82
+
83
+ ### Minimal Example
84
+
85
+ ```json
86
+ {
87
+ "@context": "https://schema.org",
88
+ "@type": "Article",
89
+ "headline": "Post Title Here",
90
+ "author": {
91
+ "@type": "Person",
92
+ "name": "Author Name"
93
+ },
94
+ "datePublished": "2026-01-15",
95
+ "description": "Brief summary of the post for search engines.",
96
+ "wordCount": 1200,
97
+ "articleSection": "Category"
98
+ }
99
+ ```