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

# Organise

> Manage folders and upload files into your xysq vault from Python.

The `organise` namespace gives you programmatic access to the folder tree and file uploads that the [Organise dashboard](/features/organise) exposes. Folders, renames, moves, deletes, and direct file uploads all run through the same backend the dashboard uses — anything you push through the SDK shows up in `app.xysq.ai` instantly, and is indexed into [memory](/sdk/memory) once extraction finishes.

```python theme={"dark"}
from xysq import Xysq

with Xysq() as client:
    folder = client.organise.create_folder("Notes")
    file = client.organise.upload_file("./meeting.md", folder_id=folder.id)
    client.organise.wait_for_file(file.asset_id)
    # File content is now searchable via client.memory.surface(...)
```

<Info>
  Uploaded files become part of your memory once extraction completes. Use `client.memory.surface()` or `client.memory.synthesize()` to query their contents — no separate Organise-specific search is needed.
</Info>

## list\_folders

List every folder in the vault. Returns a flat array — use each folder's `parent_id` to reconstruct the tree.

```python theme={"dark"}
folders = client.organise.list_folders()

for f in folders:
    indent = "  " * (0 if f.parent_id is None else 1)
    print(f"{indent}{f.name} ({f.id})")
```

**Returns:** `list[Folder]` — each with `id`, `name`, `parent_id`, `path`, `is_system`, `chat_id`, `owner_kind`, `owner_id`

<Note>
  The system `/Chats/` folder appears in this list with `is_system=True`. You can't create folders inside it or upload files directly into it — those slots are managed by Chat.
</Note>

## get\_folder

Fetch one folder plus its direct subfolders.

```python theme={"dark"}
folder, children = client.organise.get_folder(folder_id)
print(folder.name)
for c in children:
    print(f"  - {c.name}")
```

**Parameters**

| Parameter   | Type  | Default  | Description |
| ----------- | ----- | -------- | ----------- |
| `folder_id` | `str` | required | Folder UUID |

**Returns:** `tuple[Folder, list[Folder]]` — the folder and its child folders. Files inside the folder are not returned by this call.

## create\_folder

Create a new folder. Omit `parent_id` to nest directly under the vault root.

```python theme={"dark"}
notes = client.organise.create_folder("Notes")
sub = client.organise.create_folder("Q1", parent_id=notes.id)
```

**Parameters**

| Parameter   | Type  | Default  | Description                             |
| ----------- | ----- | -------- | --------------------------------------- |
| `name`      | `str` | required | 1–255 chars; cannot contain `/`         |
| `parent_id` | `str` | `None`   | Parent folder UUID; `None` = vault root |

**Returns:** `Folder`

Names must be unique among siblings. A collision raises `XysqError`.

## rename\_folder

Rename a folder. System folders (root, `/Chats/`) cannot be renamed.

```python theme={"dark"}
client.organise.rename_folder(folder.id, "Archive")
```

## move\_folder

Move a folder under a new parent. The folder and everything under it move together.

```python theme={"dark"}
client.organise.move_folder(folder.id, new_parent_id=archive.id)
```

You can't move a folder into itself, into one of its own descendants, or into the system `/Chats/` folder.

## delete\_folder

Delete a folder and every subfolder + file inside it. Irreversible.

```python theme={"dark"}
removed_count = client.organise.delete_folder(folder.id)
print(f"Removed {removed_count} files")

# Also purge what xysq extracted from those files
client.organise.delete_folder(folder.id, forget_memories=True)
```

**Parameters**

| Parameter         | Type   | Default  | Description                                      |
| ----------------- | ------ | -------- | ------------------------------------------------ |
| `folder_id`       | `str`  | required | Folder UUID                                      |
| `forget_memories` | `bool` | `False`  | Also remove extracted facts from the recall bank |

**Returns:** `int` — number of files removed by the cascade.

<Warning>
  Confirm with the user before calling this on anything non-empty. There is no trash.
</Warning>

## upload\_file

Upload one file into a folder. Two call styles — pick one:

```python theme={"dark"}
# From disk — filename and MIME inferred
file = client.organise.upload_file("./release-notes.md", folder_id=folder.id)

# From in-memory bytes or string — filename + mime_type required
file = client.organise.upload_file(
    content="# Release Notes\n\nv1.2.0 ships dark mode.",
    filename="release-notes.md",
    mime_type="text/markdown",
    folder_id=folder.id,
)
```

**Parameters**

| Parameter   | Type                | Default | Description                                                     |
| ----------- | ------------------- | ------- | --------------------------------------------------------------- |
| `path`      | `str` \| `PathLike` | `None`  | Read bytes from disk. Mutually exclusive with `content`         |
| `content`   | `bytes` \| `str`    | `None`  | In-memory payload. Requires `filename` + `mime_type`            |
| `filename`  | `str`               | `None`  | Display name. Defaults to the file's basename when using `path` |
| `mime_type` | `str`               | `None`  | MIME type. Inferred from extension when using `path`            |
| `folder_id` | `str`               | `None`  | Destination folder. `None` = vault root                         |

**Returns:** `OrganiseFile` — `asset_id`, `filename` (auto-renamed on collision), `folder_id`, `mime_type`, `size_bytes`, `extraction_status`

**Limits**

|                     | Limit                                                                                       |
| ------------------- | ------------------------------------------------------------------------------------------- |
| File size           | 10 MB                                                                                       |
| MIME types          | `text/markdown`, `text/plain`, `application/pdf`, `application/json`, `text/csv`, `image/*` |
| Filename collisions | Auto-renamed with `(N)` suffix                                                              |

Files outside the allow-list and oversized payloads raise `ValueError` **before** any bytes leave the process.

## file\_status

Poll an uploaded file's extraction status.

```python theme={"dark"}
status = client.organise.file_status(file.asset_id)
print(status.extraction_status)  # "pending" | "processing" | "ready" | "failed"
```

**Returns:** `FileStatus` — `asset_id`, `extraction_status`, `error_msg`

## wait\_for\_file

Block until extraction finishes or times out.

```python theme={"dark"}
final = client.organise.wait_for_file(file.asset_id, timeout=60.0)

if final.extraction_status == "ready":
    # Contents are now searchable via client.memory.surface(...)
    memories = client.memory.surface("release notes")
```

**Parameters**

| Parameter  | Type    | Default  | Description              |
| ---------- | ------- | -------- | ------------------------ |
| `asset_id` | `str`   | required | File to poll             |
| `timeout`  | `float` | `60.0`   | Maximum seconds to wait  |
| `interval` | `float` | `1.0`    | Poll interval in seconds |

Use `wait_for_file()` in pipelines or tests where you need the file's content searchable before continuing.

## Team Organise

Wrap the client in `team(team_id)` to operate on a team's Organise vault instead of your personal one. Permissions follow your [team role](/sdk/teams) — `ro` members can list and download, `rw` and above can upload, rename, move, and delete.

```python theme={"dark"}
with Xysq() as client:
    team = client.team("team-uuid")
    folders = team.organise.list_folders()
    team.organise.upload_file("./report.pdf", folder_id=folders[0].id)
```

***

## Full example

```python theme={"dark"}
from xysq import Xysq

with Xysq() as client:
    # Set up a folder
    folder = client.organise.create_folder("ADRs")

    # Upload several markdown decision records
    for path in ["./adr-01.md", "./adr-02.md", "./adr-03.md"]:
        file = client.organise.upload_file(path, folder_id=folder.id)
        client.organise.wait_for_file(file.asset_id, timeout=60.0)
        print(f"Indexed: {file.filename}")

    # Now query them through memory — Organise content joins the same recall layer
    result = client.memory.synthesize(
        "What did we decide about health check endpoints?"
    )
    print(result.answer)
```

***

## Related

<CardGroup cols={2}>
  <Card title="Memory" icon="brain" href="/sdk/memory">
    Uploaded files surface here once extraction completes
  </Card>

  <Card title="Organise feature" icon="folder-tree" href="/features/organise">
    Overview of the folder tree, the dashboard, and the `/Chats/` system folder
  </Card>
</CardGroup>
