open source is social v-it.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add org.v-it.skill lexicon, skill-ref validation, make vouch beacon optional

New lexicon for agent skills as first-class ATProto records alongside caps.
Vouch beacon removed from required array (skills have no beacon).
SKILL_COLLECTION constant and ref validation for skill-{name} format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+188 -4
+146
lexicons/org/v-it/skill.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "org.v-it.skill", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "Record containing an agent skill published over ATProto. Follows the Agent Skills open standard (agentskills.io).", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["name", "description", "text", "createdAt"], 12 + "properties": { 13 + "name": { 14 + "type": "string", 15 + "maxLength": 256, 16 + "maxGraphemes": 64, 17 + "description": "Skill name. Becomes the /slash-command. Lowercase letters, numbers, hyphens only. No leading hyphen, no consecutive hyphens." 18 + }, 19 + "description": { 20 + "type": "string", 21 + "maxLength": 10000, 22 + "maxGraphemes": 1024, 23 + "description": "What this skill does and when to use it. Agents use this for automatic activation matching." 24 + }, 25 + "text": { 26 + "type": "string", 27 + "maxLength": 50000, 28 + "maxGraphemes": 15000, 29 + "description": "The complete SKILL.md file content — frontmatter and body, verbatim. This is the source of truth. On learn, this is written directly as SKILL.md with no reconstruction. The other fields (name, description, version, license, compatibility) are copies extracted for discovery and indexing." 30 + }, 31 + "version": { 32 + "type": "string", 33 + "maxLength": 64, 34 + "maxGraphemes": 32, 35 + "description": "Semantic version string (e.g. 1.0.0). Author-declared." 36 + }, 37 + "license": { 38 + "type": "string", 39 + "maxLength": 256, 40 + "maxGraphemes": 64, 41 + "description": "SPDX license identifier (e.g. MIT, CC-BY-4.0)." 42 + }, 43 + "compatibility": { 44 + "type": "string", 45 + "maxLength": 2000, 46 + "maxGraphemes": 500, 47 + "description": "Environment requirements (e.g. 'Requires Python 3.8+')." 48 + }, 49 + "resources": { 50 + "type": "array", 51 + "description": "Supporting files bundled with the skill (templates, scripts, reference docs). Stored as blobs.", 52 + "maxLength": 16, 53 + "items": { 54 + "type": "ref", 55 + "ref": "lex:org.v-it.skill#resource" 56 + } 57 + }, 58 + "recap": { 59 + "type": "ref", 60 + "ref": "lex:org.v-it.skill#recapRef", 61 + "description": "Reference to the skill this was derived/forked from." 62 + }, 63 + "tags": { 64 + "type": "array", 65 + "description": "Discovery tags for categorization and search.", 66 + "maxLength": 8, 67 + "items": { 68 + "type": "string", 69 + "maxLength": 640, 70 + "maxGraphemes": 64 71 + } 72 + }, 73 + "langs": { 74 + "type": "array", 75 + "description": "Human languages of the skill content.", 76 + "maxLength": 3, 77 + "items": { 78 + "type": "string", 79 + "format": "language" 80 + } 81 + }, 82 + "facets": { 83 + "type": "array", 84 + "description": "Rich text annotations in the description.", 85 + "items": { 86 + "type": "ref", 87 + "ref": "lex:app.bsky.richtext.facet" 88 + } 89 + }, 90 + "labels": { 91 + "type": "union", 92 + "description": "Self-label values. Content warnings.", 93 + "refs": ["lex:com.atproto.label.defs#selfLabels"] 94 + }, 95 + "createdAt": { 96 + "type": "string", 97 + "format": "datetime", 98 + "description": "Client-declared creation timestamp." 99 + } 100 + } 101 + } 102 + }, 103 + "resource": { 104 + "type": "object", 105 + "description": "A supporting file bundled with the skill. Binary content stored as blob.", 106 + "required": ["path", "blob"], 107 + "properties": { 108 + "path": { 109 + "type": "string", 110 + "maxLength": 512, 111 + "maxGraphemes": 128, 112 + "description": "Relative file path within the skill directory (e.g. 'scripts/validate.sh', 'reference.md')." 113 + }, 114 + "blob": { 115 + "type": "blob", 116 + "accept": ["*/*"], 117 + "maxSize": 1000000, 118 + "description": "File content. Uploaded via com.atproto.repo.uploadBlob." 119 + }, 120 + "mimeType": { 121 + "type": "string", 122 + "maxLength": 128, 123 + "description": "MIME type hint (e.g. 'text/markdown', 'application/x-shellscript')." 124 + }, 125 + "description": { 126 + "type": "string", 127 + "maxLength": 1000, 128 + "maxGraphemes": 256, 129 + "description": "What this resource contains. Helps agents with progressive disclosure." 130 + } 131 + } 132 + }, 133 + "recapRef": { 134 + "type": "object", 135 + "description": "Reference to a parent skill this was derived from.", 136 + "required": ["uri"], 137 + "properties": { 138 + "uri": { 139 + "type": "string", 140 + "format": "at-uri", 141 + "description": "AT URI of the parent skill record." 142 + } 143 + } 144 + } 145 + } 146 + }
+4 -4
lexicons/org/v-it/vouch.json
··· 4 4 "defs": { 5 5 "main": { 6 6 "type": "record", 7 - "description": "Record endorsing a vit cap.", 7 + "description": "Record endorsing a vit cap or skill.", 8 8 "key": "tid", 9 9 "record": { 10 10 "type": "object", 11 - "required": ["subject", "createdAt", "ref", "beacon"], 11 + "required": ["subject", "createdAt", "ref"], 12 12 "properties": { 13 13 "subject": { 14 14 "type": "ref", 15 15 "ref": "lex:com.atproto.repo.strongRef", 16 - "description": "The cap being endorsed." 16 + "description": "The cap or skill being endorsed." 17 17 }, 18 18 "ref": { 19 19 "type": "string", ··· 24 24 "beacon": { 25 25 "type": "string", 26 26 "maxLength": 512, 27 - "description": "Beacon URI scoping this vouch to a project." 27 + "description": "Beacon URI scoping this vouch to a project. Included for cap vouches, omitted for skill vouches." 28 28 }, 29 29 "createdAt": { 30 30 "type": "string",
+1
src/lib/constants.js
··· 3 3 4 4 export const CAP_COLLECTION = 'org.v-it.cap'; 5 5 export const VOUCH_COLLECTION = 'org.v-it.vouch'; 6 + export const SKILL_COLLECTION = 'org.v-it.skill';
+37
src/lib/skill-ref.js
··· 1 + // SPDX-License-Identifier: AGPL-3.0-only 2 + // Copyright (c) 2026 sol pbc 3 + 4 + // Skill ref format: skill-{name} 5 + // Name: lowercase letters, numbers, hyphens. No leading hyphen, no consecutive hyphens. Max 64 chars. 6 + 7 + export const SKILL_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/; 8 + export const SKILL_REF_PATTERN = /^skill-[a-z][a-z0-9]*(-[a-z0-9]+)*$/; 9 + export const SKILL_NAME_MAX = 64; 10 + 11 + export function isValidSkillName(name) { 12 + if (!name || typeof name !== 'string') return false; 13 + if (name.length > SKILL_NAME_MAX) return false; 14 + return SKILL_NAME_PATTERN.test(name); 15 + } 16 + 17 + export function isSkillRef(ref) { 18 + if (!ref || typeof ref !== 'string') return false; 19 + return ref.startsWith('skill-'); 20 + } 21 + 22 + export function skillRefFromName(name) { 23 + return `skill-${name}`; 24 + } 25 + 26 + export function nameFromSkillRef(ref) { 27 + if (!isSkillRef(ref)) return null; 28 + return ref.slice(6); 29 + } 30 + 31 + export function isValidSkillRef(ref) { 32 + if (!ref || typeof ref !== 'string') return false; 33 + // skill- prefix + valid name, total ref max 71 chars (6 + 64 + 1 for the hyphen in prefix) 34 + if (!SKILL_REF_PATTERN.test(ref)) return false; 35 + const name = nameFromSkillRef(ref); 36 + return name.length <= SKILL_NAME_MAX; 37 + }