Scripting help -- for creating slip notes (zettelkasten) in Ulysses

Hi, I am an actions newbie and especially UNknowledgeable about JavaScript (although I appreciate its power.

I want to create an action that will take an existing note with a heading and some text in it and do two things…

  1. Insert a unique ID e.g. year/month/day/hour/minute like 202002022129 – preferably on the line under the heading
  2. Execute an x-callback-URL to a new sheet in Ulysses in a group called SLIPNOTES

I can do either individually, but it would be neat to come up with an action that performs both. Could someone give me a steer or point me to something similar or do the scripting bit?

You note you can do them individually. If you do them as successive steps in the same action wouldn’t that achieve what you are after?

Have a look – like I said, I’m a rank beginner…


For convenience reproduced below

  1. an Insert Text action:

[[date|%Y%m%d%H%M]] [[title]]


  1. Followed by a Callback Action:

template ulysses://x-callback-url/new-sheet?text=[[draft]]&group=/SLIPNOTES
waitForResponse true
encodeTags true


I wasn’t quite sincere in saying I could do each step individually – I can only insert the ID after the text, and not under the heading (which may not matter).

I’d appreciate being shown a better approach…

Okay so you can put both of those in a draft action side by side as multiple steps. But let’s focus on your extra point which I think would require a bit of scripting, and get some clarification on what you really want to do.

  • When you say insert the date beneath a heading, do you mean a Markdown heading, the draft title, or something else?
  • If you mean a Markdown heading is it always the same level, if so what level? i.e. how many hash symbols are to be matched against?
  • If a Markdown heading, what should happen if there are multiple headings? Insert after the first match, last match, all matches, etc?

The script would replace the first action step only. It would be based on either replacing the entire draft (title and body tags are your friends for that one), or replacing matching headings. In both cases the draft would then be updated ready for the x-callback step.

There’s an additional line of questioning related to this.

  • Do you actually want the draft updated?
  • Would you ever re-run the action, and if so, what should happen if it has already been marked with a date?

Good questions! I don’t want to be too prescriptive – the object of the exercise is to generate searchable, linkable slips quickly.

In my thinking, the draft title and the (main) markdown heading would be the same.

It actually doesn’t matter where the ID appears in the note but it’s ugly if it forms part of the heading. My preference is for all the ‘front matter’ to be together at the top but that’s just a familiar convention.

Here’s a general-interest example which is probably a bit more structured than most – a typical slip would be more like a heading and a paragraph or two:


Gin producers in the Marches - Pinkneys


Charles Pinkney

Charles Pinkney

Charles Pinkney claims to be following a family tradition on his 67 acre wildlife habitat farm in south Shropshire. This is also home to the Pinkneys Gin distillery.

The firm puts high values on sustainability and supporting British wildlife – as well as its carefully-crafted flavours.

These include:

  • Classic extra dry
  • Premium London dry
  • Oak aged
  • Sloe Berry
  • Thyme and Lime

and our family favourite, Rhubarb and Ginger.

See also:

Chase Distillery

Penrhos Spirits

Ludlow Dry Gin


Feel free to suggest a different or better way to go! The workflow should rule… Eg, another approach would be to generate slip template in Drafts (with the ID) and then add text and title and post to e.g. Ulysses as a separate action.

Thank you so much for your input, sylumer.

Regarding the workflow, you could definitely start these notes in Drafts. The actions, scripting support and templating functionality is a super powerful combo and can easily automate what you need. I love the idea of starting all text interactions (within reason) in Drafts, and then take it from there with actions. That seems to be the philosophy behind the app, and it works for me, so I would wholeheartedly recommend trying it out.

You might want to create the action to insert the ID anyways, in case you need to process already existing notes, right?

There are many ways to achieve this in javascript, and most of them start by grabbing the full content of the current draft, and then processing it in different ways, before you paste the result back in the editor.

const content = draft.content; // grabs the text of the current draft in the editor

// One common option is to split the text by lines into an array
let lines = content.split(“\n”);
const title = lines.shift(); // removes the first line from array and assigns it to the title variable
const body = lines.join(“\n”); // turns the array back into a text string with line changes

// Now create the ID
const id = draft.processTemplate([[date|%Y%m%d%H%M]]);

//Join the title with the id and the body of the text
const newContent = title + “\n” + id + “\n” + body; // \n is the newline character

// paste the new text (will replace the old draft)
draft.content = newContent;
draft.update(); // saves the changes

This should do the trick. If you don’t want to replace the old draft, but rather make a new one, add this line in the beginning const d = Draft.create() and exchange all instances of the word ‘draft’ in the script with ‘d’ except in the first line(!).

1 Like

I don’t use long date stamped urls - I find it much nicer to use note titles in Ulysses rather than a string of semantically uninformative numbers. If you’re using Ulysses it has already assigned unique IDs to every sheet and there’s no point in cluttering up your notes with an additional one.

See also the long discussion here


Ian Greig writes: I tried this and it returns an error that I couldn’t resolve


Got a sample action that I believe will do what you want without the need for java scripting ( if I understood you correctly :slight_smile:

Only the two first steps are active:

Tip: the tag [safe_title] strips of ## while [title] includes them, in case you already use markdown # Title Heading in draft.

2nd step is using URL step type, and will also open Ulysses with the new sheet.
Use Callback URL if you want silent update to Ulysses (3rd action step)

Include the last action step if you want to update the draft as well. It will create a new draft with Drafts’ URL scheme. (just check [x] Step enabled on iOS and [x] Step enabled on macOS. The action can then move original draft to trash to avoid duplicates.


First two steps are enough. Works brilliantly for me!