
# Workspace Tools

`workspace-tools` registers ten tools: seven over the files the reader is looking at, and three over a
command that isn't meant to end. It draws nothing — what it adds shows up wherever tools are offered,
in a conversation's tool picker, in whatever your chat participant calls, and in the browser's own
agent if you also mount [`webmcp`](/extensions/webmcp).

```ts
import { Workbench, FileSystem } from "codelet/workbench";
import { workspaceTools } from "codelet/extensions/workspace-tools";
import { chat } from "codelet/extensions/chat";
import { piAgent } from "codelet/extensions/pi-agent";

new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/index.ts": "export const hello = 1;\n" }),
  extensions: [chat, piAgent(), workspaceTools()],
});
```

## The tools

| Name               | What it does                                                                                               |
| ------------------ | ---------------------------------------------------------------------------------------------------------- |
| `workspace_read`   | A file, as the reader sees it — unsaved edits included — with numbered lines and a window into a long one. |
| `workspace_list`   | Every file and directory, from the root or from a path, to a depth.                                        |
| `workspace_search` | Case-insensitive text across the workspace, narrowed by a glob. The same search the Search view runs.      |
| `workspace_write`  | A whole file, created or replaced.                                                                         |
| `workspace_edit`   | Exact text replaced in place, refusing anything that names more than one spot unless told otherwise.       |
| `workspace_open`   | Shows a file to the reader, at a line. Changes nothing.                                                    |
| `workspace_active` | What the reader is looking at: the file, the caret, the selection, the open tabs.                          |

## A command that doesn't end

A shell tool waits for the line it runs — pi's `bash` does — so a dev server or a watcher would take
the conversation's one shell away for every call after it. These three are the way round that:

| Name              | What it does                                                                                       |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| `bash_background` | Runs a command in a shell of its own and answers with an id, plus whatever it printed in a second. |
| `bash_output`     | What it has printed since the last read, and whether it's still running. `filter` is a regex.      |
| `bash_kill`       | Stops it and closes its tab.                                                                       |

The command keeps running after the answer that started it, in a terminal tab the reader can watch and
stop — a dev server they go on using is worth more than one that dies with the answer. Nothing else
ends it: closing the tab does, and so does stopping this extension.

It needs a shell, which is another extension's: mount [`bash`](/extensions/bash) (and
[`terminal`](/extensions/terminal) to see the tab). A page with two shells names the one it means:

```ts
workspaceTools({ shell: "bash.shell" });
```

## What a write does

A write goes into the same buffer the editor types into, so the change lands in the tab the reader
is in — their cursor stays where it was, and the squiggles and decorations move with the text. Then
it's saved, so the file holds it.

The one exception is a file that already has unsaved changes in it: the write lands, the tab keeps
its dot, and saving is left to the reader. Committing someone's half-finished edit isn't something a
tool call asked for.

::note
`workspace_write`, `workspace_edit` and `bash_background` ask before they run. Turning that off is the
`chat.tools.autoApprove` setting, or the **Chat: Toggle Tool Confirmations** command — the same
switch `pi-agent`'s own tools read.
::

## Alongside pi

[`pi-agent`](/extensions/pi-agent) brings its own `read`, `edit`, `write` and `bash` inside its loop.
Mounting both is fine and common: pi keeps its four, and everything else — another participant, a
`.vsix`, a browser agent — gets these. Mount this one if you want the workbench's files reachable by
whatever is answering, rather than only by pi.

The three background tools used to be `pi-agent`'s, which is why pi's prompt talks about them: it
writes that section only where they're registered, so a page mounting pi alone tells the model not to
start a server rather than pointing it at a tool that isn't there.

## What it doesn't do

- **No delete or rename.** Those are gestures the reader has in the tree, and a page has no bin to
  take a deleted directory out of.
- **No waiting on a command.** A command that finishes belongs to whatever loop is answering —
  pi's `bash` does that. What's here is the case a waiting tool can't cover, and it needs
  [`bash`](/extensions/bash) mounted either way.
