# Hooks
URL: /docs/runtimes/opencode/hooks
Permissions, questions, session state, runtime extras.
OpenCode-specific React hooks for interacting with the running session. All hooks must be used inside the runtime context (a tree wrapped in `AssistantRuntimeProvider` from a `useOpenCodeRuntime` setup).
## Permissions \[#permissions]
OpenCode pauses tool execution to ask the user for permission (e.g. running shell commands, writing files). `useOpenCodePermissions` returns the pending permission requests and a reply function:
```tsx
import { useOpenCodePermissions } from "@assistant-ui/react-opencode";
function PermissionPrompt() {
const { pending, reply } = useOpenCodePermissions();
return pending.map((req) => (
));
}
```
Return shape:
| Field | Type | Description |
| --------- | --------------------------------- | ---------------------------------------- |
| `pending` | `OpenCodePermissionRequest[]` | Permission requests waiting for a reply. |
| `reply` | `(id, response) => Promise` | Send a reply for a pending permission. |
Reply values:
| Reply | Meaning |
| ---------- | ------------------------------------------------ |
| `"once"` | Approve this single permission request. |
| `"always"` | Approve this permission and remember the choice. |
| `"reject"` | Deny the permission; the tool call is cancelled. |
## Questions \[#questions]
OpenCode can ask interactive questions during a run. `useOpenCodeQuestions` returns the pending questions as an array:
```tsx
import {
useOpenCodeQuestions,
useOpenCodeRuntimeExtras,
} from "@assistant-ui/react-opencode";
function QuestionPrompt() {
const questions = useOpenCodeQuestions();
const { replyToQuestion, rejectQuestion } = useOpenCodeRuntimeExtras();
return questions.map((req) => (
{req.text}
));
}
```
To reply, use `replyToQuestion(id, answers)` or `rejectQuestion(id)` from [`useOpenCodeRuntimeExtras`](#runtime-extras).
## Session \[#session]
`useOpenCodeSession` returns the current OpenCode `Session` object (server-side session metadata):
```tsx
import { useOpenCodeSession } from "@assistant-ui/react-opencode";
function SessionInfo() {
const session = useOpenCodeSession();
if (!session) return null;
return
Session: {session.id}
;
}
```
## Thread state \[#thread-state]
`useOpenCodeThreadState` returns the full projected thread state (messages, run state, interactions, sync metadata). Use it for advanced custom views; most apps don't need it.
```tsx
import { useOpenCodeThreadState } from "@assistant-ui/react-opencode";
function RunStatus() {
const state = useOpenCodeThreadState();
return
Run: {state.runState.type}
;
}
```
The returned `OpenCodeThreadState` includes:
* `sessionId`, `session`, `sessionStatus`, `loadState`, `runState`
* `messageOrder`, `messagesById`, `pendingUserMessages`
* `interactions.permissions` (pending + resolved), `interactions.questions` (pending + answered + rejected)
* `unhandledEvents`, `sync` timestamps
You can also pass a selector to read a specific slice:
```tsx
const isStreaming = useOpenCodeThreadState((s) => s.runState.type === "streaming");
```
## Runtime extras \[#runtime-extras]
`useOpenCodeRuntimeExtras` exposes session-level imperative actions:
```tsx
import { useOpenCodeRuntimeExtras } from "@assistant-ui/react-opencode";
function SessionActions() {
const {
fork,
revert,
unrevert,
cancel,
refresh,
replyToPermission,
replyToQuestion,
rejectQuestion,
} = useOpenCodeRuntimeExtras();
// ...
}
```
| Action | Description |
| --------------------------------- | ------------------------------------------------------------------------------- |
| `fork(messageId)` | Create a new session forked from the given message; returns the new session id. |
| `revert(messageId)` | Revert the session to the state at the given message. |
| `unrevert()` | Undo the last revert. |
| `cancel()` | Cancel an in-flight run. |
| `refresh()` | Force re-fetch of session messages. |
| `replyToPermission(id, response)` | Reply to a permission request (`"once"`, `"always"`, `"reject"`). |
| `replyToQuestion(id, answers)` | Answer a pending question. |
| `rejectQuestion(id)` | Reject a pending question. |
`useOpenCodePermissions` and `useOpenCodeQuestions` are sugar over `replyToPermission` / `replyToQuestion` / `rejectQuestion` plus the `pending` slices of state.
## Lower-level building blocks \[#lower-level-building-blocks]
For custom integrations that bypass `useOpenCodeRuntime`:
| Export | Purpose |
| ------------------------------------------------------------ | -------------------------------------------------------------------- |
| `OpenCodeEventSource` | Wraps the OpenCode server's event stream into a typed subscription. |
| `OpenCodeThreadController` | Per-session controller managing message state. |
| `createOpenCodeThreadState`, `reduceOpenCodeThreadState` | Pure state reducers if you want to drive the state machine yourself. |
| `projectOpenCodeThreadMessages` | Project raw OpenCode messages into assistant-ui thread messages. |
| `createOpencodeClient` (re-exported from `@opencode-ai/sdk`) | Build a client with custom config. |
These are only needed for advanced cases; most apps should use `useOpenCodeRuntime` directly.
## Related \[#related]