@veyralabs/skills 0.1.0
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/LICENSE +21 -0
- package/README.md +182 -0
- package/bin/cli.js +135 -0
- package/install.sh +226 -0
- package/package.json +47 -0
- package/skills/brandaudit/SKILL.md +278 -0
- package/skills/brandaudit/references/audit-framework.md +156 -0
- package/skills/brandaudit/references/examples/sample-audits.md +239 -0
- package/skills/brandaudit/references/rebrand-decisions.md +215 -0
- package/skills/brandaudit/references/weakness-patterns.md +187 -0
- package/skills/competitornames/SKILL.md +250 -0
- package/skills/competitornames/references/examples/sample-analyses.md +185 -0
- package/skills/competitornames/references/pattern-analysis.md +94 -0
- package/skills/competitornames/references/whitespace-mapping.md +146 -0
- package/skills/domainforge/SKILL.md +266 -0
- package/skills/domainforge/references/brand-archetypes.md +147 -0
- package/skills/domainforge/references/examples/sample-outputs.md +141 -0
- package/skills/domainforge/references/naming-patterns.md +168 -0
- package/skills/domainforge/references/scoring-rubric.md +168 -0
- package/skills/domainforge/references/tld-strategy.md +112 -0
- package/skills/namingguide/SKILL.md +264 -0
- package/skills/namingguide/references/examples/sample-guides.md +212 -0
- package/skills/namingguide/references/guide-structure.md +155 -0
- package/validate.js +142 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Guide Structure — NamingGuide Reference
|
|
2
|
+
|
|
3
|
+
Naming system patterns, tier structures, and how to match them to company type.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Naming System Patterns
|
|
8
|
+
|
|
9
|
+
### Pattern 1: Standalone Brand (Apple model)
|
|
10
|
+
|
|
11
|
+
Each product is a standalone brand. Features are descriptive. No prefix.
|
|
12
|
+
|
|
13
|
+
**Structure:**
|
|
14
|
+
- Company: Apple
|
|
15
|
+
- Products: iPhone, iPad, Mac, Apple Watch (note: Apple prefix added late, after brand confusion)
|
|
16
|
+
- Features: FaceTime, Siri, AirDrop — branded features get their own names
|
|
17
|
+
- Releases: codenames internally, version numbers publicly
|
|
18
|
+
|
|
19
|
+
**When to use:**
|
|
20
|
+
- Company with multiple distinct product lines
|
|
21
|
+
- Each product serves a different audience or category
|
|
22
|
+
- Company brand is strong enough to confer trust without prefix
|
|
23
|
+
|
|
24
|
+
**Naming rule:** Products need standalone strength. Features deserve names only when users will talk about them by name.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### Pattern 2: Brand-Prefix Constellation (Stripe model)
|
|
29
|
+
|
|
30
|
+
Products expand outward from core brand with compound names.
|
|
31
|
+
|
|
32
|
+
**Structure:**
|
|
33
|
+
- Core: Stripe
|
|
34
|
+
- Products: Stripe Atlas, Stripe Radar, Stripe Issuing, Stripe Treasury
|
|
35
|
+
- Features: unnamed or described within the product
|
|
36
|
+
|
|
37
|
+
**When to use:**
|
|
38
|
+
- Company with one core product and expanding platform features
|
|
39
|
+
- B2B / enterprise context where brand authority matters in sales
|
|
40
|
+
- Products that are genuinely distinct but serve the same audience
|
|
41
|
+
|
|
42
|
+
**Naming rule:** Second word should be a strong standalone word (Atlas, Radar) not a descriptor (StripeAnalytics = bad).
|
|
43
|
+
|
|
44
|
+
**Pitfall:** Prefix exhaustion. If every product is [Brand] + [word], the brand becomes noise. Limit to 5-7 products before reconsidering.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Pattern 3: Ecosystem Umbrella (Notion model)
|
|
49
|
+
|
|
50
|
+
Everything lives under one brand. Features are described, not named. Consistency over personality.
|
|
51
|
+
|
|
52
|
+
**Structure:**
|
|
53
|
+
- Core: Notion
|
|
54
|
+
- Features: Notion AI, Notion Calendar, Notion Forms — functional compounds
|
|
55
|
+
- No sub-brands or standalone product names
|
|
56
|
+
|
|
57
|
+
**When to use:**
|
|
58
|
+
- Single-product company with expanding features
|
|
59
|
+
- Audience expects consistency and predictability
|
|
60
|
+
- Brand equity is strong enough that sub-branding would dilute it
|
|
61
|
+
|
|
62
|
+
**Naming rule:** Functional clarity over brand personality at the feature level. Reserve branded names for major platform pivots.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Pattern 4: Codename Releases (macOS model)
|
|
67
|
+
|
|
68
|
+
Releases get creative codenames. Products stay clean.
|
|
69
|
+
|
|
70
|
+
**Structure:**
|
|
71
|
+
- Product: macOS
|
|
72
|
+
- Releases: Ventura, Monterey, Sonoma — geographic/thematic codenames
|
|
73
|
+
- Features: Stage Manager, Focus Mode — descriptive
|
|
74
|
+
|
|
75
|
+
**When to use:**
|
|
76
|
+
- Regular release cadence that needs narrative (annual releases, major versions)
|
|
77
|
+
- Team culture values the ritual of naming releases
|
|
78
|
+
- Audience will remember releases by name (enthusiast community)
|
|
79
|
+
|
|
80
|
+
**Naming rule:** Codenames should come from a consistent theme (Apple: California locations). Pick the theme and commit to it for 5+ releases minimum.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Pattern 5: Open Tier (GitHub / Linear model)
|
|
85
|
+
|
|
86
|
+
Minimal naming system. Brand + product descriptions. Let the work speak.
|
|
87
|
+
|
|
88
|
+
**Structure:**
|
|
89
|
+
- GitHub: Issues, Pull Requests, Actions, Copilot (the one exception — AI gets a name)
|
|
90
|
+
- Linear: Issues, Projects, Cycles, Roadmaps — all descriptive
|
|
91
|
+
|
|
92
|
+
**When to use:**
|
|
93
|
+
- Developer tools where users value precision over brand personality
|
|
94
|
+
- Products where descriptive names aid discoverability and onboarding
|
|
95
|
+
- Teams that want to ship fast without naming debates
|
|
96
|
+
|
|
97
|
+
**Naming rule:** Only name something when it's genuinely new — when no existing word captures it. Default to the best descriptive name.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Tier Definition Reference
|
|
102
|
+
|
|
103
|
+
### Product Tier
|
|
104
|
+
The highest-level named thing. Carries full brand weight.
|
|
105
|
+
- Naming intensity: HIGH — invest time here
|
|
106
|
+
- Style: invented or modified real word preferred
|
|
107
|
+
- Length: 4-8 characters ideal
|
|
108
|
+
- Domain: should own the domain
|
|
109
|
+
|
|
110
|
+
### Feature Tier
|
|
111
|
+
A capability within a product. Named only when users will refer to it by name.
|
|
112
|
+
**The question to ask:** "Will a user say 'I used [feature name] to do X' or will they say 'I used the [description] in [product]'?"
|
|
113
|
+
- Named features: Siri, AirDrop, FaceTime, Stripe Radar
|
|
114
|
+
- Unnamed features: file export, user permissions, notification settings
|
|
115
|
+
- Naming intensity: SELECTIVE — only when the feature has brand moment potential
|
|
116
|
+
- Style: can be more descriptive than product names; concept/metaphor works well
|
|
117
|
+
|
|
118
|
+
### Release Tier
|
|
119
|
+
Time-based versions. Named only if release cadence is regular and team culture supports it.
|
|
120
|
+
- Naming intensity: LOW-MEDIUM — fun but not mission-critical
|
|
121
|
+
- Style: pick a theme and commit (geography, mythology, animals, etc.)
|
|
122
|
+
- Number: always also use a version number; codenames are supplementary
|
|
123
|
+
|
|
124
|
+
### Sub-brand Tier
|
|
125
|
+
A distinct product that serves a meaningfully different audience or market.
|
|
126
|
+
- Naming intensity: HIGH — treat like a new brand
|
|
127
|
+
- Must pass the standalone test: would this name work without the parent brand?
|
|
128
|
+
- Visual identity: can deviate from parent, but should be related
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Audience-Specific Naming Conventions
|
|
133
|
+
|
|
134
|
+
**Developer audience:**
|
|
135
|
+
- Short, lowercase-friendly names work (bun, nx, vite)
|
|
136
|
+
- Technical precision valued over warmth
|
|
137
|
+
- GitHub org name as important as domain
|
|
138
|
+
- Feature names can be more technical
|
|
139
|
+
|
|
140
|
+
**Consumer audience:**
|
|
141
|
+
- Warmth and approachability required
|
|
142
|
+
- Avoid jargon, acronyms, or overly technical constructions
|
|
143
|
+
- Names should work as verbs ("I'll [name] it")
|
|
144
|
+
- Feature names should feel intuitive, not technical
|
|
145
|
+
|
|
146
|
+
**Enterprise audience:**
|
|
147
|
+
- Clarity and credibility over cleverness
|
|
148
|
+
- Avoid names that sound like consumer apps
|
|
149
|
+
- Sub-brands and product families need clear hierarchy
|
|
150
|
+
- Acronyms acceptable at enterprise scale (but risky pre-scale)
|
|
151
|
+
|
|
152
|
+
**SMB / prosumer audience:**
|
|
153
|
+
- Balance of approachability and professionalism
|
|
154
|
+
- Avoid names that are too consumer (feels unserious) or too enterprise (feels intimidating)
|
|
155
|
+
- Feature names should be self-explanatory on first encounter
|
package/validate.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const REQUIRED_FIELDS = ['name', 'description'];
|
|
9
|
+
const NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
10
|
+
const SKILLS_DIR = path.join(__dirname, 'skills');
|
|
11
|
+
|
|
12
|
+
function findSkillFiles(dir) {
|
|
13
|
+
const results = [];
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(dir)) return results;
|
|
16
|
+
|
|
17
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
18
|
+
if (!entry.isDirectory()) continue;
|
|
19
|
+
const candidate = path.join(dir, entry.name, 'SKILL.md');
|
|
20
|
+
if (fs.existsSync(candidate)) results.push(candidate);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return results;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseFrontmatter(content) {
|
|
27
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
28
|
+
if (!match) return { error: 'No YAML frontmatter found. File must start with a --- block.' };
|
|
29
|
+
|
|
30
|
+
const fields = {};
|
|
31
|
+
const lines = match[1].split('\n');
|
|
32
|
+
let i = 0;
|
|
33
|
+
|
|
34
|
+
while (i < lines.length) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
const trimmed = line.trim();
|
|
37
|
+
|
|
38
|
+
if (!trimmed || trimmed.startsWith('#')) { i++; continue; }
|
|
39
|
+
|
|
40
|
+
const colon = trimmed.indexOf(':');
|
|
41
|
+
if (colon === -1) { i++; continue; }
|
|
42
|
+
|
|
43
|
+
const key = trimmed.slice(0, colon).trim();
|
|
44
|
+
const rawValue = trimmed.slice(colon + 1).trim();
|
|
45
|
+
|
|
46
|
+
if (!key || key.includes(' ')) { i++; continue; }
|
|
47
|
+
|
|
48
|
+
// Handle block scalars (> and |)
|
|
49
|
+
if (rawValue === '>' || rawValue === '|') {
|
|
50
|
+
const blockLines = [];
|
|
51
|
+
i++;
|
|
52
|
+
while (i < lines.length && (lines[i].startsWith(' ') || lines[i].trim() === '')) {
|
|
53
|
+
blockLines.push(lines[i].trim());
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
fields[key] = blockLines.join(' ').trim();
|
|
57
|
+
} else {
|
|
58
|
+
fields[key] = rawValue.replace(/^['"]|['"]$/g, '');
|
|
59
|
+
i++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { fields };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validate(filePath) {
|
|
67
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
68
|
+
const relative = path.relative(__dirname, filePath);
|
|
69
|
+
const errors = [];
|
|
70
|
+
const warnings = [];
|
|
71
|
+
|
|
72
|
+
const { error, fields } = parseFrontmatter(content);
|
|
73
|
+
|
|
74
|
+
if (error) {
|
|
75
|
+
return { file: relative, errors: [error], warnings, valid: false };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const field of REQUIRED_FIELDS) {
|
|
79
|
+
if (!fields[field] || !fields[field].trim()) {
|
|
80
|
+
errors.push(`Missing required field: "${field}"`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (fields.name && !NAME_PATTERN.test(fields.name)) {
|
|
85
|
+
errors.push(`"name" must be lowercase alphanumeric with hyphens only (got: "${fields.name}")`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (fields.description && fields.description.length < 20) {
|
|
89
|
+
warnings.push(`"description" is very short (${fields.description.length} chars) — be more specific`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const wordCount = content.split(/\s+/).filter(Boolean).length;
|
|
93
|
+
if (wordCount < 100) {
|
|
94
|
+
warnings.push(`SKILL.md has only ${wordCount} words — skills typically need more instructions`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { file: relative, errors, warnings, valid: errors.length === 0 };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function main() {
|
|
101
|
+
const files = findSkillFiles(SKILLS_DIR);
|
|
102
|
+
|
|
103
|
+
if (files.length === 0) {
|
|
104
|
+
console.log('No SKILL.md files found in skills/');
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log(`Validating ${files.length} skill(s)...\n`);
|
|
109
|
+
|
|
110
|
+
let allValid = true;
|
|
111
|
+
|
|
112
|
+
for (const filePath of files) {
|
|
113
|
+
const result = validate(filePath);
|
|
114
|
+
const icon = result.valid ? '✓' : '✗';
|
|
115
|
+
|
|
116
|
+
console.log(`${icon} ${result.file}`);
|
|
117
|
+
|
|
118
|
+
for (const err of result.errors) {
|
|
119
|
+
console.log(` ERROR ${err}`);
|
|
120
|
+
allValid = false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const warn of result.warnings) {
|
|
124
|
+
console.log(` WARN ${warn}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (result.errors.length === 0 && result.warnings.length === 0) {
|
|
128
|
+
console.log(' All checks passed');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log('');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!allValid) {
|
|
135
|
+
console.error('Validation failed. Fix the errors above before merging.');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log('All skills valid.');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main();
|