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

# Files

> Read, write, delete, and bulk-manage files through the KiwiFS REST API.

## Directory tree

Retrieve the directory tree as a JSON array.

<ParamField query="path" type="string" default="/">
  Root path to list. Omit to list the entire knowledge base.
</ParamField>

```bash theme={null}
curl 'http://localhost:3333/api/kiwi/tree?path=concepts'
```

<ResponseField name="response" type="array">
  Array of tree nodes.
  <ResponseField name="path" type="string">Full path relative to root.</ResponseField>
  <ResponseField name="name" type="string">File or directory name.</ResponseField>
  <ResponseField name="isDir" type="boolean">Whether this node is a directory.</ResponseField>
  <ResponseField name="size" type="integer">File size in bytes (0 for directories).</ResponseField>
  <ResponseField name="children" type="array">Nested tree nodes (directories only).</ResponseField>
</ResponseField>

```json theme={null}
[
  {
    "path": "concepts",
    "name": "concepts",
    "isDir": true,
    "size": 0,
    "children": [
      {"path": "concepts/auth.md", "name": "auth.md", "isDir": false, "size": 1420, "children": null}
    ]
  }
]
```

## Read a file

Retrieve raw markdown content. The response includes an `ETag` header containing the git blob SHA for optimistic locking.

<ParamField query="path" type="string" required>
  File path relative to the knowledge root.
</ParamField>

```bash theme={null}
curl -i 'http://localhost:3333/api/kiwi/file?path=concepts/auth.md'
```

```
HTTP/1.1 200 OK
Content-Type: text/markdown
ETag: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"

# Authentication

OAuth2 + JWT based authentication system...
```

## Read a symlink target

When a path in the knowledge root is a symbolic link, resolve its target without following into arbitrary filesystem paths outside the guard:

```http theme={null}
GET /api/kiwi/readlink?path=link/to/page.md
```

Returns **plain text** body with the symlink target. **`404`** when the path does not exist; **`400`** when the path exists but is not a symlink.

## Write a file

Create or update a file. The request body is raw markdown. KiwiFS creates a git commit for each write.

<ParamField query="path" type="string" required>
  File path relative to the knowledge root.
</ParamField>

<ParamField header="X-Actor" type="string">
  Git commit author attribution (e.g. `agent:my-agent`).
</ParamField>

<ParamField header="X-Provenance" type="string">
  Lineage tracking (e.g. `run:run-249`).
</ParamField>

<ParamField header="If-Match" type="string">
  ETag from a previous read. If the file has changed since your read, the server returns `409 Conflict`.
</ParamField>

<CodeGroup>
  ```bash Create a new file theme={null}
  curl -X PUT 'http://localhost:3333/api/kiwi/file?path=concepts/auth.md' \
    -H "Content-Type: text/markdown" \
    -H "X-Actor: agent:docs-writer" \
    -d '# Authentication

  OAuth2 + JWT based authentication system.'
  ```

  ```bash Update with optimistic locking theme={null}
  curl -X PUT 'http://localhost:3333/api/kiwi/file?path=concepts/auth.md' \
    -H "Content-Type: text/markdown" \
    -H "X-Actor: agent:docs-writer" \
    -H "If-Match: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2" \
    -d '# Authentication (updated)

  Revised content here.'
  ```
</CodeGroup>

<Warning>
  If you pass `If-Match` and the file has been modified since your read, the server returns `409 Conflict` with an error message. Fetch the latest version, merge your changes, and retry.
</Warning>

## Delete a file

Delete a file and create a git commit recording the deletion.

<ParamField query="path" type="string" required>
  File path to delete.
</ParamField>

```bash theme={null}
curl -X DELETE 'http://localhost:3333/api/kiwi/file?path=concepts/auth.md' \
  -H "X-Actor: agent:cleanup"
```

## Bulk write

Write multiple files in a single git commit. This is more efficient than individual writes and keeps your git history clean.

<ParamField header="X-Actor" type="string">
  Git commit author attribution.
</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/bulk' \
  -H "Content-Type: application/json" \
  -H "X-Actor: agent:importer" \
  -d '{
    "files": [
      {"path": "concepts/auth.md", "content": "# Authentication\n\nOAuth2 flow."},
      {"path": "concepts/billing.md", "content": "# Billing\n\nStripe integration."},
      {"path": "concepts/users.md", "content": "# Users\n\nUser management."}
    ]
  }'
```

<Tip>
  Use bulk writes when importing data or making batch updates. All files are committed atomically in a single git commit.
</Tip>

## Upload assets

Upload binary files (images, PDFs, etc.) as multipart form data.

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/assets' \
  -F "file=@diagram.png" \
  -H "X-Actor: agent:uploader"
```

The response returns the asset path you can reference in markdown:

```json theme={null}
{"path": "assets/diagram.png"}
```

## Table of contents

Get the heading outline for a file.

<ParamField query="path" type="string" required>
  File path to extract headings from.
</ParamField>

```bash theme={null}
curl 'http://localhost:3333/api/kiwi/toc?path=concepts/auth.md'
```

```json theme={null}
[
  {"level": 1, "text": "Authentication", "slug": "authentication"},
  {"level": 2, "text": "OAuth2 flow", "slug": "oauth2-flow"},
  {"level": 2, "text": "JWT tokens", "slug": "jwt-tokens"}
]
```

## Append to a file

Append content to an existing file without reading it first.

```http theme={null}
POST /api/kiwi/file/append
```

<ParamField query="path" type="string" required>
  File path to append to.
</ParamField>

<ParamField query="separator" type="string" default="\n">
  String inserted between existing content and new content.
</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/file/append?path=log/agent.md' \
  -H "X-Actor: agent:logger" \
  -d '## Entry 42

New finding from run 249.'
```

```json theme={null}
{"path": "log/agent.md", "etag": "b2c3d4e5f6..."}
```

<Tip>
  Append is useful for agent logs, episodic memory, and audit trails where you want to add content without read-modify-write cycles.
</Tip>

## Rename a file

Rename or move a file. Wiki links pointing to the old path are automatically updated.

```http theme={null}
POST /api/kiwi/rename
```

<ParamField body="from" type="string" required>Old file path.</ParamField>
<ParamField body="to" type="string" required>New file path.</ParamField>

<ParamField query="update_links" type="boolean" default="true">
  Rewrite wiki links in other files that point to the old path.
</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/rename' \
  -H "Content-Type: application/json" \
  -d '{"from": "concepts/auth.md", "to": "concepts/authentication.md"}'
```

```json theme={null}
{
  "from": "concepts/auth.md",
  "to": "concepts/authentication.md",
  "etag": "c3d4e5f6...",
  "updated_links": 8
}
```

## Rename a directory

Move an entire directory and update all internal links.

```http theme={null}
POST /api/kiwi/rename-dir
```

<ParamField body="from" type="string" required>Old directory path.</ParamField>
<ParamField body="to" type="string" required>New directory path.</ParamField>

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/rename-dir' \
  -H "Content-Type: application/json" \
  -d '{"from": "concepts", "to": "docs/concepts"}'
```

```json theme={null}
{"from": "concepts", "to": "docs/concepts", "renamed": 15}
```

## Templates

List and read page templates stored in `.kiwi/templates/`.

### List templates

```bash theme={null}
curl 'http://localhost:3333/api/kiwi/templates'
```

```json theme={null}
["runbook", "decision", "episode", "concept"]
```

### Read a template

```bash theme={null}
curl 'http://localhost:3333/api/kiwi/templates?name=runbook'
```

```json theme={null}
{"name": "runbook", "content": "---\ntype: runbook\ntitle: \nstatus: draft\n---\n\n# Title\n\n## Steps\n\n1. ..."}
```

## Resolve wiki links

Resolve `[[wiki-links]]` to their canonical file paths and permalinks.

```bash theme={null}
curl -X POST 'http://localhost:3333/api/kiwi/resolve-links' \
  -H "Content-Type: application/json" \
  -d '{"links": ["auth", "billing", "nonexistent"]}'
```

```json theme={null}
{
  "resolved": {
    "auth": {"path": "concepts/auth.md", "title": "Authentication"},
    "billing": {"path": "concepts/billing.md", "title": "Billing"}
  },
  "unresolved": ["nonexistent"]
}
```
