# Getting Started Build your first AT Protocol app in minutes with the Slices CLI. ## Quick Start ### Install the CLI You'll need Deno installed first. Get it at [deno.com](https://deno.com/). ```bash # Install from JSR deno install -g -A jsr:@slices/cli --name slices ``` ### Login to Slices Before creating a project, authenticate with your AT Protocol account: ```bash slices login ``` This will open a browser window where you can authorize the CLI with your AT Protocol handle. ### Create Your Project ```bash # Create a new project with automatic setup slices init my-vinyl-app # Or let us generate a name/domain for you slices init ``` The `slices init` command does everything for you: - Creates a full-stack Deno app with OAuth authentication - Automatically creates a slice on the network - Sets up OAuth credentials - Pulls standard lexicons (including Bluesky profiles) - Generates a TypeScript SDK - Initializes a git repository ### Start Developing ```bash cd my-vinyl-app deno task dev ``` Visit http://localhost:8080 and you're live! ## What You Get The `slices init` command creates a production-ready app with: > More templates/examples coming soon (i.e. React, Expo, Astro, etc) ### Full-Stack Deno Application - **Server-side rendering** with Preact and JSX - **OAuth authentication** with PKCE flow and automatic token refresh - **HTMX integration** for dynamic UI without complex JavaScript - **Tailwind CSS** for beautiful, responsive styling - **SQLite sessions** for secure session management - **Feature-based architecture** for scalable code organization ### AT Protocol Integration - **Configured slice** with your own namespace - **Generated TypeScript SDK** from your lexicons - **Automatic sync** capabilities - **Real-time updates** via Jetstream ### Development Experience - **Hot reload** in development - **Type safety** throughout - **Environment variables** pre-configured - **Git repository** initialized ## Project Structure Here's what the generated project structure looks like: ``` my-vinyl-app/ ├── slices.json # Slice configuration ├── .env # Your credentials (auto-generated) ├── deno.json # Deno configuration ├── lexicons/ # AT Protocol schemas │ ├── com/ │ │ └── recordcollector/ │ │ └── album.json │ └── app/ │ └── bsky/ │ └── actor/ │ └── profile.json └── src/ ├── main.ts # Server entry point ├── config.ts # App configuration ├── generated_client.ts # Your TypeScript SDK ├── routes/ # HTTP routes ├── features/ # Feature modules │ ├── auth/ # OAuth implementation │ └── dashboard/ # Main app UI ├── shared/ # Reusable components └── utils/ # Helper functions ``` ## CLI Commands The Slices CLI is your command center: ### Project Management ```bash # Create a new project slices init my-app # Check your authentication status slices status # Authenticate with Slices network slices login ``` ### Lexicon Management ```bash # Pull lexicons from your slice slices lexicon pull # Push local lexicons to your slice slices lexicon push # List lexicons in your slice slices lexicon list ``` ### Code Generation ```bash # Generate TypeScript SDK from lexicons slices codegen # The SDK is created at src/generated_client.ts ``` ### Monitoring ```bash # View real-time Jetstream logs slices logs # See sync activity and data flow slices logs --verbose ``` ## Working with Lexicons Lexicons define your data structure. The init command includes Bluesky profile lexicons to get you started, but you'll want to add your own custom lexicons for your app. ### Modify an Existing Lexicon Edit `lexicons/com/recordcollector/album.json`: ```json { "lexicon": 1, "id": "com.recordcollector.album", "defs": { "main": { "type": "record", "description": "A vinyl album in my collection", "record": { "type": "object", "required": ["title", "artist", "releaseDate"], "properties": { "title": { "type": "string" }, "artist": { "type": "string" }, "releaseDate": { "type": "string", "format": "datetime" }, "genre": { "type": "array", "items": { "type": "string" } }, "condition": { "type": "string", "enum": [ "Mint", "Near Mint", "Very Good Plus", "Very Good", "Good", "Fair", "Poor" ] }, "notes": { "type": "string" } } } } } } ``` ### Create a New Lexicon Create `lexicons/com/recordcollector/review.json`: ```json { "lexicon": 1, "id": "com.recordcollector.review", "defs": { "main": { "type": "record", "description": "Album review", "record": { "type": "object", "required": ["albumUri", "rating", "content"], "properties": { "albumUri": { "type": "string", "format": "at-uri" }, "rating": { "type": "integer", "minimum": 1, "maximum": 5 }, "content": { "type": "string" }, "createdAt": { "type": "string", "format": "datetime" } } } } } } ``` ### Update Your Slice After modifying lexicons: ```bash # Push changes to your slice slices lexicon push # Regenerate the TypeScript SDK slices codegen ``` Your SDK at `src/generated_client.ts` now includes the new types and methods! **Important:** You must push your lexicons to the slice before you can create records. The slice needs to know about your schema in order to validate and store records. ## Using the Generated SDK The generated SDK provides a type-safe client for your slice: ```typescript import { AtprotoClient } from "./generated_client.ts"; // Initialize the client const client = new AtprotoClient({ baseUrl: "https://api.slices.network", sliceUri: Deno.env.get("SLICE_URI")!, }); // List albums with filtering and sorting const albums = await client.com.recordcollector.album.getRecords({ where: { genre: { contains: "jazz" }, }, sortBy: [{ field: "releaseDate", direction: "desc" }], limit: 20, }); // Add a new album const newAlbum = await client.com.recordcollector.album.createRecord({ title: "Kind of Blue", artist: "Miles Davis", releaseDate: "1959-08-17T00:00:00Z", genre: ["jazz", "modal jazz"], condition: "Near Mint", notes: "Original Columbia pressing", }); // Get a specific album const album = await client.com.recordcollector.album.getRecord({ uri: newAlbum.uri, }); // Update an album await client.com.recordcollector.album.updateRecord({ uri: album.uri, record: { ...album.value, notes: "Verified as first pressing!", }, }); // Delete an album await client.com.recordcollector.album.deleteRecord({ uri: album.uri, }); ``` ### External Collections Since the init command included Bluesky profile lexicons, your SDK has methods for querying them: ```typescript // Query users by display name (from included Bluesky lexicons) const profiles = await client.app.bsky.actor.profile.getRecords({ where: { displayName: { contains: "vinyl collector" }, }, }); ``` Any record-type lexicon you add to your slice will generate corresponding SDK methods when you run `slices codegen`. ## Syncing Data Once your app is running, you can sync data from the AT Protocol network. ### User Authentication Sync When users log in via OAuth, you can sync their data using the `syncUserCollections` method. This discovers and imports their external collections (like Bluesky profiles and posts). ```typescript // After user logs in await client.network.slices.slice.syncUserCollections(); ``` ### Manual Bulk Sync Use the web interface at https://slices.network to start a bulk sync job. Navigate to your slice's Sync tab to configure which collections and repositories to sync. **Note:** If you created new lexicons, you'll be the only one with records initially. As more users adopt your app and write records to their own PDSs, you can sync from their repositories to grow your network. ### Real-time Updates Jetstream automatically tracks creates, updates, and deletes across the network: ```bash # Monitor real-time sync slices logs --slice $SLICE_URI ``` ## Deployment Your app is ready for production deployment. ### Deno Deploy Create a free account at [deno.com/deploy](https://deno.com/deploy). Push your code to GitHub, then connect your repository through the Deno Deploy dashboard to deploy your app. For production use with Deno Deploy, switch from SQLite to Deno KV for OAuth and session storage: ```typescript import { DenoKVOAuthStorage } from "@slices/oauth"; import { DenoKVAdapter } from "@slices/session"; // Configure OAuth with Deno KV storage const oauthClient = new OAuthClient({ clientId: Deno.env.get("OAUTH_CLIENT_ID")!, clientSecret: Deno.env.get("OAUTH_CLIENT_SECRET")!, authBaseUrl: Deno.env.get("OAUTH_AIP_BASE_URL")!, redirectUri: Deno.env.get("OAUTH_REDIRECT_URI")!, storage: new DenoKVOAuthStorage(), // Uses Deno KV }); // Configure sessions with Deno KV adapter const sessionStore = new SessionStore({ adapter: new DenoKVAdapter(), // Uses Deno KV cookieOptions: { secure: true, httpOnly: true, }, }); ``` Deno KV provides serverless-compatible storage that scales automatically with your deployment. ## Manual Setup (Advanced) If you prefer to set things up manually or need custom configuration: ### 1. Create a Slice via Web UI Visit https://slices.network and: 1. Log in with your AT Protocol account 2. Click "Create Slice" 3. Choose your namespace (e.g., `com.recordcollector`) ### 2. Create OAuth Credentials In your slice dashboard: 1. Go to Settings → OAuth Clients 2. Create a new client 3. Set redirect URI: `http://localhost:8080/oauth/callback` 4. Copy the Client ID and Secret ### 3. Set Up Your Project Use any framework you prefer. You can use the generated TypeScript SDK (works with any JavaScript/TypeScript environment) or call the XRPC endpoints directly from any language: ```bash # Configure environment cp .env.example .env # Edit .env with your credentials # Start your project # (commands depend on your framework choice) ``` ## Next Steps - [Core Concepts](./concepts.md): Understand slices, lexicons, sync, and code generation - [API Reference](./api-reference.md): Detailed endpoint documentation - [SDK Usage](./sdk-usage.md): Advanced SDK patterns and examples - [Examples](./examples/): Sample applications and use cases ## Need Help? - Join our [Discord community](https://discord.gg/slices) - Check out [example apps](https://github.com/slices/examples) - Read the [AT Protocol docs](https://atproto.com/) - Report issues on [Tangled](https://tangled.sh/slices.network/slices/issues)