@framers/agentos-skills-registry 0.2.0 → 0.2.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.
- package/CONTRIBUTING.md +225 -0
- package/README.md +120 -49
- package/dist/catalog.d.ts +5 -6
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +36 -206
- package/dist/catalog.js.map +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/dist/schema-types.d.ts +79 -0
- package/dist/schema-types.d.ts.map +1 -0
- package/dist/schema-types.js +11 -0
- package/dist/schema-types.js.map +1 -0
- package/dist/workspace-discovery.d.ts +84 -0
- package/dist/workspace-discovery.d.ts.map +1 -0
- package/dist/workspace-discovery.js +211 -0
- package/dist/workspace-discovery.js.map +1 -0
- package/package.json +18 -8
- package/registry/community/.gitkeep +0 -0
- package/registry/curated/1password/SKILL.md +53 -0
- package/registry/curated/account-manager/SKILL.md +60 -0
- package/registry/curated/apple-notes/SKILL.md +45 -0
- package/registry/curated/apple-reminders/SKILL.md +46 -0
- package/registry/curated/blog-publisher/SKILL.md +110 -0
- package/registry/curated/bluesky-bot/SKILL.md +93 -0
- package/registry/curated/cloud-ops/SKILL.md +124 -0
- package/registry/curated/coding-agent/SKILL.md +40 -0
- package/registry/curated/content-creator/SKILL.md +53 -0
- package/registry/curated/deep-research/SKILL.md +56 -0
- package/registry/curated/discord-helper/SKILL.md +43 -0
- package/registry/curated/facebook-bot/SKILL.md +94 -0
- package/registry/curated/git/SKILL.md +39 -0
- package/registry/curated/github/SKILL.md +54 -0
- package/registry/curated/healthcheck/SKILL.md +43 -0
- package/registry/curated/image-gen/SKILL.md +44 -0
- package/registry/curated/instagram-bot/SKILL.md +60 -0
- package/registry/curated/linkedin-bot/SKILL.md +86 -0
- package/registry/curated/mastodon-bot/SKILL.md +104 -0
- package/registry/curated/notion/SKILL.md +43 -0
- package/registry/curated/obsidian/SKILL.md +42 -0
- package/registry/curated/pinterest-bot/SKILL.md +45 -0
- package/registry/curated/reddit-bot/SKILL.md +62 -0
- package/registry/curated/seo-campaign/SKILL.md +51 -0
- package/registry/curated/site-deploy/SKILL.md +119 -0
- package/registry/curated/slack-helper/SKILL.md +43 -0
- package/registry/curated/social-broadcast/SKILL.md +145 -0
- package/registry/curated/spotify-player/SKILL.md +45 -0
- package/registry/curated/summarize/SKILL.md +40 -0
- package/registry/curated/threads-bot/SKILL.md +82 -0
- package/registry/curated/tiktok-bot/SKILL.md +104 -0
- package/registry/curated/trello/SKILL.md +44 -0
- package/registry/curated/twitter-bot/SKILL.md +63 -0
- package/registry/curated/weather/SKILL.md +37 -0
- package/registry/curated/web-scraper/SKILL.md +60 -0
- package/registry/curated/web-search/SKILL.md +49 -0
- package/registry/curated/whisper-transcribe/SKILL.md +58 -0
- package/registry/curated/youtube-bot/SKILL.md +104 -0
- package/registry.json +1426 -0
- package/scripts/update-registry.mjs +126 -0
- package/scripts/validate-skill.mjs +298 -0
- package/types.d.ts +77 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cross-Agent Skill Discovery (Feature 3.5)
|
|
3
|
+
*
|
|
4
|
+
* Discovers SKILL.md files from a workspace `.agents/skills/` directory,
|
|
5
|
+
* parses their YAML frontmatter, and returns them as SkillCatalogEntry[]
|
|
6
|
+
* compatible with the existing registry catalog.
|
|
7
|
+
*
|
|
8
|
+
* Workspace skills take priority over registry skills when names collide.
|
|
9
|
+
*
|
|
10
|
+
* @module @framers/agentos-skills-registry/workspace-discovery
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs/promises';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
// ── Frontmatter parser ──────────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Lightweight YAML frontmatter parser.
|
|
17
|
+
*
|
|
18
|
+
* Handles the subset of YAML used in SKILL.md frontmatter:
|
|
19
|
+
* - scalar key: value pairs
|
|
20
|
+
* - inline arrays [a, b, c]
|
|
21
|
+
* - block arrays (- item)
|
|
22
|
+
*
|
|
23
|
+
* Does NOT pull in a full YAML dependency — keeps the package lightweight.
|
|
24
|
+
*/
|
|
25
|
+
export function parseSkillFrontmatter(content) {
|
|
26
|
+
// Extract frontmatter block between leading --- fences
|
|
27
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
28
|
+
if (!match)
|
|
29
|
+
return null;
|
|
30
|
+
const block = match[1];
|
|
31
|
+
const result = {};
|
|
32
|
+
const lines = block.split('\n');
|
|
33
|
+
let i = 0;
|
|
34
|
+
while (i < lines.length) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
// Skip blank lines and deep-nested keys (metadata sub-objects)
|
|
37
|
+
if (!line.trim() || /^\s{2,}\S/.test(line)) {
|
|
38
|
+
i++;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const kvMatch = line.match(/^(\w[\w_-]*)\s*:\s*(.*)/);
|
|
42
|
+
if (!kvMatch) {
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const key = kvMatch[1];
|
|
47
|
+
let rawValue = kvMatch[2].trim();
|
|
48
|
+
// Inline array: [a, b, c]
|
|
49
|
+
if (rawValue.startsWith('[') && rawValue.endsWith(']')) {
|
|
50
|
+
const inner = rawValue.slice(1, -1);
|
|
51
|
+
result[key] = inner
|
|
52
|
+
? inner.split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''))
|
|
53
|
+
: [];
|
|
54
|
+
i++;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Block array: subsequent lines starting with "- "
|
|
58
|
+
if (rawValue === '' || rawValue === '[]') {
|
|
59
|
+
const items = [];
|
|
60
|
+
let j = i + 1;
|
|
61
|
+
while (j < lines.length) {
|
|
62
|
+
const next = lines[j];
|
|
63
|
+
const itemMatch = next.match(/^\s+-\s+(.*)/);
|
|
64
|
+
if (!itemMatch)
|
|
65
|
+
break;
|
|
66
|
+
items.push(itemMatch[1].trim().replace(/^['"]|['"]$/g, ''));
|
|
67
|
+
j++;
|
|
68
|
+
}
|
|
69
|
+
if (items.length > 0) {
|
|
70
|
+
result[key] = items;
|
|
71
|
+
i = j;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// Empty array literal
|
|
75
|
+
if (rawValue === '[]') {
|
|
76
|
+
result[key] = [];
|
|
77
|
+
i++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Scalar value — strip surrounding quotes
|
|
82
|
+
result[key] = rawValue.replace(/^['"]|['"]$/g, '');
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
// name is required
|
|
86
|
+
if (typeof result.name !== 'string' || !result.name)
|
|
87
|
+
return null;
|
|
88
|
+
return {
|
|
89
|
+
name: result.name,
|
|
90
|
+
version: result.version ?? undefined,
|
|
91
|
+
description: result.description ?? undefined,
|
|
92
|
+
category: result.category ?? undefined,
|
|
93
|
+
tags: Array.isArray(result.tags) ? result.tags : undefined,
|
|
94
|
+
author: result.author ?? undefined,
|
|
95
|
+
namespace: result.namespace ?? undefined,
|
|
96
|
+
requires_secrets: Array.isArray(result.requires_secrets)
|
|
97
|
+
? result.requires_secrets
|
|
98
|
+
: undefined,
|
|
99
|
+
requires_tools: Array.isArray(result.requires_tools)
|
|
100
|
+
? result.requires_tools
|
|
101
|
+
: undefined,
|
|
102
|
+
metadata: result.metadata ?? undefined,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// ── Skill discovery ─────────────────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Convert parsed frontmatter + filesystem path into a SkillCatalogEntry.
|
|
108
|
+
*/
|
|
109
|
+
function frontmatterToEntry(fm, skillPath) {
|
|
110
|
+
return {
|
|
111
|
+
name: fm.name,
|
|
112
|
+
displayName: fm.name
|
|
113
|
+
.split('-')
|
|
114
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
115
|
+
.join(' '),
|
|
116
|
+
description: fm.description ?? '',
|
|
117
|
+
category: fm.category ?? 'workspace',
|
|
118
|
+
tags: fm.tags ?? [],
|
|
119
|
+
requiredSecrets: fm.requires_secrets ?? [],
|
|
120
|
+
requiredTools: fm.requires_tools ?? [],
|
|
121
|
+
skillPath,
|
|
122
|
+
source: 'community',
|
|
123
|
+
namespace: 'wunderland',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Discover SKILL.md files from a workspace directory.
|
|
128
|
+
*
|
|
129
|
+
* Scans `<skillsDir>/` for sub-directories containing a SKILL.md file,
|
|
130
|
+
* parses the YAML frontmatter, and returns the discovered skills as
|
|
131
|
+
* SkillCatalogEntry[] compatible with the existing catalog.
|
|
132
|
+
*
|
|
133
|
+
* If the directory does not exist, returns an empty array.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { discoverWorkspaceSkills } from '@framers/agentos-skills-registry';
|
|
138
|
+
*
|
|
139
|
+
* // Uses default .agents/skills/ in cwd
|
|
140
|
+
* const skills = await discoverWorkspaceSkills();
|
|
141
|
+
*
|
|
142
|
+
* // Custom path
|
|
143
|
+
* const skills2 = await discoverWorkspaceSkills({
|
|
144
|
+
* skillsDir: '/my/project/.agents/skills',
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export async function discoverWorkspaceSkills(options) {
|
|
149
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
150
|
+
const skillsDir = options?.skillsDir
|
|
151
|
+
? path.resolve(cwd, options.skillsDir)
|
|
152
|
+
: path.resolve(cwd, '.agents', 'skills');
|
|
153
|
+
// If directory doesn't exist, return empty array
|
|
154
|
+
let entries;
|
|
155
|
+
try {
|
|
156
|
+
entries = await fs.readdir(skillsDir);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
const discovered = [];
|
|
162
|
+
for (const entry of entries) {
|
|
163
|
+
const entryPath = path.join(skillsDir, entry);
|
|
164
|
+
// Only scan directories
|
|
165
|
+
let stat;
|
|
166
|
+
try {
|
|
167
|
+
stat = await fs.stat(entryPath);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (!stat.isDirectory())
|
|
173
|
+
continue;
|
|
174
|
+
// Look for SKILL.md inside the directory
|
|
175
|
+
const skillMdPath = path.join(entryPath, 'SKILL.md');
|
|
176
|
+
let content;
|
|
177
|
+
try {
|
|
178
|
+
content = await fs.readFile(skillMdPath, 'utf-8');
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const frontmatter = parseSkillFrontmatter(content);
|
|
184
|
+
if (!frontmatter)
|
|
185
|
+
continue;
|
|
186
|
+
// Use relative path from skillsDir for the skillPath
|
|
187
|
+
const relativePath = path.relative(skillsDir, skillMdPath);
|
|
188
|
+
discovered.push(frontmatterToEntry(frontmatter, relativePath));
|
|
189
|
+
}
|
|
190
|
+
return discovered;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Merge workspace-discovered skills with the registry catalog.
|
|
194
|
+
*
|
|
195
|
+
* Workspace skills take priority: if a workspace skill has the same `name`
|
|
196
|
+
* as a registry skill, the workspace version replaces the registry one.
|
|
197
|
+
*
|
|
198
|
+
* @param registrySkills - Skills from the built-in catalog (SKILLS_CATALOG)
|
|
199
|
+
* @param workspaceSkills - Skills discovered from the workspace directory
|
|
200
|
+
* @returns Merged array with workspace overrides applied
|
|
201
|
+
*/
|
|
202
|
+
export function mergeWithWorkspaceSkills(registrySkills, workspaceSkills) {
|
|
203
|
+
if (workspaceSkills.length === 0)
|
|
204
|
+
return registrySkills;
|
|
205
|
+
const workspaceNames = new Set(workspaceSkills.map((s) => s.name));
|
|
206
|
+
// Filter out registry skills that are overridden by workspace skills
|
|
207
|
+
const filtered = registrySkills.filter((s) => !workspaceNames.has(s.name));
|
|
208
|
+
// Workspace skills come first (higher priority), then remaining registry skills
|
|
209
|
+
return [...workspaceSkills, ...filtered];
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=workspace-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-discovery.js","sourceRoot":"","sources":["../src/workspace-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAkClC,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,uDAAuD;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,+DAA+D;QAC/D,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEjC,0BAA0B;QAC1B,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;gBACjB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;gBACnE,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QAED,mDAAmD;QACnD,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBAC7C,IAAI,CAAC,SAAS;oBAAE,MAAM;gBACtB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC5D,CAAC,EAAE,CAAC;YACN,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACpB,CAAC,GAAG,CAAC,CAAC;gBACN,SAAS;YACX,CAAC;YACD,sBAAsB;YACtB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;gBACjB,CAAC,EAAE,CAAC;gBACJ,SAAS;YACX,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACnD,CAAC,EAAE,CAAC;IACN,CAAC;IAED,mBAAmB;IACnB,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAc;QAC3B,OAAO,EAAG,MAAM,CAAC,OAAkB,IAAI,SAAS;QAChD,WAAW,EAAG,MAAM,CAAC,WAAsB,IAAI,SAAS;QACxD,QAAQ,EAAG,MAAM,CAAC,QAAmB,IAAI,SAAS;QAClD,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,MAAM,CAAC,IAAiB,CAAC,CAAC,CAAC,SAAS;QACxE,MAAM,EAAG,MAAM,CAAC,MAAiB,IAAI,SAAS;QAC9C,SAAS,EAAG,MAAM,CAAC,SAAoB,IAAI,SAAS;QACpD,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC;YACtD,CAAC,CAAE,MAAM,CAAC,gBAA6B;YACvC,CAAC,CAAC,SAAS;QACb,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;YAClD,CAAC,CAAE,MAAM,CAAC,cAA2B;YACrC,CAAC,CAAC,SAAS;QACb,QAAQ,EAAG,MAAM,CAAC,QAAoC,IAAI,SAAS;KACpE,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E;;GAEG;AACH,SAAS,kBAAkB,CAAC,EAAoB,EAAE,SAAiB;IACjE,OAAO;QACL,IAAI,EAAE,EAAE,CAAC,IAAI;QACb,WAAW,EAAE,EAAE,CAAC,IAAI;aACjB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aAClD,IAAI,CAAC,GAAG,CAAC;QACZ,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE;QACjC,QAAQ,EAAE,EAAE,CAAC,QAAQ,IAAI,WAAW;QACpC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE;QACnB,eAAe,EAAE,EAAE,CAAC,gBAAgB,IAAI,EAAE;QAC1C,aAAa,EAAE,EAAE,CAAC,cAAc,IAAI,EAAE;QACtC,SAAS;QACT,MAAM,EAAE,WAAoB;QAC5B,SAAS,EAAE,YAAY;KACxB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAmC;IAEnC,MAAM,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS;QAClC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC;QACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAE3C,iDAAiD;IACjD,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAE9C,wBAAwB;QACxB,IAAI,IAAI,CAAC;QACT,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,SAAS;QAElC,yCAAyC;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACrD,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,WAAW;YAAE,SAAS;QAE3B,qDAAqD;QACrD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC3D,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,cAAmC,EACnC,eAAoC;IAEpC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,cAAc,CAAC;IAExD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEnE,qEAAqE;IACrE,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE3E,gFAAgF;IAChF,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@framers/agentos-skills-registry",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
|
+
"registry",
|
|
7
|
+
"registry.json",
|
|
8
|
+
"types.d.ts",
|
|
9
|
+
"scripts",
|
|
10
|
+
"CONTRIBUTING.md",
|
|
6
11
|
"README.md"
|
|
7
12
|
],
|
|
8
|
-
"description": "Curated skills registry
|
|
13
|
+
"description": "Curated skills registry for AgentOS \u2014 SKILL.md prompt modules, typed catalog, and lazy-loading factories",
|
|
9
14
|
"type": "module",
|
|
10
15
|
"sideEffects": false,
|
|
11
16
|
"main": "./dist/index.js",
|
|
@@ -19,11 +24,19 @@
|
|
|
19
24
|
"import": "./dist/catalog.js",
|
|
20
25
|
"types": "./dist/catalog.d.ts"
|
|
21
26
|
},
|
|
27
|
+
"./workspace-discovery": {
|
|
28
|
+
"import": "./dist/workspace-discovery.js",
|
|
29
|
+
"types": "./dist/workspace-discovery.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./registry.json": "./registry.json",
|
|
32
|
+
"./types": "./types.d.ts",
|
|
22
33
|
"./package.json": "./package.json"
|
|
23
34
|
},
|
|
24
35
|
"scripts": {
|
|
25
36
|
"build": "tsc",
|
|
26
37
|
"clean": "rm -rf dist",
|
|
38
|
+
"validate": "node scripts/validate-skill.mjs",
|
|
39
|
+
"update:registry": "node scripts/update-registry.mjs",
|
|
27
40
|
"prepublishOnly": "npm run build",
|
|
28
41
|
"test": "vitest run"
|
|
29
42
|
},
|
|
@@ -49,9 +62,6 @@
|
|
|
49
62
|
"publishConfig": {
|
|
50
63
|
"access": "public"
|
|
51
64
|
},
|
|
52
|
-
"dependencies": {
|
|
53
|
-
"@framers/agentos-skills": "^0.1.0"
|
|
54
|
-
},
|
|
55
65
|
"peerDependencies": {
|
|
56
66
|
"@framers/agentos": ">=0.1.0"
|
|
57
67
|
},
|
|
@@ -62,9 +72,9 @@
|
|
|
62
72
|
},
|
|
63
73
|
"devDependencies": {
|
|
64
74
|
"@framers/agentos": "workspace:*",
|
|
65
|
-
"@framers/agentos-skills": "workspace:*",
|
|
66
75
|
"@types/node": "^20.12.12",
|
|
67
76
|
"typescript": "^5.4.5",
|
|
68
|
-
"vitest": "^1.0.0"
|
|
77
|
+
"vitest": "^1.0.0",
|
|
78
|
+
"yaml": "^2.8.1"
|
|
69
79
|
}
|
|
70
|
-
}
|
|
80
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 1password
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: Query and retrieve items from 1Password vaults using the 1Password CLI for secure credential access.
|
|
5
|
+
author: Wunderland
|
|
6
|
+
namespace: wunderland
|
|
7
|
+
category: security
|
|
8
|
+
tags: [1password, passwords, secrets, vault, credentials, security]
|
|
9
|
+
requires_secrets: [1password.service_account_token]
|
|
10
|
+
requires_tools: []
|
|
11
|
+
metadata:
|
|
12
|
+
agentos:
|
|
13
|
+
emoji: "\U0001F510"
|
|
14
|
+
primaryEnv: OP_SERVICE_ACCOUNT_TOKEN
|
|
15
|
+
homepage: https://developer.1password.com/docs/cli
|
|
16
|
+
requires:
|
|
17
|
+
bins: ['op']
|
|
18
|
+
install:
|
|
19
|
+
- id: brew
|
|
20
|
+
kind: brew
|
|
21
|
+
formula: 1password-cli
|
|
22
|
+
bins: ['op']
|
|
23
|
+
label: 'Install 1Password CLI (brew)'
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# 1Password Vault Queries
|
|
27
|
+
|
|
28
|
+
You can query 1Password vaults to retrieve credentials, secure notes, API keys, and other secrets using the `op` CLI. This enables secure access to stored credentials without hardcoding secrets in code or configuration files.
|
|
29
|
+
|
|
30
|
+
When retrieving items, use `op item get` with the item name or UUID. Support querying specific fields (username, password, TOTP, custom fields) using the `--fields` flag. For listing items, filter by vault, category (login, secure-note, api-credential, credit-card), or tags. Always use the most specific identifier available to avoid ambiguous matches.
|
|
31
|
+
|
|
32
|
+
For security, never display full passwords or secret values in plain text unless the user explicitly requests it. Instead, confirm the item exists and describe its metadata (title, vault, category, last modified). When injecting secrets into environment variables or configuration files, use `op run` or `op inject` for ephemeral secret injection that avoids writing secrets to disk.
|
|
33
|
+
|
|
34
|
+
Support common workflows like looking up API keys for service integrations, retrieving database credentials for connection strings, and checking TOTP codes for two-factor authentication. When multiple items match a query, present a disambiguated list with vault and category context so the user can select the correct one.
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
- "Look up the API key for our Stripe integration"
|
|
39
|
+
- "What vaults do I have access to?"
|
|
40
|
+
- "Get the database connection credentials from the Production vault"
|
|
41
|
+
- "Generate a TOTP code for my AWS account"
|
|
42
|
+
- "List all items tagged 'deploy' in the DevOps vault"
|
|
43
|
+
- "Inject secrets from the 'staging-env' item into environment variables"
|
|
44
|
+
|
|
45
|
+
## Constraints
|
|
46
|
+
|
|
47
|
+
- Requires the `op` CLI to be installed and authenticated (service account token or interactive sign-in).
|
|
48
|
+
- The agent can only access vaults and items that the authenticated account has permissions for.
|
|
49
|
+
- Biometric unlock is not available in non-interactive CLI sessions; use service account tokens.
|
|
50
|
+
- TOTP codes are time-sensitive and expire every 30 seconds.
|
|
51
|
+
- Cannot create, modify, or delete vault items -- read-only access for security.
|
|
52
|
+
- Session tokens expire after 30 minutes of inactivity by default.
|
|
53
|
+
- Do not log, cache, or persist retrieved secret values beyond the immediate use.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: account-manager
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: Social account management — registration flows, profile optimization, credential storage, multi-platform account orchestration.
|
|
5
|
+
author: Wunderland
|
|
6
|
+
namespace: wunderland
|
|
7
|
+
category: automation
|
|
8
|
+
tags: [accounts, credentials, registration, profiles, management, automation]
|
|
9
|
+
requires_secrets: []
|
|
10
|
+
requires_tools: [credentialsSet, credentialsGet, credentialsList, credentialsImport, browserNavigate, browserClick, browserFill, browserScreenshot, browserSnapshot, browserSession]
|
|
11
|
+
metadata:
|
|
12
|
+
agentos:
|
|
13
|
+
emoji: "\U0001F511"
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Account Manager
|
|
17
|
+
|
|
18
|
+
You are a social account management agent. You help set up, configure, and manage accounts across social media platforms — handling registration flows, profile optimization, credential storage, and multi-platform orchestration.
|
|
19
|
+
|
|
20
|
+
## Core Capabilities
|
|
21
|
+
|
|
22
|
+
- **Account registration** — automate sign-up flows via browser automation
|
|
23
|
+
- **Profile optimization** — complete bios, profile pictures, settings
|
|
24
|
+
- **Credential management** — securely store and retrieve API keys and tokens
|
|
25
|
+
- **Multi-platform** — manage accounts across Twitter, Instagram, Reddit, Pinterest, TikTok, YouTube
|
|
26
|
+
- **Session management** — save and restore login sessions
|
|
27
|
+
- **Credential import** — bulk import from JSON or CSV files
|
|
28
|
+
|
|
29
|
+
## Account Setup Workflow
|
|
30
|
+
|
|
31
|
+
1. **Navigate** to the platform's sign-up page
|
|
32
|
+
2. **Fill registration form** with provided details
|
|
33
|
+
3. **Handle verification** — email/phone verification codes
|
|
34
|
+
4. **Complete profile** — bio, avatar, settings
|
|
35
|
+
5. **Store credentials** securely in the credential vault
|
|
36
|
+
6. **Save session** for future use without re-authentication
|
|
37
|
+
|
|
38
|
+
## Credential Management
|
|
39
|
+
|
|
40
|
+
- Use `credentialsSet` to store platform API keys and tokens
|
|
41
|
+
- Use `credentialsGet` to retrieve credentials when needed
|
|
42
|
+
- Use `credentialsList` to audit stored credentials
|
|
43
|
+
- Use `credentialsImport` for bulk setup from CSV/JSON
|
|
44
|
+
- All credentials are encrypted at rest
|
|
45
|
+
|
|
46
|
+
## Profile Optimization Tips
|
|
47
|
+
|
|
48
|
+
- **Bio**: Clear description of purpose, include relevant keywords
|
|
49
|
+
- **Avatar**: Consistent branding across platforms
|
|
50
|
+
- **Links**: Cross-link between platforms
|
|
51
|
+
- **Settings**: Enable API access, set appropriate privacy levels
|
|
52
|
+
- **Verification**: Complete platform-specific verification steps
|
|
53
|
+
|
|
54
|
+
## Safety
|
|
55
|
+
|
|
56
|
+
- Never store plaintext passwords in logs or outputs
|
|
57
|
+
- Always use the credential vault for sensitive data
|
|
58
|
+
- Verify account ownership before making changes
|
|
59
|
+
- Respect platform terms of service
|
|
60
|
+
- Use unique, strong passwords for each platform
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apple-notes
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: Create, read, search, and manage notes in Apple Notes using AppleScript and macOS automation.
|
|
5
|
+
author: Wunderland
|
|
6
|
+
namespace: wunderland
|
|
7
|
+
category: productivity
|
|
8
|
+
tags: [apple-notes, macos, notes, applescript, automation]
|
|
9
|
+
requires_secrets: []
|
|
10
|
+
requires_tools: [filesystem]
|
|
11
|
+
metadata:
|
|
12
|
+
agentos:
|
|
13
|
+
emoji: "\U0001F4F1"
|
|
14
|
+
os: ['darwin']
|
|
15
|
+
requires:
|
|
16
|
+
bins: ['osascript']
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Apple Notes Integration
|
|
20
|
+
|
|
21
|
+
You can create, read, search, and manage notes in Apple Notes on macOS using AppleScript commands executed via `osascript`. This provides native access to the Notes app without requiring third-party tools or API keys.
|
|
22
|
+
|
|
23
|
+
When creating notes, use `osascript` to invoke AppleScript that creates note entries with title and body text. Notes support basic HTML formatting for bold, italic, lists, and headings. Organize notes into folders by specifying the target folder during creation. If a folder does not exist, create it first before adding notes to it.
|
|
24
|
+
|
|
25
|
+
For reading and searching notes, query the Notes app for notes matching specific titles, body content, or folder locations. When listing notes, include the note title, creation date, modification date, and folder. For search operations, match against both title and body text. Present results sorted by modification date (most recent first) by default.
|
|
26
|
+
|
|
27
|
+
When modifying existing notes, append content to the end of the note body unless the user specifies a different location. Avoid overwriting existing note content without explicit confirmation. Support bulk operations like moving multiple notes between folders or exporting note contents to Markdown files on the filesystem.
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
- "Create a new note titled 'Meeting Notes - Feb 7' in my Work folder"
|
|
32
|
+
- "Search my notes for anything about 'quarterly review'"
|
|
33
|
+
- "List all notes in the Ideas folder sorted by date"
|
|
34
|
+
- "Append today's action items to my 'Running Tasks' note"
|
|
35
|
+
- "Export all notes from the Research folder to Markdown files"
|
|
36
|
+
|
|
37
|
+
## Constraints
|
|
38
|
+
|
|
39
|
+
- macOS only -- requires the Apple Notes app and `osascript` binary.
|
|
40
|
+
- AppleScript access to Notes may require accessibility permissions to be granted.
|
|
41
|
+
- Rich formatting is limited to basic HTML supported by Notes (bold, italic, lists, links).
|
|
42
|
+
- Embedded images and attachments in notes cannot be read or created via AppleScript.
|
|
43
|
+
- iCloud-synced notes are accessible but sync timing is controlled by the system.
|
|
44
|
+
- Large notes (100KB+) may experience slow AppleScript operations.
|
|
45
|
+
- Notes in locked/password-protected folders cannot be accessed via automation.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apple-reminders
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: Create, manage, and query reminders and lists in Apple Reminders using AppleScript and macOS automation.
|
|
5
|
+
author: Wunderland
|
|
6
|
+
namespace: wunderland
|
|
7
|
+
category: productivity
|
|
8
|
+
tags: [apple-reminders, macos, reminders, tasks, applescript, automation]
|
|
9
|
+
requires_secrets: []
|
|
10
|
+
requires_tools: [filesystem]
|
|
11
|
+
metadata:
|
|
12
|
+
agentos:
|
|
13
|
+
emoji: "\u2705"
|
|
14
|
+
os: ['darwin']
|
|
15
|
+
requires:
|
|
16
|
+
bins: ['osascript']
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Apple Reminders Integration
|
|
20
|
+
|
|
21
|
+
You can create, manage, complete, and query reminders in Apple Reminders on macOS using AppleScript commands executed via `osascript`. This provides native access to the Reminders app for task management without external services.
|
|
22
|
+
|
|
23
|
+
When creating reminders, specify the title, due date, priority (0=none, 1-4=high, 5=medium, 6-9=low), and target list. If the user does not specify a list, use the default reminders list. Support creating reminders with notes/body text for additional context. For recurring reminders, set the recurrence rule (daily, weekly, monthly) when supported.
|
|
24
|
+
|
|
25
|
+
For querying reminders, list items by list name, completion status, due date range, or priority level. Present results in a clear format showing title, due date, priority, and completion status. Support filtering incomplete reminders that are overdue. When showing upcoming reminders, sort by due date ascending.
|
|
26
|
+
|
|
27
|
+
When managing reminders, support completing items (marking as done), updating due dates, changing priorities, moving between lists, and deleting items. For bulk operations, process items efficiently and report results. Create new reminder lists when the user requests organizing tasks into new categories.
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
- "Create a reminder to 'Call dentist' tomorrow at 2pm in my Personal list"
|
|
32
|
+
- "Show me all overdue reminders"
|
|
33
|
+
- "Mark the 'Submit report' reminder as complete"
|
|
34
|
+
- "List all reminders due this week sorted by priority"
|
|
35
|
+
- "Create a new list called 'Home Renovation' and add 5 tasks to it"
|
|
36
|
+
- "Move all high-priority reminders from Inbox to the Urgent list"
|
|
37
|
+
|
|
38
|
+
## Constraints
|
|
39
|
+
|
|
40
|
+
- macOS only -- requires the Apple Reminders app and `osascript` binary.
|
|
41
|
+
- AppleScript access to Reminders may require accessibility permissions.
|
|
42
|
+
- Location-based reminders cannot be created via AppleScript.
|
|
43
|
+
- Sub-tasks (nested reminders) have limited AppleScript support.
|
|
44
|
+
- iCloud-synced reminders are accessible but sync timing is system-controlled.
|
|
45
|
+
- Attachments and images on reminders cannot be managed via automation.
|
|
46
|
+
- Completed reminders may be automatically hidden based on the user's Reminders app settings.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blog-publisher
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: Blog publishing automation — long-form content creation, SEO optimization, cross-posting with canonical URLs, and multi-platform distribution.
|
|
5
|
+
author: Wunderland
|
|
6
|
+
namespace: wunderland
|
|
7
|
+
category: social-automation
|
|
8
|
+
tags: [blog, publishing, long-form, seo, cross-posting, dev-to, hashnode, medium, wordpress, automation]
|
|
9
|
+
requires_secrets: [blog.devtoApiKey, blog.hashnodeToken, blog.mediumToken, blog.wordpressUrl, blog.wordpressToken]
|
|
10
|
+
requires_tools: [blogPublishArticle, blogUpdateArticle, blogListArticles, blogAnalytics, blogSchedule, blogCrossPost]
|
|
11
|
+
metadata:
|
|
12
|
+
agentos:
|
|
13
|
+
emoji: "\u270D\uFE0F"
|
|
14
|
+
primaryEnv: BLOG_DEVTO_API_KEY
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Blog Publisher
|
|
18
|
+
|
|
19
|
+
You are an autonomous blog publishing agent. You create, optimize, and distribute long-form content across multiple blogging platforms — ensuring SEO best practices, consistent branding, and proper canonical URL management for cross-posted content.
|
|
20
|
+
|
|
21
|
+
## Core Capabilities
|
|
22
|
+
|
|
23
|
+
- **Publish articles** — create and publish blog posts on Dev.to, Hashnode, Medium, and WordPress
|
|
24
|
+
- **Update articles** — edit published content across platforms
|
|
25
|
+
- **List articles** — view your published content and drafts
|
|
26
|
+
- **Cross-post** — distribute a single article across multiple platforms with canonical URLs via `blogCrossPost`
|
|
27
|
+
- **Schedule** — plan articles for future publication
|
|
28
|
+
- **Analytics** — track views, reads, reactions, and comments per platform
|
|
29
|
+
|
|
30
|
+
## Supported Platforms
|
|
31
|
+
|
|
32
|
+
### Dev.to
|
|
33
|
+
- **Audience**: Developer community
|
|
34
|
+
- **Strengths**: Tags-based discovery, strong community engagement, markdown native
|
|
35
|
+
- **Limits**: 4 tags per article, markdown format only
|
|
36
|
+
- **Best for**: Technical tutorials, dev tools, open-source, career advice
|
|
37
|
+
|
|
38
|
+
### Hashnode
|
|
39
|
+
- **Audience**: Developer blogs and personal branding
|
|
40
|
+
- **Strengths**: Custom domain support, newsletter integration, markdown native
|
|
41
|
+
- **Limits**: Tag-based discovery, publication support
|
|
42
|
+
- **Best for**: Personal developer blogs, deep technical dives, series
|
|
43
|
+
|
|
44
|
+
### Medium
|
|
45
|
+
- **Audience**: General audience, tech and non-tech
|
|
46
|
+
- **Strengths**: Built-in audience, curation, publications
|
|
47
|
+
- **Limits**: Paywall affects reach, 5 tags per article
|
|
48
|
+
- **Best for**: Thought leadership, general tech, startup stories, design
|
|
49
|
+
|
|
50
|
+
### WordPress
|
|
51
|
+
- **Audience**: Self-hosted, full control
|
|
52
|
+
- **Strengths**: Complete customization, SEO plugins, no platform risk
|
|
53
|
+
- **Limits**: Requires hosting and maintenance
|
|
54
|
+
- **Best for**: Canonical source of truth, company blogs, landing pages
|
|
55
|
+
|
|
56
|
+
## Publishing Strategy
|
|
57
|
+
|
|
58
|
+
1. **Write once, publish everywhere** — create content once, then cross-post
|
|
59
|
+
2. **Set canonical URLs** — always point to your primary platform to avoid SEO penalties
|
|
60
|
+
3. **Publish on primary platform first** — wait 24-48 hours before cross-posting
|
|
61
|
+
4. **Optimize for SEO** — keyword research, meta descriptions, structured headings
|
|
62
|
+
5. **Consistent schedule** — publish 1-2 articles per week for steady growth
|
|
63
|
+
6. **Repurpose content** — turn articles into threads, carousels, and video scripts
|
|
64
|
+
|
|
65
|
+
## Content Guidelines
|
|
66
|
+
|
|
67
|
+
- **Title**: Clear, keyword-rich, under 60 characters for SEO
|
|
68
|
+
- **Introduction**: Hook the reader in the first 2-3 sentences
|
|
69
|
+
- **Structure**: Use H2/H3 headings, bullet points, code blocks, and images
|
|
70
|
+
- **Length**: 800-2000 words for optimal engagement and SEO
|
|
71
|
+
- **Cover image**: Include a high-quality cover image (1200x630px recommended)
|
|
72
|
+
- **Tags**: Use 4-6 relevant tags per platform
|
|
73
|
+
- **Call-to-action**: End with a clear next step (follow, subscribe, comment)
|
|
74
|
+
|
|
75
|
+
## SEO Best Practices
|
|
76
|
+
|
|
77
|
+
- **Keyword research** — target one primary keyword per article
|
|
78
|
+
- **Title tag** — include primary keyword near the beginning
|
|
79
|
+
- **Meta description** — compelling summary under 160 characters
|
|
80
|
+
- **Headings** — use H2/H3 hierarchy with keywords naturally included
|
|
81
|
+
- **Internal linking** — link to your other relevant articles
|
|
82
|
+
- **External linking** — cite authoritative sources
|
|
83
|
+
- **Alt text** — describe all images for accessibility and SEO
|
|
84
|
+
- **URL slug** — short, descriptive, keyword-rich
|
|
85
|
+
|
|
86
|
+
## Cross-Posting Rules
|
|
87
|
+
|
|
88
|
+
- **Always set canonical URL** — prevents duplicate content penalties
|
|
89
|
+
- **Primary platform first** — publish on your canonical source before cross-posting
|
|
90
|
+
- **Adapt formatting** — each platform has slightly different markdown support
|
|
91
|
+
- **Update cross-posts** — when you update the original, update cross-posts too
|
|
92
|
+
- **Track per-platform performance** — know where your audience engages most
|
|
93
|
+
|
|
94
|
+
## Safety Limits
|
|
95
|
+
|
|
96
|
+
- Maximum 2 articles per day across all platforms
|
|
97
|
+
- Always set canonical URL when cross-posting
|
|
98
|
+
- Don't publish identical content without canonical — search engines penalize this
|
|
99
|
+
- Respect each platform's Terms of Service
|
|
100
|
+
- Don't spam tags or use irrelevant tags for discovery
|
|
101
|
+
- Proofread and fact-check before publishing
|
|
102
|
+
|
|
103
|
+
## Workflow
|
|
104
|
+
|
|
105
|
+
1. **Plan** — Research topics, keywords, and audience interest
|
|
106
|
+
2. **Write** — Create well-structured, SEO-optimized content
|
|
107
|
+
3. **Publish** — Post to your primary platform first
|
|
108
|
+
4. **Cross-post** — Distribute to secondary platforms with canonical URLs
|
|
109
|
+
5. **Promote** — Share on social channels (use social-broadcast skill)
|
|
110
|
+
6. **Analyze** — Review per-platform performance and adjust strategy
|