> ## Documentation Index
> Fetch the complete documentation index at: https://extended-openai-conversation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Write File Functions

> Write content to files safely with path restrictions

Write File functions allow AI assistants to create or overwrite files with content, using built-in security controls that restrict access to designated directories.

<Warning>
  **Caution: File Overwrite**

  Write File functions will **overwrite existing files** without warning. Use Edit File functions for safer modifications to existing files.
</Warning>

## Configuration

```yaml theme={null}
function:
  type: write_file
  path: "{{ filename }}"
  content: "{{ file_content }}"
```

<ParamField path="path" type="template" required>
  Path to the file to write. Can be absolute or relative to the working directory (`config/extended_openai_conversation/`).
</ParamField>

<ParamField path="content" type="template" required>
  Content to write to the file. Can include Jinja2 templates for dynamic content generation.
</ParamField>

<ParamField path="allow_dir" type="array">
  Optional list of additional allowed directories (as templates). By default, only the working directory is allowed.
</ParamField>

## Working Directory

The default working directory is `config/extended_openai_conversation/`.

<Tabs>
  <Tab title="Relative Path">
    ```yaml theme={null}
    # Writes to /config/extended_openai_conversation/notes.txt
    function:
      type: write_file
      path: "notes.txt"
      content: "{{ note_text }}"
    ```
  </Tab>

  <Tab title="Subdirectory">
    ```yaml theme={null}
    # Writes to /config/extended_openai_conversation/data/config.json
    # Note: Parent directory must already exist
    function:
      type: write_file
      path: "data/config.json"
      content: "{{ json_data }}"
    ```
  </Tab>

  <Tab title="Absolute Path">
    ```yaml theme={null}
    # Writes to /config/scripts/generated.py
    function:
      type: write_file
      path: "/config/scripts/generated.py"
      content: "{{ python_code }}"
    ```
  </Tab>
</Tabs>

## Examples

### Write File

```yaml theme={null}
- spec:
    name: write_file
    description: Write content to a file in workspace.
    parameters:
      type: object
      properties:
        filename:
          type: string
          description: Name of the file
        content:
          type: string
          description: Content to write
      required:
      - filename
      - content
  function:
    type: write_file
    path: "{{ filename }}"
    content: "{{ content }}"
```

### Custom Allowed Directories

Extend allowed directories beyond the default workspace. The `allow_dir` parameter adds additional directories where files can be written.

```yaml theme={null}
- spec:
    name: write_file_with_allow_dir
    description: Write a file with custom allowed directories.
    parameters:
      type: object
      properties:
        filename:
          type: string
          description: Name of the file
        content:
          type: string
          description: Content to write
      required:
      - filename
      - content
  function:
    type: write_file
    path: "{{ filename }}"
    content: "{{ content }}"
    allow_dir:
      - "/backup"
      - "/media"
```

<Info>
  `allow_dir` accepts templates with access to variables like `{{ config_dir }}`:

  ```yaml theme={null}
  allow_dir:
    - "{{ config_dir }}/www"
    - "{{ config_dir }}/custom_data"
  ```
</Info>

## Return Value

On success:

```json theme={null}
{
  "success": true,
  "path": "/config/extended_openai_conversation/notes.txt",
  "bytes_written": 1234
}
```

On error:

```json theme={null}
{
  "error": "Access denied: path 'filename' is not in allowed directories"
}
```

### Error Types

* **Access denied**: File path is outside allowed directories
* **Permission error**: Insufficient permissions to write file
* **No such file or directory**: Parent directory doesn't exist
* **Other errors**: Encoding issues, disk full, etc.

## Dynamic Content Generation

Write File functions support Jinja2 templates in the `content` field:

### Generate YAML Configuration

```yaml theme={null}
- spec:
    name: create_automation
    description: Create a new automation configuration
    parameters:
      type: object
      properties:
        automation_name:
          type: string
        trigger_entity:
          type: string
        action_entity:
          type: string
  function:
    type: write_file
    path: "automations/{{ automation_name | slugify }}.yaml"
    content: |
      - alias: "{{ automation_name }}"
        trigger:
          - platform: state
            entity_id: {{ trigger_entity }}
        action:
          - service: homeassistant.turn_on
            target:
              entity_id: {{ action_entity }}
```

### Generate JSON Data

```yaml theme={null}
- spec:
    name: save_sensor_data
    description: Save sensor data to JSON file
    parameters:
      type: object
      properties:
        sensor_id:
          type: string
        readings:
          type: array
          items:
            type: number
  function:
    type: write_file
    path: "data/{{ sensor_id }}.json"
    content: |
      {
        "sensor": "{{ sensor_id }}",
        "timestamp": "{{ now().isoformat() }}",
        "readings": {{ readings | tojson }}
      }
```

### Generate Python Script

```yaml theme={null}
- spec:
    name: create_python_script
    description: Create a Python script for automation
    parameters:
      type: object
      properties:
        script_name:
          type: string
        entity_id:
          type: string
  function:
    type: write_file
    path: "python_scripts/{{ script_name }}.py"
    content: |
      # Generated script: {{ script_name }}
      # Created: {{ now().strftime('%Y-%m-%d %H:%M:%S') }}

      entity_id = "{{ entity_id }}"
      state = hass.states.get(entity_id)

      if state and state.state == "on":
          logger.info(f"{entity_id} is on")
```

## Use Cases

<CardGroup cols={2}>
  <Card title="Note Taking" icon="note-sticky">
    Save user notes, reminders, and documentation
  </Card>

  <Card title="Configuration Generation" icon="gear">
    Generate automation configs, scripts, templates
  </Card>

  <Card title="Data Export" icon="download">
    Export sensor data, logs, or analysis results
  </Card>

  <Card title="Report Generation" icon="file-lines">
    Create markdown, CSV, or text reports
  </Card>
</CardGroup>

## Common Patterns

### Append Timestamp to Filename

```yaml theme={null}
- spec:
    name: save_log
    description: Save log entry with timestamp
    parameters:
      type: object
      properties:
        log_message:
          type: string
  function:
    type: write_file
    path: "logs/{{ now().strftime('%Y%m%d_%H%M%S') }}.log"
    content: |
      [{{ now().strftime('%Y-%m-%d %H:%M:%S') }}] {{ log_message }}
```

### Write Multiple Lines

```yaml theme={null}
- spec:
    name: write_todo_list
    description: Write a todo list
    parameters:
      type: object
      properties:
        tasks:
          type: array
          items:
            type: string
  function:
    type: write_file
    path: "todo.txt"
    content: |
      # Todo List - {{ now().strftime('%Y-%m-%d') }}
      {% for task in tasks %}
      - [ ] {{ task }}
      {% endfor %}
```

### Write CSV Data

```yaml theme={null}
- spec:
    name: export_to_csv
    description: Export data to CSV
    parameters:
      type: object
      properties:
        filename:
          type: string
        headers:
          type: array
          items:
            type: string
        rows:
          type: array
          items:
            type: array
  function:
    type: write_file
    path: "exports/{{ filename }}.csv"
    content: |
      {{ headers | join(',') }}
      {% for row in rows %}
      {{ row | join(',') }}
      {% endfor %}
```

### Conditional Content

```yaml theme={null}
- spec:
    name: write_status_report
    description: Write system status report
    parameters:
      type: object
      properties:
        system_ok:
          type: boolean
        errors:
          type: array
          items:
            type: string
  function:
    type: write_file
    path: "reports/status_{{ now().strftime('%Y%m%d') }}.md"
    content: |
      # System Status Report

      **Date**: {{ now().strftime('%Y-%m-%d %H:%M:%S') }}

      **Status**: {% if system_ok %}✅ All systems operational{% else %}⚠️ Issues detected{% endif %}

      {% if not system_ok and errors %}
      ## Errors
      {% for error in errors %}
      - {{ error }}
      {% endfor %}
      {% endif %}
```

## Security

<AccordionGroup>
  <Accordion title="Path Restriction">
    Files must be within allowed directories. By default:

    * `/config/extended_openai_conversation/` (working directory)

    Additional directories can be added via `allow_dir`.
  </Accordion>

  <Accordion title="Path Traversal Protection">
    Paths are resolved to absolute paths and validated. Attempts to use `../` to escape allowed directories will be blocked.
  </Accordion>

  <Accordion title="File Overwrite">
    **Write File overwrites existing files without confirmation.** Use Edit File for safer modifications.
  </Accordion>

  <Accordion title="Directory Creation">
    Parent directories are **not** automatically created. The parent directory must exist before writing a file. Use bash functions if you need to create directories:

    ```yaml theme={null}
    type: composite
    sequence:
      - type: bash
        command: "mkdir -p data/reports"
      - type: write_file
        path: "data/reports/report.txt"
        content: "{{ content }}"
    ```
  </Accordion>
</AccordionGroup>

## Best Practices

<Steps>
  <Step title="Validate before overwriting">
    Check if file exists before overwriting (use composite function):

    ```yaml theme={null}
    type: composite
    sequence:
      - type: bash
        command: "test -f {{ filename }} && echo 'exists' || echo 'new'"
        response_variable: file_status
      - type: template
        value_template: |
          {% if 'exists' in file_status.stdout %}
            Error: File already exists. Use edit_file or choose a different name.
          {% else %}
            {# Proceed with write #}
          {% endif %}
    ```
  </Step>

  <Step title="Use descriptive filenames">
    Include timestamps or identifiers in filenames:

    ```yaml theme={null}
    path: "backups/{{ entity_id }}_{{ now().strftime('%Y%m%d_%H%M%S') }}.json"
    ```
  </Step>

  <Step title="Handle encoding properly">
    Always use UTF-8 text. For special characters, ensure proper escaping:

    ```yaml theme={null}
    content: |
      # Content with special characters
      Temperature: {{ temp }}°C
      Status: {{ status | replace('"', '\\"') }}
    ```
  </Step>

  <Step title="Organize files in subdirectories">
    Use subdirectories to organize files (ensure they exist first):

    ```yaml theme={null}
    path: "logs/{{ now().strftime('%Y/%m') }}/{{ filename }}.log"
    ```
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Access denied: path not in allowed directories">
    The target path is outside allowed directories. Either:

    * Write to the workspace (`/config/extended_openai_conversation/`)
    * Add the target directory to `allow_dir`
  </Accordion>

  <Accordion title="No such file or directory">
    The parent directory doesn't exist. Create it first:

    ```yaml theme={null}
    type: composite
    sequence:
      - type: bash
        command: "mkdir -p $(dirname '{{ filepath }}')"
      - type: write_file
        path: "{{ filepath }}"
        content: "{{ content }}"
    ```
  </Accordion>

  <Accordion title="Permission denied">
    Check:

    * File permissions on the parent directory
    * Available disk space
    * SELinux or AppArmor policies (in container environments)
  </Accordion>
</AccordionGroup>

## FAQ

<AccordionGroup>
  <Accordion title="What happens to existing files?">
    **Existing files are overwritten without warning.** There is no backup or confirmation. Use Edit File for safer modifications to existing files.
  </Accordion>

  <Accordion title="Are parent directories created automatically?">
    No. Parent directories must exist before writing a file. Use bash functions to create directories if needed.
  </Accordion>

  <Accordion title="What's the maximum file size I can write?">
    There's no explicit limit, but very large content (>10MB) may cause memory issues. For large files, consider using bash functions with streaming:

    ```yaml theme={null}
    type: bash
    command: "cat > {{ filename }} << 'EOF'\n{{ content }}\nEOF"
    ```
  </Accordion>

  <Accordion title="Can I append to existing files?">
    No. Write File always overwrites. To append, use bash functions:

    ```yaml theme={null}
    type: bash
    command: "echo '{{ new_line }}' >> {{ filename }}"
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="Read File" icon="book-open" href="/functions/read_file">
    Read file contents
  </Card>

  <Card title="Edit File" icon="pen-to-square" href="/functions/edit_file">
    Safely modify existing files
  </Card>

  <Card title="Bash Functions" icon="terminal" href="/functions/bash">
    Advanced file operations
  </Card>
</CardGroup>
