{"id":14239,"date":"2026-05-11T10:45:13","date_gmt":"2026-05-11T10:45:13","guid":{"rendered":"https:\/\/www.rjt.org.uk\/home\/?post_type=home_assistant_tip&#038;p=14239"},"modified":"2026-05-11T10:45:14","modified_gmt":"2026-05-11T10:45:14","slug":"adding-tasks-to-obsidian-via-a-network-share","status":"publish","type":"home_assistant_tip","link":"https:\/\/www.rjt.org.uk\/home\/archives\/home-assistant-tip\/adding-tasks-to-obsidian-via-a-network-share\/","title":{"rendered":"Adding tasks to obsidian  via a network share"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Overview<\/h2>\n\n\n\n<p>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 <em>&#8220;Add task [title] about [body]&#8221;<\/em>, a markdown file is written directly into your Obsidian vault, which is kept ion another server via a SMB share.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What you will need<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Home Assistant (VM or install) with the SSH &amp; Web Terminal add-on<\/li>\n\n\n\n<li>A network share from your Syncthing LXC already mounted in Home Assistant<\/li>\n\n\n\n<li>The Obsidian Tasks or Tasknotes plugin configured to use frontmatter properties<\/li>\n\n\n\n<li>Assist enabled in Home Assistant<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Architecture<\/h3>\n\n\n\n<p>The flow works as follows:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>You speak a command via Assist<\/li>\n\n\n\n<li>A conversation trigger fires an automation, passing the title and body as slots<\/li>\n\n\n\n<li>The automation calls an HA script<\/li>\n\n\n\n<li>The script runs a shell command which executes a bash script on the HA host<\/li>\n\n\n\n<li>The bash script writes a formatted markdown file to the network share<\/li>\n\n\n\n<li>Syncthing picks up the new file and syncs it to your Obsidian vault<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1 \u2014 Mount the Syncthing folder as a network share in Home Assistant<\/h2>\n\n\n\n<p>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 <strong>Settings ? System ? Storage ? Add network storage<\/strong>. Give it a recognisable name such as <code>obsidian-tasks<\/code>.<\/p>\n\n\n\n<p>Once mounted, confirm the path it appears at. Open the HA terminal (SSH add-on) and run:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">df -h\n# or\nmount | grep -i cifs\nmount | grep -i nfs<\/pre>\n\n\n\n<p>Note the mount path \u2014 it will typically be something like <code>\/media\/obsidian-tasks<\/code>. You will need this in the steps below.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2 \u2014 Update configuration.yaml<\/h2>\n\n\n\n<p>Home Assistant requires external paths to be explicitly allowlisted before scripts can write to them. Add the following to your <code>configuration.yaml<\/code>, replacing the path with your actual mount point:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">homeassistant:\n  allowlist_external_dirs:\n    - \/media\/obsidian-tasks\n\nshell_command:\n  write_obsidian_task: bash \/config\/scripts\/create_task.sh '{{ title }}' '{{ body }}' '{{ subfolder }}'<\/pre>\n\n\n\n<p>Restart Home Assistant after saving this file.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3 \u2014 Create the bash script<\/h2>\n\n\n\n<p>This script does the actual work of generating the markdown file with the correct frontmatter for the Tasknotes plugin.<\/p>\n\n\n\n<p>In the HA terminal, create the scripts folder and the file:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">mkdir -p \/config\/scripts\nnano \/config\/scripts\/create_task.sh<\/pre>\n\n\n\n<p>Paste the following content, replacing <code>\/media\/obsidian-tasks<\/code> with your actual share path:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\nTITLE=\"$1\"\nBODY=\"$2\"\nSUBFOLDER=\"${3:-Tasks}\"\n\nDEST=\"\/media\/obsidian-tasks\/${SUBFOLDER}\"\nmkdir -p \"$DEST\"\n\n# Sanitise the title for use as a filename\nFILENAME=\"$(echo \"$TITLE\" | tr ' ' '-' | tr -cd '[:alnum:]-_').md\"\n\n# Date\/time values\nCREATED=\"$(date +\"%Y-%m-%dT%H:%M\")\"\nDATE_MODIFIED=\"$(date +\"%Y-%m-%dT%H:%M:%S.000\")$(date +\"%z\" | sed 's\/\\(..\\)$\/:\\1\/')\"\nSCHEDULED=\"$(date +\"%Y-%m-%d\")\"\nDUE=\"$(date -d \"@$(($(date +%s) + 259200))\" +\"%Y-%m-%d\")\"\n\n{\n  printf -- \"---\\n\"\n  printf \"created: %s\\n\" \"$CREATED\"\n  printf \"tags:\\n\"\n  printf \"  - task\\n\"\n  printf \"dateModified: %s\\n\" \"$DATE_MODIFIED\"\n  printf \"title: %s\\n\" \"$TITLE\"\n  printf \"status: open\\n\"\n  printf \"priority: normal\\n\"\n  printf \"due: %s\\n\" \"$DUE\"\n  printf \"scheduled: %s\\n\" \"$SCHEDULED\"\n  printf -- \"---\\n\"\n  printf \"\\n\"\n  printf \"%s\\n\" \"$BODY\"\n} > \"${DEST}\/${FILENAME}\"\n\necho \"Created: ${DEST}\/${FILENAME}\"<\/pre>\n\n\n\n<p>Save the file (<kbd>Ctrl+X<\/kbd>, then <kbd>Y<\/kbd>, then <kbd>Enter<\/kbd>), then make it executable:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">chmod +x \/config\/scripts\/create_task.sh<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Notes on the date fields<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>created<\/strong> \u2014 timestamp when the file is written<\/li>\n\n\n\n<li><strong>dateModified<\/strong> \u2014 same timestamp, formatted with timezone offset and milliseconds to match the Tasknotes plugin format<\/li>\n\n\n\n<li><strong>scheduled<\/strong> \u2014 set to today<\/li>\n\n\n\n<li><strong>due<\/strong> \u2014 set to 3 days from today (259200 seconds). The arithmetic method is used instead of <code>date -d \"+3 days\"<\/code> because the HA container uses BusyBox date which does not support that flag<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Test the script manually<\/h3>\n\n\n\n<p>Before wiring it into Home Assistant, confirm it works from the terminal:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">bash \/config\/scripts\/create_task.sh \"Test Task\" \"This is the body text\" \"Tasks\"<\/pre>\n\n\n\n<p>Check your Obsidian vault to confirm the file appears with the correct frontmatter.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4 \u2014 Create the Home Assistant script<\/h2>\n\n\n\n<p>This script is the callable action that automations and voice commands will trigger. Add it via <strong>Settings ? Automations &amp; Scenes ? Scripts ? Add Script ? Edit in YAML<\/strong>, or add it directly to <code>scripts.yaml<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">alias: Create Obsidian Task\ndescription: Write a markdown task into the Obsidian vault via Syncthing\nicon: mdi:note-plus-outline\nfields:\n  title:\n    description: Task title (becomes the filename)\n    required: true\n    example: \"Fix bathroom tap\"\n    selector:\n      text:\n  body:\n    description: Task body \/ details\n    required: false\n    default: \"\"\n    example: \"Dripping since Monday, check washer first\"\n    selector:\n      text:\n        multiline: true\n  subfolder:\n    description: Subfolder within the vault\n    required: false\n    default: \"HomeAssistant\"\n    example: \"HomeAssistant, Family, Projects\"\n    selector:\n      text:\nsequence:\n  - action: shell_command.write_obsidian_task\n    data:\n      title: \"{{ title }}\"\n      body: \"{{ body }}\"\n      subfolder: \"{{ subfolder }}\"\n    response_variable: result\n  - if: \"{{ result['returncode'] != 0 }}\"\n    then:\n      - action: persistent_notification.create\n        data:\n          title: \"Obsidian task failed\"\n          message: \"{{ result['stderr'] }}\"<\/pre>\n\n\n\n<p>If the shell command fails for any reason, a persistent notification will appear in your HA dashboard with the error detail.<\/p>\n\n\n\n<p>You can test this script directly via <strong>Developer Tools ? Actions<\/strong>, searching for <code>script.create_obsidian_task<\/code> and filling in the fields.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5 \u2014 Create the voice automation<\/h2>\n\n\n\n<p>This automation listens for spoken commands via Assist and triggers the script. Add it via <strong>Settings ? Automations &amp; Scenes ? Automations ? Add Automation ? Edit in YAML<\/strong>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">alias: Voice - Create Obsidian Task\ndescription: Creates an Obsidian task via Assist voice command\ntriggers:\n  - trigger: conversation\n    command:\n      - \"add task {title} about {body}\"\n      - \"create task {title} about {body}\"\n      - \"new task {title} about {body}\"\nactions:\n  - action: script.create_obsidian_task\n    data:\n      title: \"{{ trigger.slots.title }}\"\n      body: \"{{ trigger.slots.body }}\"\n      subfolder: \"HomeAssistant\"\n  - stop: \"Task created\"\n    response_variable:\n      speech: \"Task {{ trigger.slots.title }} has been created\"<\/pre>\n\n\n\n<p>The <code>{title}<\/code> and <code>{body}<\/code> placeholders in the trigger commands act as named slots automatically \u2014 no separate custom sentence file is needed. The <code>stop<\/code> action at the end sends a spoken confirmation back through whichever Assist pipeline triggered the command.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Step 6 \u2014 Test the voice command<\/h2>\n\n\n\n<p>Before testing with a physical voice device, use the Assist chat interface in Home Assistant:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Click the Assist icon in the HA toolbar (the chat bubble)<\/li>\n\n\n\n<li>Type: <code>add task Fix the boiler about needs a new pressure valve<\/code><\/li>\n\n\n\n<li>Confirm you receive the spoken\/text confirmation response<\/li>\n\n\n\n<li>Check your Obsidian vault to confirm the file has been created with the correct frontmatter<\/li>\n<\/ol>\n\n\n\n<p>If using a physical satellite device (such as a Wyoming-protocol voice device), the confirmation will be spoken back through that device.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">returncode 127 \u2014 script not found<\/h3>\n\n\n\n<p>The bash script does not exist at <code>\/config\/scripts\/create_task.sh<\/code> or is not executable. Re-run the <code>chmod +x<\/code> command and verify the file exists with <code>ls -la \/config\/scripts\/<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">returncode 1 \u2014 permission denied writing to share<\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">File created but frontmatter fields missing in Tasknotes<\/h3>\n\n\n\n<p>Check that the frontmatter field names in the script (<code>status<\/code>, <code>priority<\/code>, <code>due<\/code>, <code>scheduled<\/code>, <code>dateModified<\/code>) exactly match the field names configured in your Tasknotes plugin settings. These are configurable and may differ from the defaults shown here.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Voice command not recognised<\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Due date is blank<\/h3>\n\n\n\n<p>The HA container uses BusyBox date which does not support <code>date -d \"+3 days\"<\/code>. Confirm the script is using the arithmetic method shown above (<code>date -d \"@$(($(date +%s) + 259200))\"<\/code>).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Customisation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Changing the default due date offset<\/h3>\n\n\n\n<p>To change the due date from 3 days to a different number, replace <code>259200<\/code> in the script with the number of seconds you want. Common values:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1 day \u2014 <code>86400<\/code><\/li>\n\n\n\n<li>3 days \u2014 <code>259200<\/code><\/li>\n\n\n\n<li>7 days \u2014 <code>604800<\/code><\/li>\n\n\n\n<li>14 days \u2014 <code>1209600<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Adding more voice trigger phrases<\/h3>\n\n\n\n<p>Add additional entries under the <code>command<\/code> list in the automation trigger. The slot names <code>{title}<\/code> and <code>{body}<\/code> must remain consistent:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">command:\n  - \"add task {title} about {body}\"\n  - \"create task {title} about {body}\"\n  - \"new task {title} about {body}\"\n  - \"remind me to {title} because {body}\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Routing to different subfolders by voice<\/h3>\n\n\n\n<p>To support dynamic subfolder selection by voice, extend the trigger and pass the slot through:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">command:\n  - \"add {subfolder} task {title} about {body}\"\nactions:\n  - action: script.create_obsidian_task\n    data:\n      title: \"{{ trigger.slots.title }}\"\n      body: \"{{ trigger.slots.body }}\"\n      subfolder: \"{{ trigger.slots.subfolder }}\"<\/pre>\n\n\n\n<p>You would then say: <em>&#8220;Add HomeAssistant task Fix the boiler about needs a new pressure valve&#8221;<\/em><\/p>\n\n\n\n<p><\/p>\n","protected":false},"template":"","class_list":["post-14239","home_assistant_tip","type-home_assistant_tip","status-publish","hentry","comments-off"],"_links":{"self":[{"href":"https:\/\/www.rjt.org.uk\/home\/wp-json\/wp\/v2\/home_assistant_tip\/14239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rjt.org.uk\/home\/wp-json\/wp\/v2\/home_assistant_tip"}],"about":[{"href":"https:\/\/www.rjt.org.uk\/home\/wp-json\/wp\/v2\/types\/home_assistant_tip"}],"wp:attachment":[{"href":"https:\/\/www.rjt.org.uk\/home\/wp-json\/wp\/v2\/media?parent=14239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}