> ## Documentation Index
> Fetch the complete documentation index at: https://docs.skybridge.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# useFileResource

> Read, watch and save the file a ChatGPT file entrypoint opened

A [file viewer](/api-reference/register-file-viewer.md) opens your view on a file the user picked in ChatGPT desktop. ChatGPT never gives the view the file's path: the tool input carries an opaque `file.resourceUri` instead. `useFileResource` reads that resource, re-reads it whenever the host reports a change, and saves edits back.

> [!NOTE]
>
> Reading uses the standard MCP `resources/read`. Text or blob selection, change subscriptions and writes come from the [OpenAI MCP extensions](https://github.com/openai/mcp-extensions/blob/main/docs/spec.md), so only **ChatGPT** desktop supports them.

## Example

A part editor loads the opened file as text and saves the user's edits.

```tsx theme={null}
import { useState } from "react";
import { useFileResource } from "skybridge/web";
import { useToolInfo } from "../helpers.js";

function PartEditor() {
  const { input } = useToolInfo<"open-part">();
  const { data, isLoading, write } = useFileResource(input.file?.resourceUri, {
    representation: "text",
  });
  const [draft, setDraft] = useState<string>();
  const [conflict, setConflict] = useState(false);

  if (isLoading || !data || !("text" in data)) {
    return null;
  }
  const save = async () => {
    const result = await write({ text: draft ?? data.text });
    setConflict(result.outcome === "conflict");
  };
  const discardEdits = () => {
    setDraft(undefined);
    setConflict(false);
  };
  return (
    <>
      <textarea value={draft ?? data.text} onChange={(e) => setDraft(e.target.value)} />
      <button disabled={!data.writable} onClick={save}>Save</button>
      {conflict && (
        <p>
          The file changed on disk. <button onClick={discardEdits}>Load the latest version</button>
        </p>
      )}
    </>
  );
}
```

## Parameters

### `uri`

```tsx theme={null}
uri: string | undefined;
```

The resource to read, usually `file.resourceUri` from the tool input. Pass `undefined` to do nothing, for example when the view also opens outside a file entrypoint.

### `options`

```tsx theme={null}
options?: { representation?: "text" | "blob" };
```

Asks ChatGPT to return the contents as text or as a base64 blob. Without it, ChatGPT picks one, so handle both.

The hook subscribes to changes only on hosts that advertise `openai/resource`. Elsewhere it reads the resource once.

## Returns

### `data`

```tsx theme={null}
data: ({ text: string } | { blob: string }) & {
  mimeType?: string;
  writable: boolean;
  etag?: string;
} | undefined;
```

The current contents. `writable` tells whether ChatGPT accepts writes, and `etag` identifies this version. `undefined` until the first read completes.

### `isLoading`, `error`

`isLoading` is `true` until the first read of `uri` completes. Re-reads after a change keep the previous `data` on screen until the new contents arrive. `error` holds the last read failure, and `data` keeps the last contents that loaded.

### `write`

```tsx theme={null}
write: (content: { text: string } | { blob: string }) =>
  Promise<
    | { outcome: "saved"; etag: string }
    | { outcome: "conflict"; etag: string }
    | { outcome: "too-large"; maxBytes: number }
  >;
```

Saves new contents through `openai/resources/write`, with the current `etag` as `ifMatch`. When ChatGPT returned no `etag`, the write has no version check. When the file changed since the last read, ChatGPT answers `conflict` instead of overwriting it, and the hook re-reads the latest version into `data`. On `saved`, `data` takes the new contents and etag. It rejects with a `NotSupportedError` when the host doesn't advertise `openai/resource`, `data` isn't loaded yet, or `data.writable` is `false`.

> **[registerTool](/api-reference/register-tool.md#openai)**
>
> Add a file entrypoint to a tool

> **[useOpenFile](/api-reference/use-open-file.md)**
>
> Ask ChatGPT to open another local file


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.