Hook to New with Momenta’s Agenda app using x-callback-url

Agenda is an app by Momenta for taking temporal notes.

The Hook to New command enables you to simultaneously create, name, hook and store items in the app of your choice. This is controlled by the Hook to New script. This page provides an example of tailoring the Hook to New script just for Agenda.

If you just want Hook to support Hook to New Agenda notes, skip to the end of this article and follow the instructions there.

For a more detailed explanation, read on.

Hook to New with x-callback-url

For some applications (e.g. Ulysses, Bear, Agenda) the best or only way to create new items programmatically is with x-callback-url.

Agenda’s create-note x-callback-url

Agenda’s x-callback-url support is documented here.

set newNoteURL to "agenda://x-callback-url/create-note?title=" & encodedTitle & "&project-title=" & projectTitle

newNoteURL is an x-callback-url which makes a new note in Agenda.

The parameters are passed as URL query values and must be percent encoded. This can be done with a simple one line python shell script.

title

The standard behavior of Hook to New is to name the new item after the source item it is being created from and linked with. Hook will subsititute the title for $title before executing the script.

set encodedTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of "$title"

project-title

Agenda does not have a default project for new unassigned notes, so user must edit the script to specify the project they want to create new notes in.

set projectTitle to "Hook notes"
set projectTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of projectTitle

x-success

The x-success parameter is a URL. If Agenda successfully creates the note described in the create-note x-callback-url, it appends a query specifying the new note’s ID, and calls it.

set newNoteURL to newNoteURL & "&x-success=" & callbackURL

Hook’s link-to-new x-callback-url

set callbackURL to "hook://x-callback-url/link-to-new?src=" & doubleEncodedSrc & "%26partialURL=agenda://note/%26identifierKey=note%26title=" & doubleEncodedTitle

callbackURL is called with the information Hook needs to link the new note with the source item. Because callbackURL is itself a query value, it must be percent encoded (notably the &s are encoded to %26) and any query values in it must be double encoded, so that they are still encoded when callbackURL is decoded and called.

$encoded_src is the URL of the source item which Hook to New was called on. It is used by Hook to link the new Agenda Note to the original item. Since it is a query value of a URL which is the value of a URL query, it is double encoded

hook://x-callback-url/link-to-new
    ?src=<doubleEncodedSrcURL>
    &title=<doubleEncodedTitle>
    &identifierKey=note
    &note=<identifier>
    &partialURL=agenda://note/

src

The URL of the source item. Since x-callback-URLs work asynchronously, by the time Agenda creates the note and calls back to Hook, Hook may not be open on the source item, so the link-to-new URL must include a reference to it.

This value must be double encoded.

set doubleEncodedSrc to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of "$link"
set doubleEncodedSrc to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of doubleEncodedSrc

title

The title parameter specifies the title of the linked item. The title must also be double encoded.

set doubleEncodedTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of encodedTitle

identifier, identifierKey, note

The identifier of the new item given by x-success should be keyed to identifier.

But the create-note x-success callback keys the identifier of the new note under note, not identifier.

The link-to-new callback can use identifierKey to designate a different query key to find the identifier

&identifierKey=note&note=<note-identifier>

partialURL

Since the create-note x-success callback only includes the identifier of the new note, not the whole URL, we give the first half of the URL here. The identifier is appended to it into the whole URL which is linked together with src.

We haven’t encoded Agenda’s partialURL because it is a static string and we know with certainty that partialURL=agenda:// doesn’t contain any characters which will break the URL if they’re not encoded.

return placeholder URL

The last line of the script has to be get "hook://link-to-new-callback", because Hook expects it to return the address of the new document. Since the linking is done with x-callback, we don’t need to return a valid URL and return “hook://link-to-new-callback”, a placeholder.

Integrating Hook to Hook to New Agenda notes

  1. Copy the following script to the Hook to New script field for Agenda in Hook Preferences>Scripts.
  2. Replace “Hook notes” in the first line (set projectTitle to "Hook notes") with the project of your choice. Agenda doesn’t have a default project for new notes, it has to be specified.
set projectTitle to "Hook notes"
set projectTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of projectTitle

set encodedTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of "$title"

set newNoteURL to "agenda://x-callback-url/create-note?title=" & encodedTitle & "&project-title=" & projectTitle

set doubleEncodedTitle to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of encodedTitle

set doubleEncodedSrc to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of "$link"
set doubleEncodedSrc to do shell script "python -c \"import urllib, sys; print (urllib.quote(sys.argv[1]))\" " & quoted form of doubleEncodedSrc

set callbackURL to "hook://x-callback-url/link-to-new?src=" & doubleEncodedSrc & "%26partialURL=agenda://note/%26identifierKey=note%26title=" & doubleEncodedTitle
set newNoteURL to newNoteURL & "&x-success=" & callbackURL
do shell script "open '" & newNoteURL & "'"
get "hook://link-to-new-callback"