a tool to help your Letta AI agents navigate bluesky

Add domain verification guard to schema publication script

Changes:
- Update scripts/publishSchema.ts: Add domain ownership verification
- Add SCHEMA_PUBLISHER_USERNAME and SCHEMA_PUBLISHER_PASSWORD env vars
- Verify logged-in account handle contains expected domain
- Provide clear error messages for template users who accidentally run script
- Update scripts/README.md: Document new credential approach
- Update .env.example: Add schema publisher credential placeholders

This prevents template users from accidentally publishing duplicate schemas
while allowing the voyager.studio domain owner to publish independently
from any Bluesky account with a voyager.studio handle.

The script can now be run with:
SCHEMA_PUBLISHER_USERNAME=handle SCHEMA_PUBLISHER_PASSWORD=pass deno task publish-schema

Claude 9050744b b90ff4d4

Changed files
+54 -12
scripts
+5
.env.example
··· 6 RESPONSIBLE_PARTY_NAME= 7 RESPONSIBLE_PARTY_CONTACT="example@example.com, example.com/contact, or @example.bsky.app" 8 9 # AUTOMATION_LEVEL="automated" 10 # BSKY_SERVICE_URL=https://bsky.social 11 # BSKY_NOTIFICATION_TYPES="mention, reply"
··· 6 RESPONSIBLE_PARTY_NAME= 7 RESPONSIBLE_PARTY_CONTACT="example@example.com, example.com/contact, or @example.bsky.app" 8 9 + # Schema Publisher Credentials (ONLY for voyager.studio domain owner) 10 + # Template users do NOT need these - the schema is already published 11 + # SCHEMA_PUBLISHER_USERNAME= 12 + # SCHEMA_PUBLISHER_PASSWORD= 13 + 14 # AUTOMATION_LEVEL="automated" 15 # BSKY_SERVICE_URL=https://bsky.social 16 # BSKY_NOTIFICATION_TYPES="mention, reply"
+20 -3
scripts/README.md
··· 23 Type: TXT 24 Value: did=did:plc:YOUR_DID 25 ``` 26 - 3. `.env` file configured with credentials for the voyager.studio account owner: 27 - - `BSKY_USERNAME`: Your voyager.studio handle 28 - - `BSKY_APP_PASSWORD`: App password for that account 29 30 ### Usage 31 32 ```bash 33 deno task publish-schema 34 ``` 35 36 ### What it does 37
··· 23 Type: TXT 24 Value: did=did:plc:YOUR_DID 25 ``` 26 + 3. Credentials for a Bluesky account with a handle containing `voyager.studio` 27 28 ### Usage 29 + 30 + **Option 1: Environment variables (recommended)** 31 32 ```bash 33 + SCHEMA_PUBLISHER_USERNAME=your.voyager.studio.handle \ 34 + SCHEMA_PUBLISHER_PASSWORD=your-app-password \ 35 deno task publish-schema 36 ``` 37 + 38 + **Option 2: Add to .env file** 39 + 40 + Add these lines to `.env` (separate from your AI agent credentials): 41 + ```bash 42 + SCHEMA_PUBLISHER_USERNAME=your.voyager.studio.handle 43 + SCHEMA_PUBLISHER_PASSWORD=your-app-password 44 + ``` 45 + 46 + Then run: 47 + ```bash 48 + deno task publish-schema 49 + ``` 50 + 51 + **Note**: The script will verify that the logged-in account's handle contains `voyager.studio` before publishing. 52 53 ### What it does 54
+29 -9
scripts/publishSchema.ts
··· 10 * 11 * Prerequisites: 12 * 1. DNS TXT record: _lexicon.account.voyager.studio pointing to your DID 13 - * 2. BSKY_USERNAME and BSKY_APP_PASSWORD in .env for the voyager.studio account 14 * 15 - * Usage: deno task publish-schema 16 */ 17 18 import { AtpAgent } from "@atproto/api"; ··· 21 const publishSchema = async () => { 22 console.log("🔧 Publishing studio.voyager.account.autonomy schema...\n"); 23 24 - // Get credentials from environment 25 - const username = Deno.env.get("BSKY_USERNAME"); 26 - const password = Deno.env.get("BSKY_APP_PASSWORD"); 27 const serviceUrl = Deno.env.get("BSKY_SERVICE_URL") || "https://bsky.social"; 28 29 if (!username || !password) { 30 console.error( 31 - "❌ Error: BSKY_USERNAME and BSKY_APP_PASSWORD must be set in .env", 32 - ); 33 - console.error( 34 - " This should be the credentials for the voyager.studio account owner.\n", 35 ); 36 Deno.exit(1); 37 } 38 ··· 47 password: password, 48 }); 49 console.log(`✅ Logged in as: ${agent.session?.handle} (${agent.session?.did})\n`); 50 51 // Prepare schema record 52 const schemaRecord = {
··· 10 * 11 * Prerequisites: 12 * 1. DNS TXT record: _lexicon.account.voyager.studio pointing to your DID 13 + * 2. SCHEMA_PUBLISHER_USERNAME: Bluesky handle for voyager.studio domain owner 14 + * 3. SCHEMA_PUBLISHER_PASSWORD: App password for that account 15 * 16 + * Usage: 17 + * SCHEMA_PUBLISHER_USERNAME=your.handle SCHEMA_PUBLISHER_PASSWORD=xxxx deno task publish-schema 18 + * 19 + * OR set these in .env (separate from your agent credentials): 20 + * SCHEMA_PUBLISHER_USERNAME=... 21 + * SCHEMA_PUBLISHER_PASSWORD=... 22 */ 23 24 import { AtpAgent } from "@atproto/api"; ··· 27 const publishSchema = async () => { 28 console.log("🔧 Publishing studio.voyager.account.autonomy schema...\n"); 29 30 + // Get credentials from environment - use separate vars from agent credentials 31 + const username = Deno.env.get("SCHEMA_PUBLISHER_USERNAME") || Deno.env.get("BSKY_USERNAME"); 32 + const password = Deno.env.get("SCHEMA_PUBLISHER_PASSWORD") || Deno.env.get("BSKY_APP_PASSWORD"); 33 const serviceUrl = Deno.env.get("BSKY_SERVICE_URL") || "https://bsky.social"; 34 + const expectedDomain = Deno.env.get("SCHEMA_DOMAIN") || "voyager.studio"; 35 36 if (!username || !password) { 37 console.error( 38 + "❌ Error: Schema publisher credentials not found.\n" 39 ); 40 + console.error(" Set SCHEMA_PUBLISHER_USERNAME and SCHEMA_PUBLISHER_PASSWORD"); 41 + console.error(" OR run with: SCHEMA_PUBLISHER_USERNAME=your.handle SCHEMA_PUBLISHER_PASSWORD=xxxx deno task publish-schema\n"); 42 + console.error(" ⚠️ Template users: You do NOT need to run this command!"); 43 + console.error(" The schema is already published by voyager.studio.\n"); 44 Deno.exit(1); 45 } 46 ··· 55 password: password, 56 }); 57 console.log(`✅ Logged in as: ${agent.session?.handle} (${agent.session?.did})\n`); 58 + 59 + // Verify domain ownership 60 + const handle = agent.session?.handle || ""; 61 + if (!handle.includes(expectedDomain)) { 62 + console.error(`❌ Error: This account does not appear to own ${expectedDomain}\n`); 63 + console.error(` Logged in as: ${handle}`); 64 + console.error(` Expected domain: ${expectedDomain}\n`); 65 + console.error(" ⚠️ Template users: You do NOT need to publish the schema!"); 66 + console.error(" The schema is already published and discoverable."); 67 + console.error(" You only create your own autonomy declaration record via 'deno task mount'.\n"); 68 + Deno.exit(1); 69 + } 70 71 // Prepare schema record 72 const schemaRecord = {