Skip to main content
Write File functions allow AI assistants to create or overwrite files with content, using built-in security controls that restrict access to designated directories.
Caution: File OverwriteWrite File functions will overwrite existing files without warning. Use Edit File functions for safer modifications to existing files.

Configuration

function:
  type: write_file
  path: "{{ filename }}"
  content: "{{ file_content }}"
path
template
required
Path to the file to write. Can be absolute or relative to the working directory (config/extended_openai_conversation/).
content
template
required
Content to write to the file. Can include Jinja2 templates for dynamic content generation.
allow_dir
array
Optional list of additional allowed directories (as templates). By default, only the working directory is allowed.

Working Directory

The default working directory is config/extended_openai_conversation/.
# Writes to /config/extended_openai_conversation/notes.txt
function:
  type: write_file
  path: "notes.txt"
  content: "{{ note_text }}"

Examples

Write File

- 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.
- 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"
allow_dir accepts templates with access to variables like {{ config_dir }}:
allow_dir:
  - "{{ config_dir }}/www"
  - "{{ config_dir }}/custom_data"

Return Value

On success:
{
  "success": true,
  "path": "/config/extended_openai_conversation/notes.txt",
  "bytes_written": 1234
}
On error:
{
  "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

- 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

- 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

- 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

Note Taking

Save user notes, reminders, and documentation

Configuration Generation

Generate automation configs, scripts, templates

Data Export

Export sensor data, logs, or analysis results

Report Generation

Create markdown, CSV, or text reports

Common Patterns

Append Timestamp to Filename

- 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

- 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

- 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

- 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

Files must be within allowed directories. By default:
  • /config/extended_openai_conversation/ (working directory)
Additional directories can be added via allow_dir.
Paths are resolved to absolute paths and validated. Attempts to use ../ to escape allowed directories will be blocked.
Write File overwrites existing files without confirmation. Use Edit File for safer modifications.
Parent directories are not automatically created. The parent directory must exist before writing a file. Use bash functions if you need to create directories:
type: composite
sequence:
  - type: bash
    command: "mkdir -p data/reports"
  - type: write_file
    path: "data/reports/report.txt"
    content: "{{ content }}"

Best Practices

1

Validate before overwriting

Check if file exists before overwriting (use composite function):
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 %}
2

Use descriptive filenames

Include timestamps or identifiers in filenames:
path: "backups/{{ entity_id }}_{{ now().strftime('%Y%m%d_%H%M%S') }}.json"
3

Handle encoding properly

Always use UTF-8 text. For special characters, ensure proper escaping:
content: |
  # Content with special characters
  Temperature: {{ temp }}°C
  Status: {{ status | replace('"', '\\"') }}
4

Organize files in subdirectories

Use subdirectories to organize files (ensure they exist first):
path: "logs/{{ now().strftime('%Y/%m') }}/{{ filename }}.log"

Troubleshooting

The target path is outside allowed directories. Either:
  • Write to the workspace (/config/extended_openai_conversation/)
  • Add the target directory to allow_dir
The parent directory doesn’t exist. Create it first:
type: composite
sequence:
  - type: bash
    command: "mkdir -p $(dirname '{{ filepath }}')"
  - type: write_file
    path: "{{ filepath }}"
    content: "{{ content }}"
Check:
  • File permissions on the parent directory
  • Available disk space
  • SELinux or AppArmor policies (in container environments)

FAQ

Existing files are overwritten without warning. There is no backup or confirmation. Use Edit File for safer modifications to existing files.
No. Parent directories must exist before writing a file. Use bash functions to create directories if needed.
There’s no explicit limit, but very large content (>10MB) may cause memory issues. For large files, consider using bash functions with streaming:
type: bash
command: "cat > {{ filename }} << 'EOF'\n{{ content }}\nEOF"
No. Write File always overwrites. To append, use bash functions:
type: bash
command: "echo '{{ new_line }}' >> {{ filename }}"

Next Steps