# Getting Started
URL: /docs/ink
Build AI chat interfaces for the terminal with @assistant-ui/react-ink.
Quick Start \[#quick-start]
The fastest way to get started with assistant-ui for the terminal.
Create a new project \[#create-a-new-project]
```sh
npx assistant-ui@latest create --ink my-chat-app
cd my-chat-app
```
Install dependencies \[#install-dependencies]
```sh
pnpm install
```
Start the app \[#start-the-app]
```sh
pnpm dev
```
Manual Setup \[#manual-setup]
If you prefer to add assistant-ui to an existing Node.js project, follow these steps.
Install dependencies \[#install-dependencies-1]
```sh
npm install @assistant-ui/react-ink @assistant-ui/react-ink-markdown ink react
```
Create a chat model adapter \[#create-a-chat-model-adapter]
Define how your app communicates with your AI backend. This example uses a simple streaming adapter:
```ts title="adapters/my-chat-adapter.ts"
import type { ChatModelAdapter } from "@assistant-ui/react-ink";
export const myChatAdapter: ChatModelAdapter = {
async *run({ messages, abortSignal }) {
const response = await fetch("http://localhost:3000/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
signal: abortSignal,
});
const reader = response.body?.getReader();
if (!reader) throw new Error("No response body");
const decoder = new TextDecoder();
let fullText = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
fullText += chunk;
yield { content: [{ type: "text", text: fullText }] };
}
},
};
```
This is the same `ChatModelAdapter` interface used in `@assistant-ui/react` and `@assistant-ui/react-native`. If you already have an adapter, you can reuse it as-is.
Set up the runtime \[#set-up-the-runtime]
```tsx title="app.tsx"
import { Box, Text } from "ink";
import {
AssistantProvider,
useLocalRuntime,
} from "@assistant-ui/react-ink";
import { myChatAdapter } from "./adapters/my-chat-adapter.js";
export function App() {
const runtime = useLocalRuntime(myChatAdapter);
return (
My Terminal Chat
{/* your chat UI */}
);
}
```
Build your chat UI \[#build-your-chat-ui]
Use primitives to compose your terminal chat interface:
```tsx title="components/thread.tsx"
import { Box, Text } from "ink";
import {
ThreadRoot,
ThreadMessages,
ThreadEmpty,
ComposerInput,
useThreadIsRunning,
} from "@assistant-ui/react-ink";
import type { ThreadMessage } from "@assistant-ui/react-ink";
import { MarkdownText } from "@assistant-ui/react-ink-markdown";
const Message = ({ message }: { message: ThreadMessage }) => {
const isUser = message.role === "user";
const text = message.content
.filter((p) => p.type === "text")
.map((p) => ("text" in p ? p.text : ""))
.join("");
if (isUser) {
return (
You:
{text}
);
}
return (
AI:
);
};
const StatusIndicator = () => {
const isRunning = useThreadIsRunning();
if (!isRunning) return null;
return (
Thinking...
);
};
export const Thread = () => {
return (
No messages yet. Start typing below!
} />
{"> "}
);
};
```
Render with Ink \[#render-with-ink]
```tsx title="index.tsx"
import { render } from "ink";
import { App } from "./app.js";
render();
```
What's Next? \[#whats-next]