# Jazz ## Documentation ### Getting started #### Introduction ### ai-tools Implementation # Using AI to build Jazz apps AI tools, particularly large language models (LLMs), can accelerate your development with Jazz. Searching docs, responding to questions and even helping you write code are all things that LLMs are starting to get good at. However, Jazz is a rapidly evolving framework, so sometimes AI might get things a little wrong. To help the LLMs, we provide the Jazz documentation in a txt file that is optimized for use with AI tools, like Cursor. llms-full.txt ## Setting up AI tools Every tool is different, but generally, you'll need to either paste the contents of the [llms-full.txt](https://jazz.tools/llms-full.txt) file directly in your prompt, or attach the file to the tool. ### ChatGPT and v0 Upload the txt file in your prompt. ![ChatGPT prompt with llms-full.txt attached](/chatgpt-with-llms-full-txt.jpg) ### Cursor 1. Go to Settings > Cursor Settings > Features > Docs 2. Click "Add new doc" 3. Enter the following URL: ``` https://jazz.tools/llms-full.txt ``` ## llms.txt convention We follow the llms.txt [proposed standard](https://llmstxt.org/) for providing documentation to AI tools at inference time that helps them understand the context of the code you're writing. ## Limitations and considerations AI is amazing, but it's not perfect. What works well this week could break next week (or be twice as good). We're keen to keep up with changes in tooling to help support you building the best apps, but if you need help from humans (or you have issues getting set up), please let us know on [Discord](https://discord.gg/utDMjHYg42). --- ### inspector Implementation # Jazz Inspector [Jazz Inspector](https://inspector.jazz.tools) is a tool to visually inspect a Jazz account or other CoValues. For now, you can get your account credentials from the `jazz-logged-in-secret` local storage key from within your Jazz app. [https://inspector.jazz.tools](https://inspector.jazz.tools) ## Exporting current account to Inspector from your app In development mode, you can launch the Inspector from your Jazz app to inspect your account by pressing `Cmd+J`. ## Embedding the Inspector widget into your app Alternatively, you can embed the Inspector directly into your app, so you don't need to open a separate window. Install the package. ```sh npm install jazz-inspector ``` Render the component within your `JazzProvider`. ```sh // old // old ``` Check out the [music player app](https://github.com/garden-co/jazz/blob/main/examples/music-player/src/2_main.tsx) for a full example. --- ### sync-and-storage Implementation # Sync and storage ## Using Jazz Cloud Simply use `wss://cloud.jazz.tools/?key=...` as the sync server URL. Jazz Cloud will - sync CoValues in real-time between users and devices - safely persist CoValues on redundant storage nodes with additional backups - make use of geographically distributed cache nodes for low latency ### Free public alpha - Jazz Cloud is free during the public alpha, with no strict usage limits - We plan to keep a free tier, so you'll always be able to get started with zero setup - See [Jazz Cloud pricing](/cloud#pricing) for more details - ⚠️ Please use a valid email address as your API key. Your full sync server URL should look something like ```wss://cloud.jazz.tools/?key=you@example.com``` Once we support per-app API keys, we'll email you an API key you can use instead. ## Running your own sync server You can run your own sync server using: ```sh npx jazz-run sync ``` And then use `ws://localhost:4200` as the sync server URL. You can also run this simple sync server behind a proxy that supports WebSockets, for example to provide TLS. In this case, provide the WebSocket endpoint your proxy exposes as the sync server URL. ### Command line options: - `--port` / `-p` - the port to run the sync server on. Defaults to 4200. - `--in-memory` - keep CoValues in-memory only and do sync only, no persistence. Persistence is enabled by default. - `--db` - the path to the file where to store the data (SQLite). Defaults to `sync-db/storage.db`. ### Source code The implementation of this simple sync server is available open-source [on GitHub](https://github.com/garden-co/jazz/blob/main/packages/jazz-run/src/startSyncServer.ts). #### Guide ### react Implementation # React guide This is a step-by-step tutorial where we'll build an issue tracker app using React. You'll learn how to set up a Jazz app, use Jazz Cloud for sync and storage, create and manipulate data using Collaborative Values (CoValues), build a UI and subscribe to changes, set permissions, and send invites. ## Project setup 1. Create a project called "circular" from a generic Vite starter template: {/* prettier-ignore */} ```bash npx degit gardencmp/vite-ts-react-tailwind circular cd circular npm install npm run dev ``` You should now have an empty app running, typically at [localhost:5173](http://localhost:5173).
(If you make changes to the code, the app will automatically refresh.) 2. Install `jazz-tools` and `jazz-react`
(in a new terminal window): {/* prettier-ignore */} ```bash cd circular npm install jazz-tools jazz-react ``` 3. Modify `src/main.tsx` to set up a Jazz context: {/* prettier-ignore */} ```tsx import React from "react"; // old import ReactDOM from "react-dom/client"; // old import App from "./App.tsx"; // old import "./index.css"; // old import { JazzProvider } from "jazz-react"; // old ReactDOM.createRoot(document.getElementById("root")!).render( // old // old // old ); // old ``` This sets Jazz up and wraps our app in the provider. {/* TODO: explain Auth */} ## Intro to CoValues Let's learn about the **central idea** behind Jazz: **Collaborative Values.** What if we could **treat distributed state like local state?** That's what CoValues do. We can - **create** CoValues, anywhere - **load** CoValues by `ID`, from anywhere else - **edit** CoValues, from anywhere, by mutating them like local state - **subscribe to edits** in CoValues, whether they're local or remote ### Declaring our own CoValues To make our own CoValues, we first need to declare a schema for them. Think of a schema as a combination of TypeScript types and runtime type information. Let's start by defining a schema for our most central entity in Circular: an **Issue.** Create a new file `src/schema.ts` and add the following: ```ts export class Issue extends CoMap { title = co.string; description = co.string; estimate = co.number; status? = co.literal("backlog", "in progress", "done"); } ``` {/* TODO: explain what's happening */} ### Reading from CoValues CoValues are designed to be read like simple local JSON state. Let's see how we can read from an Issue by building a component to render one. Create a new file `src/components/Issue.tsx` and add the following: {/* prettier-ignore */} ```tsx export function IssueComponent({ issue }: { issue: Issue }) { return (

{issue.title}

{issue.description}

Estimate: {issue.estimate}

Status: {issue.status}

); } ```
Simple enough! ### Creating CoValues To actually see an Issue, we have to create one. This is where things start to get interesting... Let's modify `src/App.tsx` to prepare for creating an Issue and then rendering it: {/* prettier-ignore */} ```tsx // old function App() {// old const [issue, setIssue] = useState(); // old if (issue) { return ; } else { return ; } } // old // old export default App; // old ``` Now, finally, let's implement creating an issue: {/* prettier-ignore */} ```tsx // old function App() {// old const [issue, setIssue] = useState(); // old // old const createIssue = () => { const newIssue = Issue.create( { title: "Buy terrarium", description: "Make sure it's big enough for 10 snails.", estimate: 5, status: "backlog", }, ); setIssue(newIssue); }; // old if (issue) {// old return ; // old } else { // old return ; } // old } // old // old export default App; // old ``` 🏁 Now you should be able to create a new issue by clicking the button and then see it rendered!
Preview

Buy terrarium

Make sure it's big enough for 10 snails.

Estimate: 5

Status: backlog

We'll already notice one interesting thing here: - We have to create every CoValue with an `owner`! - this will determine access rights on the CoValue, which we'll learn about in "Groups & Permissions" - here the `owner` is set automatically to a group managed by the current user because we have not declared any **Behind the scenes, Jazz not only creates the Issue in memory but also automatically syncs an encrypted version to the cloud and persists it locally. The Issue also has a globally unique ID.** We'll make use of both of these facts in a bit, but for now let's start with local editing and subscribing. ### Editing CoValues and subscribing to edits Since we're the owner of the CoValue, we should be able to edit it, right? And since this is a React app, it would be nice to subscribe to edits of the CoValue and reactively re-render the UI, like we can with local state. This is exactly what the `useCoState` hook is for! - Note that `useCoState` doesn't take a CoValue directly, but rather a CoValue's schema, plus its `ID`. - So we'll slightly adapt our `useState` to only keep track of an issue ID... - ...and then use `useCoState` to get the actual issue Let's modify `src/App.tsx`: {/* prettier-ignore */} ```tsx // old function App() { // old const [issueID, setIssueID] = useState>(); // old const issue = useCoState(Issue, issueID); // old const createIssue = () => {// old const newIssue = Issue.create(// old { // old title: "Buy terrarium", // old description: "Make sure it's big enough for 10 snails.", // old estimate: 5, // old status: "backlog", // old }, // old ); // old setIssueID(newIssue.id); }; // old // old if (issue) { // old return ; // old } else { // old return ; // old } // old } // old // old export default App; // old ``` And now for the exciting part! Let's make `src/components/Issue.tsx` an editing component. {/* prettier-ignore */} ```tsx // old export function IssueComponent({ issue }: { issue: Issue }) { // old return ( // old
// old { issue.title = event.target.value }}/>