open source is social v-it.org
0
fork

Configure Feed

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

feat: prepare network seeding with skills, docs, and explore improvements

Add dogfooding instructions to CLAUDE.md, create three seed skills
(semantic-commits, bun-project, atproto-records), document vit scan
in the vit skill, add starter follow guidance to getting started page,
and improve the explore app with activity indicators, ATProto record
links, and descriptive empty states.

+477 -6
+18
CLAUDE.md
··· 59 59 - Use gerund or action-oriented naming (lowercase-hyphens only) for skill names. 60 60 - Write descriptions in third person that specify both what the skill does and when to use it. 61 61 - Test with all target models (Haiku, Sonnet, Opus) as effectiveness varies. 62 + 63 + ## Dogfooding 64 + 65 + Ship meaningful work as caps. Use `vit ship` after completing a feature, fix, or improvement — not for typos or formatting. 66 + 67 + ``` 68 + vit ship --title "Short Title" --description "One sentence of value." --ref "three-word-slug" --kind feat <<'EOF' 69 + Body paragraph explaining what the cap does and how it works. 70 + EOF 71 + ``` 72 + 73 + Flags: 74 + - `--title`: concise noun phrase (2–5 words) 75 + - `--description`: one sentence explaining the value 76 + - `--ref`: three lowercase hyphenated words — a memorable discovery slug 77 + - `--kind`: one of `feat`, `fix`, `test`, `docs`, `refactor`, `chore`, `perf`, `style` 78 + - `--recap <ref>`: link to a prior cap this one derives from (e.g. after `vit remix`) 79 + - Body (stdin): short paragraph for another developer or agent who might adopt it
+6
docs/start/index.html
··· 295 295 <p><strong><a href="https://explore.v-it.org">explore.v-it.org</a></strong> — the live network of projects and capabilities.</p> 296 296 <p>browse beacons (projects), see what caps (capabilities) are being shipped, and get a feel for how the bazaar works.</p> 297 297 <hr> 298 + <h2>who to follow</h2> 299 + <p>follow an active publisher to populate your skim feed:</p> 300 + <pre><code class="language-bash">npx vit follow jeremie.com</code></pre> 301 + <p>following means their caps show up when you <code>vit skim</code>. follow a few people whose work interests you.</p> 302 + <p>use <code>vit scan</code> to discover active publishers on the network — it replays recent activity and shows who&#39;s shipping.</p> 303 + <hr> 298 304 <h2>skim the network</h2> 299 305 <pre><code class="language-bash">npx vit skim 300 306 </code></pre>
+55 -6
explore/public/index.html
··· 323 323 background: #e5e7eb; 324 324 } 325 325 326 + .pulse-indicator { 327 + display: inline-block; 328 + color: #6b7280; 329 + font-size: 0.85rem; 330 + margin-left: 12px; 331 + } 332 + 333 + .pulse-dot { 334 + display: inline-block; 335 + width: 6px; 336 + height: 6px; 337 + background: var(--vit-green); 338 + border-radius: 50%; 339 + margin-right: 6px; 340 + vertical-align: middle; 341 + } 342 + 343 + .recent-activity { 344 + margin-top: 32px; 345 + } 346 + 347 + .recent-activity h3 { 348 + margin: 0 0 12px; 349 + font-size: 1rem; 350 + color: #374151; 351 + } 352 + 353 + .empty-state p { 354 + margin: 4px 0; 355 + } 356 + 357 + .empty-state a { 358 + color: var(--vit-green-deep); 359 + } 360 + 326 361 .view-title { 327 362 margin-top: 0; 328 363 margin-bottom: 16px; ··· 391 426 <a href="https://github.com/solpbc/vit">github</a> 392 427 </nav> 393 428 </div> 394 - <p class="tagline">open source is social</p> 429 + <p class="tagline">open source is social<span id="pulse" class="pulse-indicator"></span></p> 395 430 </header> 396 431 397 432 <main id="content"> ··· 484 519 const beacon = cap.beacon ? '<a href="#beacon/' + encodeURIComponent(cap.beacon) + '">' + esc(cap.beacon) + '</a>' : ''; 485 520 const time = timeAgo(cap.created_at); 486 521 const metaParts = [name, beacon, ref, time].filter(Boolean); 487 - return '<div class="cap-item"><div class="cap-title">' + title + '</div><div class="cap-meta">' + metaParts.join(' · ') + '</div></div>'; 522 + const titleHtml = cap.uri 523 + ? '<a href="https://pdsls.dev/at/' + esc(cap.uri.replace('at://', '')) + '" target="_blank" rel="noopener">' + title + '</a>' 524 + : title; 525 + return '<div class="cap-item"><div class="cap-title">' + titleHtml + '</div><div class="cap-meta">' + metaParts.join(' · ') + '</div></div>'; 488 526 } 489 527 490 528 function renderSkillItem(skill) { ··· 548 586 capsCursor = data.cursor; 549 587 550 588 if (data.caps.length === 0) { 551 - el.innerHTML = '<div class="empty-state"><p>no caps yet — be the first to <code>vit ship</code></p></div>'; 589 + el.innerHTML = '<div class="empty-state"><p><strong>No caps yet.</strong></p><p>Caps are software capabilities published to the network. Ship the first one:</p><pre><code>vit ship --title "..." --description "..." --ref "..."</code></pre><p><a href="https://v-it.org/start/">Get started with vit →</a></p></div>'; 552 590 return; 553 591 } 554 592 ··· 564 602 skillsCursor = data.cursor; 565 603 566 604 if (data.skills.length === 0) { 567 - el.innerHTML = '<div class="empty-state"><p>no skills yet — publish one with <code>vit ship --skill</code></p></div>'; 605 + el.innerHTML = '<div class="empty-state"><p><strong>No skills yet.</strong></p><p>Skills are reusable agent instructions published to the network. Publish one:</p><pre><code>vit ship --skill</code></pre><p><a href="https://v-it.org/start/">Get started with vit →</a></p></div>'; 568 606 return; 569 607 } 570 608 ··· 597 635 const data = await api('beacons'); 598 636 599 637 if (data.beacons.length === 0) { 600 - el.innerHTML = '<div class="empty-state"><p>no beacons yet — create one with <code>vit init</code></p></div>'; 638 + el.innerHTML = '<div class="empty-state"><p><strong>No beacons yet.</strong></p><p>Beacons are project markers that connect repos to the vit network. Light one up:</p><pre><code>vit init</code></pre><p><a href="https://v-it.org/start/">Get started with vit →</a></p></div>'; 601 639 return; 602 640 } 603 641 ··· 609 647 } 610 648 611 649 async function renderStats(el) { 612 - const data = await api('stats'); 650 + const [data, recent] = await Promise.all([api('stats'), api('caps?limit=5')]); 613 651 el.innerHTML = '<div class="stat-grid">' + 614 652 '<div class="stat-card"><div class="stat-number">' + data.total_caps + '</div><div class="stat-label">capabilities</div></div>' + 615 653 '<div class="stat-card"><div class="stat-number">' + data.total_vouches + '</div><div class="stat-label">vouches</div></div>' + ··· 618 656 '<div class="stat-card"><div class="stat-number">' + data.total_skills + '</div><div class="stat-label">skills</div></div>' + 619 657 '<div class="stat-card"><div class="stat-number">' + data.skill_publishers + '</div><div class="stat-label">skill publishers</div></div>' + 620 658 '</div>'; 659 + if (recent.caps && recent.caps.length > 0) { 660 + el.innerHTML += '<div class="recent-activity"><h3>recent activity</h3>' + recent.caps.map(renderCapItem).join('') + '</div>'; 661 + } 621 662 } 663 + 664 + // Pulse indicator 665 + api('caps?limit=1').then(function(data) { 666 + var el = document.getElementById('pulse'); 667 + if (el && data.caps && data.caps.length > 0) { 668 + el.innerHTML = '<span class="pulse-dot"></span>last activity: ' + timeAgo(data.caps[0].created_at); 669 + } 670 + }).catch(function() {}); 622 671 623 672 async function navigate() { 624 673 updateNav();
+177
skills/atproto-records/SKILL.md
··· 1 + --- 2 + name: atproto-records 3 + version: "1.0.0" 4 + description: >- 5 + Guides agents through reading and writing ATProto records, DID resolution, 6 + and PDS discovery. Activates when working with AT Protocol, Bluesky, or 7 + decentralized identity. 8 + --- 9 + 10 + ## 1. Core Concepts 11 + 12 + - **DID**: Decentralized identifier (e.g. `did:plc:abc123`). The stable identity. 13 + - **Handle**: Human-readable name (e.g. `alice.bsky.social`). Resolves to a DID. 14 + - **PDS**: Personal Data Server — stores a user's records. 15 + - **AT URI**: `at://did/collection/rkey` — uniquely identifies a record. 16 + - **Lexicon**: Schema definition for record types (like a protobuf for ATProto). 17 + - **NSID**: Namespaced identifier for collections (e.g. `app.bsky.feed.post`). 18 + 19 + ## 2. DID Resolution 20 + 21 + ### did:plc (most common) 22 + 23 + ```bash 24 + curl https://plc.directory/did:plc:abc123 25 + ``` 26 + 27 + Response includes `service` entries — find the one with `#atproto_pds` to get the PDS URL: 28 + 29 + ```json 30 + { 31 + "id": "did:plc:abc123", 32 + "service": [ 33 + { "id": "#atproto_pds", "type": "AtprotoPersonalDataServer", "serviceEndpoint": "https://pds.example.com" } 34 + ] 35 + } 36 + ``` 37 + 38 + ### did:web 39 + 40 + Resolve by fetching `https://<domain>/.well-known/did.json`. 41 + 42 + ### Handle to DID 43 + 44 + ```bash 45 + curl https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=alice.bsky.social 46 + ``` 47 + 48 + ## 3. Reading Records 49 + 50 + ### Get a Single Record 51 + 52 + ``` 53 + GET /xrpc/com.atproto.repo.getRecord?repo=<did>&collection=<nsid>&rkey=<rkey> 54 + ``` 55 + 56 + ```bash 57 + curl "https://pds.example.com/xrpc/com.atproto.repo.getRecord?repo=did:plc:abc123&collection=app.bsky.feed.post&rkey=3abc123" 58 + ``` 59 + 60 + Response: 61 + 62 + ```json 63 + { 64 + "uri": "at://did:plc:abc123/app.bsky.feed.post/3abc123", 65 + "cid": "bafyrei...", 66 + "value": { "$type": "app.bsky.feed.post", "text": "hello", "createdAt": "..." } 67 + } 68 + ``` 69 + 70 + ### List Records 71 + 72 + ``` 73 + GET /xrpc/com.atproto.repo.listRecords?repo=<did>&collection=<nsid>&limit=<n> 74 + ``` 75 + 76 + Supports cursor-based pagination via `cursor` parameter. 77 + 78 + ### Browsing Records 79 + 80 + Use [pdsls.dev](https://pdsls.dev) to browse any AT URI visually: 81 + 82 + ``` 83 + https://pdsls.dev/at/did:plc:abc123/app.bsky.feed.post/3abc123 84 + ``` 85 + 86 + Strip the `at://` prefix from the AT URI and append the rest as a path. 87 + 88 + ## 4. Writing Records 89 + 90 + Authenticated requests require an access token from `com.atproto.server.createSession`. 91 + 92 + ### Create a Record 93 + 94 + ``` 95 + POST /xrpc/com.atproto.repo.createRecord 96 + ``` 97 + 98 + ```json 99 + { 100 + "repo": "did:plc:abc123", 101 + "collection": "org.v-it.cap", 102 + "record": { 103 + "$type": "org.v-it.cap", 104 + "title": "Example Cap", 105 + "description": "What it does", 106 + "ref": "example-cap-ref", 107 + "beacon": "vit:github.com/org/repo", 108 + "createdAt": "2026-01-01T00:00:00.000Z" 109 + } 110 + } 111 + ``` 112 + 113 + ### Put a Record (upsert) 114 + 115 + ``` 116 + POST /xrpc/com.atproto.repo.putRecord 117 + ``` 118 + 119 + Same as create, but includes `rkey` and optionally `swapRecord` (CID) for conflict detection. 120 + 121 + ### Delete a Record 122 + 123 + ``` 124 + POST /xrpc/com.atproto.repo.deleteRecord 125 + ``` 126 + 127 + ```json 128 + { 129 + "repo": "did:plc:abc123", 130 + "collection": "org.v-it.cap", 131 + "rkey": "abc123" 132 + } 133 + ``` 134 + 135 + ## 5. Lexicon System 136 + 137 + Lexicons define record schemas using JSON: 138 + 139 + ```json 140 + { 141 + "lexicon": 1, 142 + "id": "org.v-it.cap", 143 + "defs": { 144 + "main": { 145 + "type": "record", 146 + "key": "tid", 147 + "record": { 148 + "type": "object", 149 + "required": ["title", "ref", "beacon", "createdAt"], 150 + "properties": { 151 + "title": { "type": "string", "maxLength": 256 }, 152 + "ref": { "type": "string" }, 153 + "beacon": { "type": "string" }, 154 + "description": { "type": "string", "maxLength": 1024 }, 155 + "createdAt": { "type": "string", "format": "datetime" } 156 + } 157 + } 158 + } 159 + } 160 + } 161 + ``` 162 + 163 + NSIDs follow reverse-domain naming: `org.v-it.cap`, `app.bsky.feed.post`. 164 + 165 + ## 6. Jetstream 166 + 167 + Jetstream provides real-time event streaming over WebSocket: 168 + 169 + ``` 170 + wss://jetstream2.us-east.bsky.network/subscribe?wantedCollections=org.v-it.cap 171 + ``` 172 + 173 + Parameters: 174 + - `wantedCollections`: filter by collection NSID (repeatable) 175 + - `cursor`: microsecond timestamp to replay from 176 + 177 + Events are JSON with `kind` (`commit`, `identity`, `account`), `did`, and `commit` details.
+127
skills/bun-project/SKILL.md
··· 1 + --- 2 + name: bun-project 3 + version: "1.0.0" 4 + description: >- 5 + Guides agents through Bun project setup, testing, and APIs. Activates when 6 + working with Bun-based JavaScript/TypeScript projects. 7 + --- 8 + 9 + ## 1. Project Setup 10 + 11 + Initialize a new project: 12 + 13 + ```bash 14 + bun init # interactive setup 15 + bun init -y # accept defaults 16 + ``` 17 + 18 + Key files: 19 + - `package.json` — standard npm-compatible manifest 20 + - `bun.lock` — binary lockfile (commit it, never edit manually) 21 + - `bunfig.toml` — optional Bun-specific config 22 + 23 + Install dependencies: 24 + 25 + ```bash 26 + bun install # install from package.json 27 + bun add <pkg> # add a dependency 28 + bun add -d <pkg> # add a dev dependency 29 + bun remove <pkg> # remove a dependency 30 + ``` 31 + 32 + ## 2. Running and Executing 33 + 34 + ```bash 35 + bun run <script> # run a package.json script 36 + bun <file.js> # run a JS/TS file directly 37 + bunx <pkg> # execute a package binary (like npx) 38 + ``` 39 + 40 + Bun runs TypeScript and JSX natively — no build step needed. 41 + 42 + ## 3. Testing 43 + 44 + Bun has a built-in test runner compatible with Jest-like syntax: 45 + 46 + ```javascript 47 + import { test, expect, describe, beforeEach } from 'bun:test'; 48 + 49 + describe('example', () => { 50 + test('adds numbers', () => { 51 + expect(1 + 1).toBe(2); 52 + }); 53 + }); 54 + ``` 55 + 56 + Run tests: 57 + 58 + ```bash 59 + bun test # run all test files 60 + bun test path/to/file # run specific test file 61 + bun test --watch # re-run on file changes 62 + ``` 63 + 64 + Test file patterns: `*.test.{js,ts,jsx,tsx}`, `*_test.{js,ts}`, or files in `__tests__/`. 65 + 66 + ## 4. Bun-Specific APIs 67 + 68 + ### File I/O 69 + 70 + ```javascript 71 + const file = Bun.file('path/to/file.txt'); 72 + const text = await file.text(); // read as string 73 + const json = await file.json(); // parse as JSON 74 + const bytes = await file.arrayBuffer(); // read as bytes 75 + await Bun.write('out.txt', 'content'); // write a file 76 + ``` 77 + 78 + ### HTTP Server 79 + 80 + ```javascript 81 + Bun.serve({ 82 + port: 3000, 83 + fetch(req) { 84 + const url = new URL(req.url); 85 + if (url.pathname === '/') return new Response('ok'); 86 + return new Response('not found', { status: 404 }); 87 + }, 88 + }); 89 + ``` 90 + 91 + ### Hashing and Utilities 92 + 93 + ```javascript 94 + const hash = Bun.hash('input string'); 95 + const pw = await Bun.password.hash('secret'); 96 + const ok = await Bun.password.verify('secret', pw); 97 + ``` 98 + 99 + ### Shell 100 + 101 + ```javascript 102 + import { $ } from 'bun'; 103 + const result = await $`ls -la`.text(); 104 + ``` 105 + 106 + ## 5. Workspaces 107 + 108 + For monorepos, add to `package.json`: 109 + 110 + ```json 111 + { 112 + "workspaces": ["packages/*"] 113 + } 114 + ``` 115 + 116 + Each workspace package gets its own `package.json`. Run scripts in a specific workspace: 117 + 118 + ```bash 119 + bun run --filter <name> <script> 120 + ``` 121 + 122 + ## 6. Common Patterns 123 + 124 + - **Shebangs**: Use `#!/usr/bin/env bun` for executable scripts 125 + - **Environment variables**: Access via `Bun.env.VAR_NAME` or `process.env.VAR_NAME` 126 + - **Import from URL**: `import x from 'https://example.com/mod.js'` works directly 127 + - **SQLite**: `import { Database } from 'bun:sqlite'` — built-in, no install needed
+79
skills/semantic-commits/SKILL.md
··· 1 + --- 2 + name: semantic-commits 3 + version: "1.0.0" 4 + description: >- 5 + Guides agents to write conventional commit messages with correct types, scopes, 6 + and formatting. Activates when committing code or writing commit messages. 7 + --- 8 + 9 + ## 1. Format 10 + 11 + ``` 12 + <type>(<scope>): <subject> 13 + 14 + <body> 15 + ``` 16 + 17 + - **subject**: imperative mood, lowercase, no period, under 72 characters 18 + - **scope**: optional, names the area changed (e.g. `cli`, `auth`, `explorer`) 19 + - **body**: optional, explains *why* not *what*, wrapped at 72 characters 20 + 21 + ## 2. Types 22 + 23 + | Type | When to use | 24 + |------|------------| 25 + | `feat` | A new feature or capability | 26 + | `fix` | A bug fix | 27 + | `test` | Adding or updating tests only | 28 + | `docs` | Documentation changes only | 29 + | `refactor` | Code restructuring with no behavior change | 30 + | `chore` | Maintenance — deps, CI, tooling, config | 31 + | `perf` | Performance improvement with no behavior change | 32 + | `style` | Formatting, whitespace, linting — no logic change | 33 + 34 + ## 3. Scope 35 + 36 + Use the most specific component name that applies: 37 + 38 + - CLI commands: `cli`, `ship`, `skim`, `scan`, `follow` 39 + - Libraries: `auth`, `pds`, `lexicon`, `brand` 40 + - Infrastructure: `ci`, `deps`, `build` 41 + - Documentation: `docs`, `readme`, `skill` 42 + 43 + Omit scope if the change spans multiple areas. 44 + 45 + ## 4. Examples 46 + 47 + ``` 48 + feat(scan): add tag filtering for skill discovery 49 + fix(auth): handle expired OAuth sessions gracefully 50 + test(ship): add validation tests for --kind flag 51 + docs(skill): document vit scan flags and output format 52 + refactor(pds): extract DID resolution into shared helper 53 + chore(deps): update bun to 1.3.10 54 + perf(skim): batch PDS queries for followed accounts 55 + style(cli): normalize whitespace in help output 56 + ``` 57 + 58 + ## 5. Breaking Changes 59 + 60 + Add `!` after type/scope and a `BREAKING CHANGE:` footer: 61 + 62 + ``` 63 + feat(auth)!: require OAuth for all PDS operations 64 + 65 + BREAKING CHANGE: Basic auth is no longer supported. Users must run 66 + `vit login <handle>` to authenticate via OAuth. 67 + ``` 68 + 69 + ## 6. Multi-line Bodies 70 + 71 + When the *why* matters, use the body: 72 + 73 + ``` 74 + fix(skim): deduplicate caps from multi-PDS resolution 75 + 76 + The handle-to-DID resolution could return records from both the 77 + primary and mirror PDS, causing duplicate caps in skim output. 78 + Filter by URI uniqueness before display. 79 + ```
+15
skills/vit/SKILL.md
··· 133 133 - Output: `beacon: lit <uri>` or `beacon: unlit`. 134 134 - Common errors: invalid target URL or clone/probe failure. 135 135 136 + ### `vit scan` 137 + - Description: Discover cap and skill publishers across the network via Jetstream replay. 138 + - Usage: `vit scan [options]` 139 + - Key flags: 140 + - `--days <n>` — number of days to replay (default: 7) 141 + - `--beacon <beacon>` — filter by beacon (caps only) 142 + - `--skills` — show only skill publishers 143 + - `--caps` — show only cap publishers 144 + - `--tag <tag>` — filter skills by tag 145 + - `-v, --verbose` — show each event as it arrives 146 + - `--jetstream <url>` — custom Jetstream URL (default: `VIT_JETSTREAM_URL` env or built-in) 147 + - Output: Publisher summaries sorted by activity count. Each entry shows handle, cap/skill counts, beacons, tags, and last active date. 148 + - Read-only: Replays Jetstream events with a time-bounded timeout (2–10 minutes based on `--days`). Does not write any data. 149 + - Use cases: Find active publishers to follow, discover beacons with recent activity, identify skill authors by tag. 150 + 136 151 ## 5. Commands the Agent Must NOT Run 137 152 138 153 These commands require human interaction. Tell the user exactly what to run: