UClaw SDK Skill
Overview
Use this skill to help users install and use @uclaw/sdk, the official TypeScript SDK for UClaw. UClaw provides a managed runtime for stateful AI agents, so users can build agentic applications without managing WebSocket connections, session persistence, or sandbox execution infrastructure themselves.
Prefer the production SDK package, @uclaw/sdk. The @uclaw/cli package is experimental and for internal testing only, so do not recommend it for normal user workflows unless the user specifically asks about the CLI and accepts the risk.
Pre-work Technical Decisions & Architecture Alignment
Before writing code or configuring UClaw agents/applications, you must align on the following five technical decisions with the user. If they are not specified, ask or suggest defaults based on the following guidelines:
- Scenario Target (Server-Side vs Frontend):
- Server-Side: Run UClaw's
AppClient in server scripts, APIs, background jobs, or workers. Requires UCLAW_API_KEY on the server (never leaked to browser).
- Frontend: Connect to agent sessions in browser components using React hooks (
@uclaw/sdk/react such as useApp or useAgent). Secure this by setting up a token exchange server route (e.g. /api/uclaw/client-tokens) that exchanges UCLAW_API_KEY for short-lived client tokens.
- App Identity & Data Boundary:
- Choose an explicit
appId for each product, project, tenant, or environment before creating agents.
- Treat
appId as the real data isolation boundary for agents, history, workspace state, and secrets. UCLAW_API_KEY authenticates the account/request, but it does not create a fresh data namespace by itself.
- Avoid using
appId: "default" in new projects unless the user intentionally wants to connect to the account's existing default app data. Reusing default can reveal or continue historical agents from previous experiments.
- Rotating or changing the API key does not isolate data if the code keeps using the same
appId.
- Use stable, descriptive IDs such as
my-product-dev, my-product-prod, or customer-portal-staging, and pass the same appId consistently to server AppClient, token routes, useApp, and useAgent.
- Agent Orchestration:
- Global Unique Agent: A single agent session. Ideal for single-user stateless utilities or simple one-off tasks where user data is ephemeral.
- Multiple Named Agents: Multiple distinct agent sessions (tracked via unique IDs/titles). Ideal for persistent multi-chat interfaces, multi-user systems, or separate projects.
- App-Agent Hierarchy: The parent application layer manages a directory/collection of distinct agent sessions (listing, creating, and deleting agents via
useApp or AppClient). Ideal when the application needs to dynamically spawn and maintain separate persistent chats/agents for different users or contexts.
- Model Selection:
- Determine the provider and performance level required.
- Configure using
modelProvider (e.g., "openai", "anthropic", "deepseek") and modelTier: "fast" | "balanced" | "capable" (defaults to "balanced"). This avoids pinning direct model names (which may go unsupported later) and allows the platform to route to the best available models.
- Only use
model (e.g. "openai/gpt-5.5", "anthropic/claude-opus-4.8") as a fallback override if a specific model version is explicitly requested.
- Capabilities & Extensions:
- Select the minimum set of capabilities required:
read: access to read workspace files (read, list, find, grep tools).
write: access to edit/write/delete workspace files (write, edit, delete tools).
execute: run code in sandboxed workers (bash and execute tools).
database: SQL database access in workspace (sql tool).
network: external network access from execute scripts.
secret: secrets management (add_secret, list_secrets, remove_secret tools).
browser: browser scraping/interaction (Chrome CDP browser tool).
- Configure custom tools under
extensions using the ExtensionDefinition format for custom execution tasks.
When To Use This Skill
Use this skill when the user asks to:
- Install or configure UClaw in a JavaScript, TypeScript, React, or Next.js project.
- Create, list, rename, delete, or run UClaw agent sessions.
- Stream agent responses or generate text with
AppClient.
- Configure
/api/uclaw/client-tokens for browser-side React hooks.
- Use
@uclaw/sdk/react hooks such as useApp or useAgent.
- Manage UClaw secrets through the SDK.
- Fix SDK setup issues involving Node.js, npm, pnpm, bun,
.env, or UCLAW_API_KEY.
Working Principles
- Keep
UCLAW_API_KEY server-side. Never place it in browser code, React client components, public bundles, or frontend environment variables.
- Do not confuse authentication with data isolation:
UCLAW_API_KEY authenticates access, while appId selects the app data namespace.
- Always choose and document an explicit
appId for new projects. Do not default to appId: "default" unless the user knowingly wants to reuse the account's existing default app history.
- Store
UCLAW_API_KEY in the project-local .env file, not in global shell files such as ~/.zshrc, ~/.bashrc, or machine-wide environment settings.
- Never ask the user to paste an API key into chat. Give local terminal instructions that let the user edit
.env themselves.
- Install
@uclaw/sdk into the user's project. Do not install it globally.
- Choose the user's existing package manager from project evidence instead of defaulting to
npm.
- If Node.js is missing, treat that as an environment prerequisite, not as permission to silently install system software.
Environment Check Workflow
Before using UClaw functionality in a project, check the local JavaScript environment from the project root.
Check for Node.js:
node --version
Check available package managers:
npm --version
pnpm --version
bun --version
It is fine if some commands are missing. Use the ones that exist.
Detect the preferred package manager from the project, in this order:
package.json packageManager field, if present.
- Lockfiles:
pnpm-lock.yaml -> pnpm
bun.lock or bun.lockb -> bun
package-lock.json or npm-shrinkwrap.json -> npm
yarn.lock -> yarn
- Existing scripts or repo docs that consistently use one package manager.
- If no evidence exists, use
npm because it ships with Node.js.
If a package manager is implied but missing:
- For
pnpm or yarn, prefer corepack enable when the installed Node version supports Corepack.
- For
bun, tell the user Bun is required for this project and ask before installing it.
- Do not switch package managers just because another one is installed; mixing lockfiles causes avoidable dependency drift.
If Node.js Is Missing
If node --version fails, do not attempt to install @uclaw/sdk yet. Explain that UClaw's SDK is a TypeScript/JavaScript package and needs a Node.js-compatible runtime first.
Use this industry-standard decision tree:
If the user is inside an existing project with a documented Node version, follow the project's version file or docs first:
.nvmrc
.node-version
.tool-versions
package.json engines.node
If there is no project standard, recommend an LTS Node.js installation through a user-level version manager such as fnm or nvm. This avoids changing system Node globally and makes project versions reproducible.
Ask the user for confirmation before installing runtime tooling. Installing Node.js changes the user's machine environment and may require shell changes, so it should not be done silently.
After Node.js is installed, restart or refresh the terminal session, then rerun:
node --version
npm --version
Only continue to SDK installation after Node.js and the selected package manager are available.
When giving the user instructions, keep them practical:
I cannot install @uclaw/sdk yet because this project does not have a working Node.js runtime. The safest path is to install an LTS Node version with a user-level version manager such as fnm or nvm, then rerun the environment check. After Node is available, I can install @uclaw/sdk with the project's package manager.
Install The SDK
Run exactly one install command based on the package manager selected above:
npm install @uclaw/sdk
pnpm add @uclaw/sdk
bun add @uclaw/sdk
yarn add @uclaw/sdk
After installing, preserve the project's existing lockfile and package manager conventions.
Configure UCLAW_API_KEY
UClaw server-side code authenticates with UCLAW_API_KEY. Guide the user to create or update a project-local .env file.
Check whether .env already exists and whether .gitignore ignores it.
If .env is not ignored, add this line to .gitignore before the user stores the key:
.env
Tell the user to open .env locally and add:
UCLAW_API_KEY=replace_with_your_key
Make clear that the user should replace the placeholder locally and should not paste the real key into chat.
If the project already has an established local environment file convention, such as .env.local in a Next.js app, follow that convention only if it is already in use and ignored by git. Otherwise, use .env.
For plain Node.js scripts, ensure the app loads .env before reading process.env.UCLAW_API_KEY. Use the project's existing env-loading pattern if present. If there is no existing pattern, prefer the runtime/framework built-in env-file support when available; otherwise use a minimal dependency such as dotenv.
Do not suggest global shell exports like:
export UCLAW_API_KEY=...
Global exports leak across projects and are harder to audit or rotate. A project-local .env keeps the secret scoped to the app that needs it.
Server-Side AppClient Usage
Use AppClient in server-side scripts, API routes, workers, or background jobs.
import { AppClient } from "@uclaw/sdk";
const appId = "my-product-dev";
const app = new AppClient({
apiKey: process.env.UCLAW_API_KEY,
appId,
});
// Configure an agent with specific capabilities and custom extensions
const agent = await app.agents.create({
title: "Dev Helper Agent",
config: {
modelTier: "capable", // Use high-performance model for complex tasks
instructions: "You are a development helper. You can read/write files and run bash scripts.",
capabilities: [
"read", // Allows file read tools: read, list, find, grep
"write", // Allows file write tools: write, edit, delete
"execute", // Allows bash execution in workspace and the execute tool
"network", // Allows outgoing network requests from execute code
"secret", // Allows secrets replacement and management
"browser", // Allows Chrome browser tools via CDP
],
extensions: [
{
name: "custom_fetch_api",
description: "Fetch data from an API and print it to workspace",
parameters: {
type: "object",
properties: {
url: { type: "string", description: "The API endpoint URL" },
},
required: ["url"],
},
code: `async (args) => {
// Can call fetch because "network" capability is enabled
const res = await fetch(args.url);
const data = await res.json();
// Write to state using workspace tools
await state.writeFile("api_response.json", JSON.stringify(data, null, 2));
return "Saved API response to api_response.json";
}`,
},
],
},
});
const run = await agent.run("Fetch and save users from https://jsonplaceholder.typicode.com/users");
for await (const event of run.stream()) {
if (event.type === "text-delta" && event.delta) {
process.stdout.write(event.delta);
}
}
Common server-side APIs:
app.generateText(prompt, options) generates a complete text response.
app.streamText(prompt, options) streams text deltas.
app.agents.create(input) creates a stateful agent session.
app.agents.list() lists existing agent sessions.
app.agents.get(agentId) returns an AgentClient.
agent.run(input) starts a run.
run.stream() streams run events.
run.wait(options) waits for a target run status.
agent.updateConfig(patch) updates agent configuration.
app.secrets.add(key, value, options) stores a secret for agent/app use.
app.secrets.list() lists configured secret names.
app.secrets.remove(key) removes a secret.
Next.js Route Handler For Client Tokens
Browser code must not receive the master API key. For React hooks, add a server route that exchanges the server-side key for short-lived client tokens.
In a Next.js App Router project, create app/api/uclaw/[...all]/route.ts:
import { AppClient } from "@uclaw/sdk";
const appId = "my-product-dev";
const app = new AppClient({
apiKey: process.env.UCLAW_API_KEY,
appId,
});
export const POST = (request: Request) => app.handler(request);
This automatically serves POST /api/uclaw/client-tokens.
If the project uses a different framework, keep the same architecture:
- A server-only endpoint owns
UCLAW_API_KEY.
- Browser code calls that endpoint for short-lived client tokens.
- The master API key never crosses into client-side code.
- The server and browser hooks use the same explicit
appId for the intended app namespace.
React Hooks Usage
Use @uclaw/sdk/react in browser components after the client-token route exists.
useAgent({ agentId }) returns a chat field that follows the AI SDK useChat return shape. Treat it as the chat controller for the active UClaw agent:
- Read
chat.messages to render the conversation.
- Read
chat.status and chat.error to render streaming, ready, and error states.
- Call
chat.sendMessage({ role: "user", parts: [{ type: "text", text: ... }] }) to submit a user message.
- Call
chat.regenerate(...), chat.stop(), chat.clearError(), chat.resumeStream(), or chat.setMessages(...) when building richer chat controls.
- For tool workflows, use the tool-result helpers exposed by the AI SDK-compatible return object, such as
chat.addToolResult(...), when present in the installed SDK version.
Reference: AI SDK useChat returns documentation: https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat#returns
"use client";
import { useApp, useAgent } from "@uclaw/sdk/react";
import { useState } from "react";
const appId = "my-product-dev";
export function ChatApp() {
const [activeAgentId, setActiveAgentId] = useState<string | null>(null);
const { agents, createAgent, status } = useApp({ appId });
const handleCreate = async () => {
const agent = await createAgent({ title: "New Assistant" });
setActiveAgentId(agent.id);
};
return (
<div>
<button disabled={status !== "connected"}>
New Chat
</button>
{agents.map((agent) => (
<button key={agent.id} => setActiveAgentId(agent.id)}>
{agent.title}
</button>
))}
{activeAgentId && <ChatPane agentId={activeAgentId} />}
</div>
);
}
function ChatPane({ agentId }: { agentId: string }) {
const [input, setInput] = useState("");
const { chat, status } = useAgent({ appId, agentId });
const handleSend = (event: React.FormEvent) => {
event.preventDefault();
chat.sendMessage({
role: "user",
parts: [{ type: "text", text: input }],
});
setInput("");
};
return (
<div>
<p>Connection: {status}</p>
<div>
{chat.messages.map((message) => (
<p key={message.id}>
{message.role}: {message.parts.map((part) => part.text).join("")}
</p>
))}
</div>
<form
<input value={input} => setInput(event.target.value)} />
<button type="submit">Send</button>
</form>
</div>
);
}
Troubleshooting
UCLAW_API_KEY is undefined: confirm .env exists in the project root, is loaded by the server runtime, and contains UCLAW_API_KEY=....
- Browser requests fail for client tokens: confirm the server route exists at
/api/uclaw/client-tokens and that the master API key is only read server-side.
- Package install fails: re-check the selected package manager and lockfile. Do not mix npm, pnpm, bun, and yarn lockfiles casually.
- React hook connection stays disconnected: verify the token endpoint returns successfully and that the app is running against the expected
appId.
- TypeScript cannot resolve
@uclaw/sdk: confirm the package is installed in the same workspace/package where the source file is compiled.
Reference Links
1---2name: uclaw-sdk3description: Use this skill for building, installing, or configuring AI agents and agentic apps with the UClaw TypeScript SDK (@uclaw/sdk). Apply it when a user works with UClaw, evaluates it for an agent/AI app in JavaScript or TypeScript, or needs help with @uclaw/sdk setup, agent sessions, API keys, and secure local configuration.4---56# UClaw SDK Skill78## Overview910Use this skill to help users install and use `@uclaw/sdk`, the official TypeScript SDK for UClaw. UClaw provides a managed runtime for stateful AI agents, so users can build agentic applications without managing WebSocket connections, session persistence, or sandbox execution infrastructure themselves.1112Prefer the production SDK package, `@uclaw/sdk`. The `@uclaw/cli` package is experimental and for internal testing only, so do not recommend it for normal user workflows unless the user specifically asks about the CLI and accepts the risk.1314## Pre-work Technical Decisions & Architecture Alignment1516Before writing code or configuring UClaw agents/applications, you must align on the following five technical decisions with the user. If they are not specified, ask or suggest defaults based on the following guidelines:17181. **Scenario Target (Server-Side vs Frontend)**:19 - **Server-Side**: Run UClaw's `AppClient` in server scripts, APIs, background jobs, or workers. Requires `UCLAW_API_KEY` on the server (never leaked to browser).20 - **Frontend**: Connect to agent sessions in browser components using React hooks (`@uclaw/sdk/react` such as `useApp` or `useAgent`). Secure this by setting up a token exchange server route (e.g. `/api/uclaw/client-tokens`) that exchanges `UCLAW_API_KEY` for short-lived client tokens.212. **App Identity & Data Boundary**:22 - Choose an explicit `appId` for each product, project, tenant, or environment before creating agents.23 - Treat `appId` as the real data isolation boundary for agents, history, workspace state, and secrets. `UCLAW_API_KEY` authenticates the account/request, but it does not create a fresh data namespace by itself.24 - Avoid using `appId: "default"` in new projects unless the user intentionally wants to connect to the account's existing default app data. Reusing `default` can reveal or continue historical agents from previous experiments.25 - Rotating or changing the API key does not isolate data if the code keeps using the same `appId`.26 - Use stable, descriptive IDs such as `my-product-dev`, `my-product-prod`, or `customer-portal-staging`, and pass the same `appId` consistently to server `AppClient`, token routes, `useApp`, and `useAgent`.273. **Agent Orchestration**:28 - **Global Unique Agent**: A single agent session. Ideal for single-user stateless utilities or simple one-off tasks where user data is ephemeral.29 - **Multiple Named Agents**: Multiple distinct agent sessions (tracked via unique IDs/titles). Ideal for persistent multi-chat interfaces, multi-user systems, or separate projects.30 - **App-Agent Hierarchy**: The parent application layer manages a directory/collection of distinct agent sessions (listing, creating, and deleting agents via `useApp` or `AppClient`). Ideal when the application needs to dynamically spawn and maintain separate persistent chats/agents for different users or contexts.314. **Model Selection**:32 - Determine the provider and performance level required.33 - Configure using `modelProvider` (e.g., `"openai"`, `"anthropic"`, `"deepseek"`) and `modelTier: "fast" | "balanced" | "capable"` (defaults to `"balanced"`). This avoids pinning direct model names (which may go unsupported later) and allows the platform to route to the best available models.34 - Only use `model` (e.g. `"openai/gpt-5.5"`, `"anthropic/claude-opus-4.8"`) as a fallback override if a specific model version is explicitly requested.355. **Capabilities & Extensions**:36 - Select the minimum set of capabilities required:37 - `read`: access to read workspace files (`read`, `list`, `find`, `grep` tools).38 - `write`: access to edit/write/delete workspace files (`write`, `edit`, `delete` tools).39 - `execute`: run code in sandboxed workers (`bash` and `execute` tools).40 - `database`: SQL database access in workspace (`sql` tool).41 - `network`: external network access from execute scripts.42 - `secret`: secrets management (`add_secret`, `list_secrets`, `remove_secret` tools).43 - `browser`: browser scraping/interaction (Chrome CDP browser tool).44 - Configure custom tools under `extensions` using the `ExtensionDefinition` format for custom execution tasks.4546## When To Use This Skill4748Use this skill when the user asks to:4950- Install or configure UClaw in a JavaScript, TypeScript, React, or Next.js project.51- Create, list, rename, delete, or run UClaw agent sessions.52- Stream agent responses or generate text with `AppClient`.53- Configure `/api/uclaw/client-tokens` for browser-side React hooks.54- Use `@uclaw/sdk/react` hooks such as `useApp` or `useAgent`.55- Manage UClaw secrets through the SDK.56- Fix SDK setup issues involving Node.js, npm, pnpm, bun, `.env`, or `UCLAW_API_KEY`.5758## Working Principles5960- Keep `UCLAW_API_KEY` server-side. Never place it in browser code, React client components, public bundles, or frontend environment variables.61- Do not confuse authentication with data isolation: `UCLAW_API_KEY` authenticates access, while `appId` selects the app data namespace.62- Always choose and document an explicit `appId` for new projects. Do not default to `appId: "default"` unless the user knowingly wants to reuse the account's existing default app history.63- Store `UCLAW_API_KEY` in the project-local `.env` file, not in global shell files such as `~/.zshrc`, `~/.bashrc`, or machine-wide environment settings.64- Never ask the user to paste an API key into chat. Give local terminal instructions that let the user edit `.env` themselves.65- Install `@uclaw/sdk` into the user's project. Do not install it globally.66- Choose the user's existing package manager from project evidence instead of defaulting to `npm`.67- If Node.js is missing, treat that as an environment prerequisite, not as permission to silently install system software.6869## Environment Check Workflow7071Before using UClaw functionality in a project, check the local JavaScript environment from the project root.72731. Check for Node.js:7475 ```bash76 node --version77 ```78792. Check available package managers:8081 ```bash82 npm --version83 pnpm --version84 bun --version85 ```8687 It is fine if some commands are missing. Use the ones that exist.88893. Detect the preferred package manager from the project, in this order:90 - `package.json` `packageManager` field, if present.91 - Lockfiles:92 - `pnpm-lock.yaml` -> `pnpm`93 - `bun.lock` or `bun.lockb` -> `bun`94 - `package-lock.json` or `npm-shrinkwrap.json` -> `npm`95 - `yarn.lock` -> `yarn`96 - Existing scripts or repo docs that consistently use one package manager.97 - If no evidence exists, use `npm` because it ships with Node.js.98994. If a package manager is implied but missing:100 - For `pnpm` or `yarn`, prefer `corepack enable` when the installed Node version supports Corepack.101 - For `bun`, tell the user Bun is required for this project and ask before installing it.102 - Do not switch package managers just because another one is installed; mixing lockfiles causes avoidable dependency drift.103104## If Node.js Is Missing105106If `node --version` fails, do not attempt to install `@uclaw/sdk` yet. Explain that UClaw's SDK is a TypeScript/JavaScript package and needs a Node.js-compatible runtime first.107108Use this industry-standard decision tree:1091101. If the user is inside an existing project with a documented Node version, follow the project's version file or docs first:111 - `.nvmrc`112 - `.node-version`113 - `.tool-versions`114 - `package.json` `engines.node`1151162. If there is no project standard, recommend an LTS Node.js installation through a user-level version manager such as fnm or nvm. This avoids changing system Node globally and makes project versions reproducible.1171183. Ask the user for confirmation before installing runtime tooling. Installing Node.js changes the user's machine environment and may require shell changes, so it should not be done silently.1191204. After Node.js is installed, restart or refresh the terminal session, then rerun:121122 ```bash123 node --version124 npm --version125 ```1261275. Only continue to SDK installation after Node.js and the selected package manager are available.128129When giving the user instructions, keep them practical:130131```text132I cannot install @uclaw/sdk yet because this project does not have a working Node.js runtime. The safest path is to install an LTS Node version with a user-level version manager such as fnm or nvm, then rerun the environment check. After Node is available, I can install @uclaw/sdk with the project's package manager.133```134135## Install The SDK136137Run exactly one install command based on the package manager selected above:138139```bash140npm install @uclaw/sdk141```142143```bash144pnpm add @uclaw/sdk145```146147```bash148bun add @uclaw/sdk149```150151```bash152yarn add @uclaw/sdk153```154155After installing, preserve the project's existing lockfile and package manager conventions.156157## Configure UCLAW_API_KEY158159UClaw server-side code authenticates with `UCLAW_API_KEY`. Guide the user to create or update a project-local `.env` file.1601611. Check whether `.env` already exists and whether `.gitignore` ignores it.1621632. If `.env` is not ignored, add this line to `.gitignore` before the user stores the key:164165 ```gitignore166 .env167 ```1681693. Tell the user to open `.env` locally and add:170171 ```dotenv172 UCLAW_API_KEY=replace_with_your_key173 ```1741754. Make clear that the user should replace the placeholder locally and should not paste the real key into chat.1761775. If the project already has an established local environment file convention, such as `.env.local` in a Next.js app, follow that convention only if it is already in use and ignored by git. Otherwise, use `.env`.1781796. For plain Node.js scripts, ensure the app loads `.env` before reading `process.env.UCLAW_API_KEY`. Use the project's existing env-loading pattern if present. If there is no existing pattern, prefer the runtime/framework built-in env-file support when available; otherwise use a minimal dependency such as `dotenv`.180181Do not suggest global shell exports like:182183```bash184export UCLAW_API_KEY=...185```186187Global exports leak across projects and are harder to audit or rotate. A project-local `.env` keeps the secret scoped to the app that needs it.188189## Server-Side AppClient Usage190191Use `AppClient` in server-side scripts, API routes, workers, or background jobs.192193```typescript194import { AppClient } from "@uclaw/sdk";195196const appId = "my-product-dev";197198const app = new AppClient({199 apiKey: process.env.UCLAW_API_KEY,200 appId,201});202203// Configure an agent with specific capabilities and custom extensions204const agent = await app.agents.create({205 title: "Dev Helper Agent",206 config: {207 modelTier: "capable", // Use high-performance model for complex tasks208 instructions: "You are a development helper. You can read/write files and run bash scripts.",209 capabilities: [210 "read", // Allows file read tools: read, list, find, grep211 "write", // Allows file write tools: write, edit, delete212 "execute", // Allows bash execution in workspace and the execute tool213 "network", // Allows outgoing network requests from execute code214 "secret", // Allows secrets replacement and management215 "browser", // Allows Chrome browser tools via CDP216 ],217 extensions: [218 {219 name: "custom_fetch_api",220 description: "Fetch data from an API and print it to workspace",221 parameters: {222 type: "object",223 properties: {224 url: { type: "string", description: "The API endpoint URL" },225 },226 required: ["url"],227 },228 code: `async (args) => {229 // Can call fetch because "network" capability is enabled230 const res = await fetch(args.url);231 const data = await res.json();232 // Write to state using workspace tools233 await state.writeFile("api_response.json", JSON.stringify(data, null, 2));234 return "Saved API response to api_response.json";235 }`,236 },237 ],238 },239});240241const run = await agent.run("Fetch and save users from https://jsonplaceholder.typicode.com/users");242243for await (const event of run.stream()) {244 if (event.type === "text-delta" && event.delta) {245 process.stdout.write(event.delta);246 }247}248```249250Common server-side APIs:251252- `app.generateText(prompt, options)` generates a complete text response.253- `app.streamText(prompt, options)` streams text deltas.254- `app.agents.create(input)` creates a stateful agent session.255- `app.agents.list()` lists existing agent sessions.256- `app.agents.get(agentId)` returns an `AgentClient`.257- `agent.run(input)` starts a run.258- `run.stream()` streams run events.259- `run.wait(options)` waits for a target run status.260- `agent.updateConfig(patch)` updates agent configuration.261- `app.secrets.add(key, value, options)` stores a secret for agent/app use.262- `app.secrets.list()` lists configured secret names.263- `app.secrets.remove(key)` removes a secret.264265## Next.js Route Handler For Client Tokens266267Browser code must not receive the master API key. For React hooks, add a server route that exchanges the server-side key for short-lived client tokens.268269In a Next.js App Router project, create `app/api/uclaw/[...all]/route.ts`:270271```typescript272import { AppClient } from "@uclaw/sdk";273274const appId = "my-product-dev";275276const app = new AppClient({277 apiKey: process.env.UCLAW_API_KEY,278 appId,279});280281export const POST = (request: Request) => app.handler(request);282```283284This automatically serves `POST /api/uclaw/client-tokens`.285286If the project uses a different framework, keep the same architecture:287288- A server-only endpoint owns `UCLAW_API_KEY`.289- Browser code calls that endpoint for short-lived client tokens.290- The master API key never crosses into client-side code.291- The server and browser hooks use the same explicit `appId` for the intended app namespace.292293## React Hooks Usage294295Use `@uclaw/sdk/react` in browser components after the client-token route exists.296297`useAgent({ agentId })` returns a `chat` field that follows the AI SDK `useChat` return shape. Treat it as the chat controller for the active UClaw agent:298299- Read `chat.messages` to render the conversation.300- Read `chat.status` and `chat.error` to render streaming, ready, and error states.301- Call `chat.sendMessage({ role: "user", parts: [{ type: "text", text: ... }] })` to submit a user message.302- Call `chat.regenerate(...)`, `chat.stop()`, `chat.clearError()`, `chat.resumeStream()`, or `chat.setMessages(...)` when building richer chat controls.303- For tool workflows, use the tool-result helpers exposed by the AI SDK-compatible return object, such as `chat.addToolResult(...)`, when present in the installed SDK version.304305Reference: AI SDK `useChat` returns documentation: https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat#returns306307```tsx308"use client";309310import { useApp, useAgent } from "@uclaw/sdk/react";311import { useState } from "react";312313const appId = "my-product-dev";314315export function ChatApp() {316 const [activeAgentId, setActiveAgentId] = useState<string | null>(null);317 const { agents, createAgent, status } = useApp({ appId });318319 const handleCreate = async () => {320 const agent = await createAgent({ title: "New Assistant" });321 setActiveAgentId(agent.id);322 };323324 return (325 <div>326 <button onClick={handleCreate} disabled={status !== "connected"}>327 New Chat328 </button>329330 {agents.map((agent) => (331 <button key={agent.id} onClick={() => setActiveAgentId(agent.id)}>332 {agent.title}333 </button>334 ))}335336 {activeAgentId && <ChatPane agentId={activeAgentId} />}337 </div>338 );339}340341function ChatPane({ agentId }: { agentId: string }) {342 const [input, setInput] = useState("");343 const { chat, status } = useAgent({ appId, agentId });344345 const handleSend = (event: React.FormEvent) => {346 event.preventDefault();347 chat.sendMessage({348 role: "user",349 parts: [{ type: "text", text: input }],350 });351 setInput("");352 };353354 return (355 <div>356 <p>Connection: {status}</p>357 <div>358 {chat.messages.map((message) => (359 <p key={message.id}>360 {message.role}: {message.parts.map((part) => part.text).join("")}361 </p>362 ))}363 </div>364 <form onSubmit={handleSend}>365 <input value={input} onChange={(event) => setInput(event.target.value)} />366 <button type="submit">Send</button>367 </form>368 </div>369 );370}371```372373## Troubleshooting374375- `UCLAW_API_KEY` is undefined: confirm `.env` exists in the project root, is loaded by the server runtime, and contains `UCLAW_API_KEY=...`.376- Browser requests fail for client tokens: confirm the server route exists at `/api/uclaw/client-tokens` and that the master API key is only read server-side.377- Package install fails: re-check the selected package manager and lockfile. Do not mix npm, pnpm, bun, and yarn lockfiles casually.378- React hook connection stays disconnected: verify the token endpoint returns successfully and that the app is running against the expected `appId`.379- TypeScript cannot resolve `@uclaw/sdk`: confirm the package is installed in the same workspace/package where the source file is compiled.380381## Reference Links382383- UClaw console and keys: https://uclaw.dev384- UClaw docs: https://uclaw.dev/docs385- SDK package: `@uclaw/sdk`