Adding tasks to obsidian via a network share

Home Assistant General

Overview

This guide walks through setting up Home Assistant to create Obsidian task notes via voice command using the built-in Assist voice assistant. When you say “Add task [title] about [body]”, a markdown file is written directly into your Obsidian vault, which is kept ion another server via a SMB share.

What you will need

  • Home Assistant (VM or install) with the SSH & Web Terminal add-on
  • A network share from your Syncthing LXC already mounted in Home Assistant
  • The Obsidian Tasks or Tasknotes plugin configured to use frontmatter properties
  • Assist enabled in Home Assistant

Architecture

The flow works as follows:

  1. You speak a command via Assist
  2. A conversation trigger fires an automation, passing the title and body as slots
  3. The automation calls an HA script
  4. The script runs a shell command which executes a bash script on the HA host
  5. The bash script writes a formatted markdown file to the network share
  6. Syncthing picks up the new file and syncs it to your Obsidian vault

Step 1 — Mount the Syncthing folder as a network share in Home Assistant

If you have not already done this, add the Syncthing LXC folder as a network share (SMB or NFS) and mount it in Home Assistant via Settings ? System ? Storage ? Add network storage. Give it a recognisable name such as obsidian-tasks.

Once mounted, confirm the path it appears at. Open the HA terminal (SSH add-on) and run:

df -h
# or
mount | grep -i cifs
mount | grep -i nfs

Note the mount path — it will typically be something like /media/obsidian-tasks. You will need this in the steps below.


Step 2 — Update configuration.yaml

Home Assistant requires external paths to be explicitly allowlisted before scripts can write to them. Add the following to your configuration.yaml, replacing the path with your actual mount point:

homeassistant:
  allowlist_external_dirs:
    - /media/obsidian-tasks

shell_command:
  write_obsidian_task: bash /config/scripts/create_task.sh '{{ title }}' '{{ body }}' '{{ subfolder }}'

Restart Home Assistant after saving this file.


Step 3 — Create the bash script

This script does the actual work of generating the markdown file with the correct frontmatter for the Tasknotes plugin.

In the HA terminal, create the scripts folder and the file:

mkdir -p /config/scripts
nano /config/scripts/create_task.sh

Paste the following content, replacing /media/obsidian-tasks with your actual share path:

#!/bin/bash
TITLE="$1"
BODY="$2"
SUBFOLDER="${3:-Tasks}"

DEST="/media/obsidian-tasks/${SUBFOLDER}"
mkdir -p "$DEST"

# Sanitise the title for use as a filename
FILENAME="$(echo "$TITLE" | tr ' ' '-' | tr -cd '[:alnum:]-_').md"

# Date/time values
CREATED="$(date +"%Y-%m-%dT%H:%M")"
DATE_MODIFIED="$(date +"%Y-%m-%dT%H:%M:%S.000")$(date +"%z" | sed 's/\(..\)$/:\1/')"
SCHEDULED="$(date +"%Y-%m-%d")"
DUE="$(date -d "@$(($(date +%s) + 259200))" +"%Y-%m-%d")"

{
  printf -- "---\n"
  printf "created: %s\n" "$CREATED"
  printf "tags:\n"
  printf "  - task\n"
  printf "dateModified: %s\n" "$DATE_MODIFIED"
  printf "title: %s\n" "$TITLE"
  printf "status: open\n"
  printf "priority: normal\n"
  printf "due: %s\n" "$DUE"
  printf "scheduled: %s\n" "$SCHEDULED"
  printf -- "---\n"
  printf "\n"
  printf "%s\n" "$BODY"
} > "${DEST}/${FILENAME}"

echo "Created: ${DEST}/${FILENAME}"

Save the file (Ctrl+X, then Y, then Enter), then make it executable:

chmod +x /config/scripts/create_task.sh

Notes on the date fields

  • created — timestamp when the file is written
  • dateModified — same timestamp, formatted with timezone offset and milliseconds to match the Tasknotes plugin format
  • scheduled — set to today
  • due — set to 3 days from today (259200 seconds). The arithmetic method is used instead of date -d "+3 days" because the HA container uses BusyBox date which does not support that flag

Test the script manually

Before wiring it into Home Assistant, confirm it works from the terminal:

bash /config/scripts/create_task.sh "Test Task" "This is the body text" "Tasks"

Check your Obsidian vault to confirm the file appears with the correct frontmatter.


Step 4 — Create the Home Assistant script

This script is the callable action that automations and voice commands will trigger. Add it via Settings ? Automations & Scenes ? Scripts ? Add Script ? Edit in YAML, or add it directly to scripts.yaml:

alias: Create Obsidian Task
description: Write a markdown task into the Obsidian vault via Syncthing
icon: mdi:note-plus-outline
fields:
  title:
    description: Task title (becomes the filename)
    required: true
    example: "Fix bathroom tap"
    selector:
      text:
  body:
    description: Task body / details
    required: false
    default: ""
    example: "Dripping since Monday, check washer first"
    selector:
      text:
        multiline: true
  subfolder:
    description: Subfolder within the vault
    required: false
    default: "HomeAssistant"
    example: "HomeAssistant, Family, Projects"
    selector:
      text:
sequence:
  - action: shell_command.write_obsidian_task
    data:
      title: "{{ title }}"
      body: "{{ body }}"
      subfolder: "{{ subfolder }}"
    response_variable: result
  - if: "{{ result['returncode'] != 0 }}"
    then:
      - action: persistent_notification.create
        data:
          title: "Obsidian task failed"
          message: "{{ result['stderr'] }}"

If the shell command fails for any reason, a persistent notification will appear in your HA dashboard with the error detail.

You can test this script directly via Developer Tools ? Actions, searching for script.create_obsidian_task and filling in the fields.


Step 5 — Create the voice automation

This automation listens for spoken commands via Assist and triggers the script. Add it via Settings ? Automations & Scenes ? Automations ? Add Automation ? Edit in YAML:

alias: Voice - Create Obsidian Task
description: Creates an Obsidian task via Assist voice command
triggers:
  - trigger: conversation
    command:
      - "add task {title} about {body}"
      - "create task {title} about {body}"
      - "new task {title} about {body}"
actions:
  - action: script.create_obsidian_task
    data:
      title: "{{ trigger.slots.title }}"
      body: "{{ trigger.slots.body }}"
      subfolder: "HomeAssistant"
  - stop: "Task created"
    response_variable:
      speech: "Task {{ trigger.slots.title }} has been created"

The {title} and {body} placeholders in the trigger commands act as named slots automatically — no separate custom sentence file is needed. The stop action at the end sends a spoken confirmation back through whichever Assist pipeline triggered the command.


Step 6 — Test the voice command

Before testing with a physical voice device, use the Assist chat interface in Home Assistant:

  1. Click the Assist icon in the HA toolbar (the chat bubble)
  2. Type: add task Fix the boiler about needs a new pressure valve
  3. Confirm you receive the spoken/text confirmation response
  4. Check your Obsidian vault to confirm the file has been created with the correct frontmatter

If using a physical satellite device (such as a Wyoming-protocol voice device), the confirmation will be spoken back through that device.


Troubleshooting

returncode 127 — script not found

The bash script does not exist at /config/scripts/create_task.sh or is not executable. Re-run the chmod +x command and verify the file exists with ls -la /config/scripts/.

returncode 1 — permission denied writing to share

The HA process does not have write permission to the network share mount point. Check the share permissions on the Syncthing LXC side and ensure the user account used for the SMB/NFS mount has write access.

File created but frontmatter fields missing in Tasknotes

Check that the frontmatter field names in the script (status, priority, due, scheduled, dateModified) exactly match the field names configured in your Tasknotes plugin settings. These are configurable and may differ from the defaults shown here.

Voice command not recognised

Ensure the automation is enabled and that Assist is using a pipeline with speech-to-text configured. Test by typing the command in the Assist chat interface first to confirm the trigger is matching before involving speech recognition.

Due date is blank

The HA container uses BusyBox date which does not support date -d "+3 days". Confirm the script is using the arithmetic method shown above (date -d "@$(($(date +%s) + 259200))").


Customisation

Changing the default due date offset

To change the due date from 3 days to a different number, replace 259200 in the script with the number of seconds you want. Common values:

  • 1 day — 86400
  • 3 days — 259200
  • 7 days — 604800
  • 14 days — 1209600

Adding more voice trigger phrases

Add additional entries under the command list in the automation trigger. The slot names {title} and {body} must remain consistent:

command:
  - "add task {title} about {body}"
  - "create task {title} about {body}"
  - "new task {title} about {body}"
  - "remind me to {title} because {body}"

Routing to different subfolders by voice

To support dynamic subfolder selection by voice, extend the trigger and pass the slot through:

command:
  - "add {subfolder} task {title} about {body}"
actions:
  - action: script.create_obsidian_task
    data:
      title: "{{ trigger.slots.title }}"
      body: "{{ trigger.slots.body }}"
      subfolder: "{{ trigger.slots.subfolder }}"

You would then say: “Add HomeAssistant task Fix the boiler about needs a new pressure valve”