# Workspace (/tools/toolkits/local/workspace)



`Workspace` is a local-machine toolkit scoped to a single `root` directory. Reads (`read`, `list`, `search`) run silently; destructive operations (`write`, `edit`, `move`, `delete`, `shell`) require human confirmation by default through the run's HITL requirements.

## Prerequisites [#prerequisites]

[Create and activate a virtual environment](/sdk/setup), then install:

```shell
uv pip install agno openai
```

The Agent model uses an OpenAI key, separately from any toolkit provider credentials.

## Set OpenAI Key [#set-openai-key]

Set your `OPENAI_API_KEY` as an environment variable. You can get one [from OpenAI](https://platform.openai.com/account/api-keys).

<CodeBlockTabs defaultValue="Mac">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="Mac">
      Mac
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Windows PowerShell">
      Windows PowerShell
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="Mac">
    ```bash
    export OPENAI_API_KEY=sk-***
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Windows PowerShell">
    ```powershell
    $env:OPENAI_API_KEY = "your-openai-api-key"
    ```
  </CodeBlockTab>
</CodeBlockTabs>

## Example [#example]

```python title="cookbook/91_tools/workspace_tools/basic_usage.py"
import tempfile
from pathlib import Path

from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools.workspace import Workspace

# Use a clean tmp directory so the demo doesn't touch real files.
workspace = Path(tempfile.mkdtemp(prefix="workspace_demo_"))
(workspace / "README.md").write_text(
    "# Demo workspace\n\n"
    "This file lives in a tmp directory.\n"
    "The agent below will read it and produce a summary file.\n"
)

agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=[
        Workspace(
            str(workspace),
            allowed=Workspace.ALL_TOOLS,
            confirm=[],
        )
    ],
    markdown=True,
)

if __name__ == "__main__":
    agent.print_response(
        "Read README.md, then write a 2-line summary to NOTES.md. "
        "After that, list the files to confirm both exist."
    )
    print(f"\nWorkspace: {workspace}")
```

This example passes `confirm=[]` to disable confirmation so it runs end-to-end without prompts. For production, leave the defaults on.

## Permission Model [#permission-model]

`allowed` and `confirm` are mutually exclusive partitions of short aliases:

| In list   | Behavior                                                        |
| --------- | --------------------------------------------------------------- |
| `allowed` | Runs silently.                                                  |
| `confirm` | Requires user approval via [HITL](/hitl/overview) pause/resume. |
| neither   | Not registered with the toolkit. The LLM never sees it.         |
| both      | Raises `ValueError`.                                            |

When both lists are `None`, reads auto-pass and writes require confirmation (the safe default). When only one is set, the other defaults to `[]`. Use `Workspace.ALL_TOOLS` to register every tool.

| Alias    | Registered tool  | What it does                              |
| -------- | ---------------- | ----------------------------------------- |
| `read`   | `read_file`      | Read a file (line-numbered).              |
| `list`   | `list_files`     | List a directory (recursive option).      |
| `search` | `search_content` | Recursive content grep.                   |
| `write`  | `write_file`     | Create or overwrite a file (atomic).      |
| `edit`   | `edit_file`      | Replace a substring (with `replace_all`). |
| `move`   | `move_file`      | Move or rename a file.                    |
| `delete` | `delete_file`    | Delete a file.                            |
| `shell`  | `run_command`    | Run a shell command in `root`.            |

<Warning>
  This is a path-scoping boundary, not a process sandbox. Named file operations reject paths outside `root`. `run_command` executes a process with `cwd=root` and does not enforce those path or exclusion checks; it can access other files, environment variables and the network with ordinary process permissions. For untrusted code execution, run the agent inside a real sandbox (container, VM, or [Daytona](/tools/toolkits/others/daytona)).
</Warning>

## Toolkit Params [#toolkit-params]

| Parameter                   | Type                  | Default    | Description                                                                                |
| --------------------------- | --------------------- | ---------- | ------------------------------------------------------------------------------------------ |
| `root`                      | `Optional[str\|Path]` | `cwd`      | Directory all operations are scoped to.                                                    |
| `allowed`                   | `Optional[List[str]]` | `None`     | Aliases that run silently.                                                                 |
| `confirm`                   | `Optional[List[str]]` | `None`     | Aliases that require confirmation.                                                         |
| `require_read_before_write` | `bool`                | `False`    | Block writes/edits/move/delete on existing files until read through this toolkit instance. |
| `max_file_lines`            | `int`                 | `100000`   | Maximum lines `read_file` will load.                                                       |
| `max_file_length`           | `int`                 | `10000000` | Maximum file length (characters) `read_file` will load.                                    |
| `exclude_patterns`          | `Optional[List[str]]` | noise dirs | Patterns excluded from discovery and direct file operations. Pass `[]` to disable.         |

`allow_paths` (`Optional[List[str]]`, default `None`) accepts literal workspace-relative files or directories allowed through exclusions.

Exclusions apply to direct reads, writes, edits, moves and deletes as well as listing/search. Defaults cover noise directories and common credential paths. `allow_paths=["build"]` allows `build/index.html`, while an excluded child such as `build/.env` stays blocked. An explicitly allowed path beneath an excluded directory can be accessed by name even when recursive listing prunes its parent. Shell execution does not use these file exclusions.

## Confirmation Flow [#confirmation-flow]

With aliases in `confirm`, the run pauses when the agent calls a gated tool. This separate example uses default confirmation and a disposable file. Inspect each operation, resolve its requirement, and resume using the response object; no session database is needed:

```python
import tempfile
from pathlib import Path

from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools.workspace import Workspace

approval_root = Path(tempfile.mkdtemp(prefix="workspace_approval_"))
(approval_root / "old.log").write_text("Disposable tutorial log.\n")
approval_agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=[Workspace(approval_root)],
)
run_response = approval_agent.run("Read old.log, then delete it.")

while run_response.is_paused:
    for requirement in run_response.active_requirements:
        if requirement.needs_confirmation:
            print(requirement.tool_execution)
            if input("Approve this operation? [y/N] ").strip().lower() == "y":
                requirement.confirm()
            else:
                requirement.reject()
    run_response = approval_agent.continue_run(
        run_response=run_response,
        requirements=run_response.requirements,
    )
```

See [Workspace with confirmation](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/workspace_tools/workspace_tools_with_confirmation.py) for the full pause/resume example, and [User Confirmation](/hitl/user-confirmation) for the HITL pattern.

## Developer Resources [#developer-resources]

* [Tools source](https://github.com/agno-agi/agno/blob/main/libs/agno/agno/tools/workspace.py)
* [Basic usage](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/workspace_tools/basic_usage.py)
* [With confirmation](https://github.com/agno-agi/agno/blob/main/cookbook/91_tools/workspace_tools/workspace_tools_with_confirmation.py)
* [WorkspaceContextProvider](/context-providers/providers/workspace) wraps this toolkit read-only as a context provider
