DEVONthink as bookmark manager, revisited

After trying a bookmark manager, I decided no, I really wanted my bookmarks in DEVONthink, for convenience of filing, privacy protection, and having one place to search for information.

Unfortunately I’ve also concluded that regular bookmarks (i.e. Apple webloc files) aren’t good enough. The problems:

  • There’s no way to put a description or keywords or anything else useful into the file. You can put a description in the Finder comments, and I tried that for a while, but…
  • In DEVONthink, the smart sorting suggestions don’t work unless you actually load the page, which also means you don’t seem to get filing suggestions based on other bookmarks. This makes filing a very manual process.

I considered storing pages as formatted text, but that’s bad because they’re often huge, because of how bloated modern web pages are. Web archives are just as bloated.

So… I decided I wanted to store my bookmarks as Markdown consisting of a heading, a clickable URL, and then arbitrary description, hashtags, and so on. The problem was to convert my hundreds of existing bookmarks.

Step 1 is easy: tell DEVONthink to import the bookmarks from an HTML file written out by the bookmark manager.

Step 2 is also easy: tell DEVONthink to convert the bookmarks to Markdown. It goes away and fetches the corresponding page, and cleans it up.

Unfortunately the cleaned page is often still full of junk. Sometimes the web site is constructed badly and you get nothing useful, or they are blocking based on user agent to try to stop bulk AI scraping. In that case I settled for opening the web page, doing select all, copy, and then paste into the markdown in DEVONthink, because of the next step…

Step 3 for me was getting Apple Intelligence to summarize the markdown. That turns out to be tricky, because as far as I can discover you can’t call Apple Intelligence from AppleScript. You can call it from Shortcuts, but you can’t call DEVONthink from Shortcuts. So I flailed around until I’d worked out how to put together a shortcut to summarize text, and AppleScript to call it. Wrapping a loop around to do the rest was fairly easy.

Here’s what the Shortcut looks like:

[iCloud link to Shortcut]

Here’s the AppleScript:

tell application "DEVONthink"
	set theSelection to the selection
	try
		show progress indicator "Summarizing…" steps (count of theSelection)
		repeat with theRecord in theSelection
			set theName to name of theRecord
			set theURL to URL of theRecord
			set theGroup to parent 1 of theRecord
			set sourceMarkdown to markdown source of theRecord
			step progress indicator theName
			tell application "Shortcuts Events"
				set theSummary to run shortcut "Summarize text" with input sourceMarkdown
			end tell
			set markdownContent to "# " & theName & linefeed & linefeed & ¬
				"<" & theURL & ">" & linefeed & linefeed & theSummary
			set newRecord to create record with {name:theName, |type|:"markdown", content:markdownContent} in theGroup
			set creation date of newRecord to creation date of theRecord
			set label of newRecord to label of theRecord
			set flag of newRecord to flag of theRecord
			set URL of newRecord to theURL
			delete record theRecord
		end repeat
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

The script creates a new item and then deletes the old one because I couldn’t persuade DEVONthink to let me update the markdown content of items. Probably something I was doing wrong in AppleScript, which I continue to dislike intensely.

After summarizing, I end up with small markdown documents with summaries. The summaries aren’t always great, but they’re good enough for searching and sorting, which is why I want them. I then go and delete any Assets DEVONthink automatically brought in (since that’s my normal preference).

I order the documents title - link - summary, whereas DEVONthink’s convert to markdown puts the link first then the title. I prefer the title first, and it also gives me a way to see if I’ve fed a particular document through the summarizer yet.

Thanks to this project I can report that after a few hundred uses of Apple Intelligence it stops working (probably due to a memory leak) and you have to reboot your Mac. Maybe they vibe coded it.

Anyway, hope this helps anyone else tackling the same problem.

Can you please post an example of such bookmark created ?

# It's Now Possible To Sign Arbitrary Data With Your SSH Keys

<https://www.agwa.name/blog/post/ssh_signatures>

It is now possible to sign arbitrary data with SSH keys, offering a viable alternative to PGP. SSH signatures are easier to use, widely available, and offer optional lightweight certificates. This feature will soon be available for signing Git commits and tags in Git 2.34.

The SSH protocol signature input differs from the ssh-keygen signature input, preventing cross-protocol attacks and allowing the use of existing SSH keys for signing messages. While openssl can be used to sign with SSH keys, it lacks the namespace parameter, making SSH signatures safer for multiple purposes. The signing feature was added to OpenSSH in version 8.1, allowing arbitrary data to be signed with SSH keys.

Sadly Apple Intelligence via Shortcuts has now broken itself to the point where reboots no longer seem to fix it. Safari can still summarize things, which suggests that maybe the bug is in Shortcuts.

Are you running the shortcut just to use Apple Intelligence? While its use in DEVONthink is in testing, YMMV. I would recommend using a better AI engine than Apple’s offering.

Also, in DEVONthink we offer more than one way to handle the task you’re proposing – yes, in AppleScript – and with varying levels of customizability.

Done directly in DEVONthink…

1 Like

An upcoming release will support this via AppleScript:

But at the moment I would recommend e.g. Ollama and Gemma 4:26b or Qwen 3.6:35b (depending on your hardware). Hopefully WWDC 2026 will introduce much more powerful foundation models, the current one feels like early 2023 :wink:

3 Likes

And maybe fix their UI and PDFKit and get WebKit/Safari up to par with current browsers… Ah well, one can hope.

I realize Apple Intelligence isn’t as good as the commercial offerings, but I’m not willing to financially support any of them. I plan to write my own summaries going forward, I just needed a quick hack to let me convert my backlog of bookmarks, because going through 1,240 items manually wasn’t an option.

I guess I could run something else locally, but I don’t know how I’d call that from AppleScript. I know there are Mac applications for running models locally, but I’ve no idea which ones might be scriptable.

You could e.g. install Ollama or LM Studio, download a model (e.g. Gemma 4:26b) and then use DEVONthink and its get chat response for message AppleScript command, see screenshot above.

1 Like

And following up on @cgrunenberg’s recommendation, here is a script that follows the output you illustrated…

on run
	tell application id "DNtp" to my performSmartRule(selected records)
end run

on performSmartRule(theRecords)
	tell application id "DNtp"
		repeat with theRecord in (theRecords)
			show progress indicator "Summarizing…" steps -1

			set {crDate, recLabel, recFlag, recURL, recName, recType} to {creation date, label, flag, URL, name without extension, record type} of theRecord

			set thePrompt to "From the text of the selected document, return Markdown formatted text explicitly in this format:
			The title as an H1 header on the first line.
			<" & recURL & "> on the second line.
			Summarize the text in the selected document in no more than two paragraphs.
			Lastly, provide one or two key points from the text as an unordered list at the end of the response.
			Do NOT vary from these instructions." -- There is no guarantee you can force AI to comply here.

			set theReply to get chat response for message thePrompt engine Ollama model "qwen3:8b" record theRecord temperature 0.4 -- Logically, change the engine and model as needed.

			if theReply is not in {"", missing value} then
				set summaryDoc to (create record with {name:recName, record type:markdown, content:theReply} in (parent of theRecord))
				if exists summaryDoc then
					set properties of summaryDoc to {creation date:crDate, label:recLabel, URL:recURL, flag:recFlag}
					move record theRecord to (trash group of theRecord's database)
				end if
			end if

			hide progress indicator
		end repeat
	end tell
end performSmartRule

This script is built to run as a standalone script, especially useful for testing, but also for the Apply Script smart action in smart rules and batch processing.

PS: I only added the progress indicator here since local models are going to take more time to generate a reply. With commercial models, it happens quickly enough to not warrant it IMHO.

PPS:

because going through 1,240 items manually wasn’t an option.

I would not try to process over 1200 bookmarks in one go, especially if you’re going to try a local AI model on a Mac with less than 24GB RAM.

1 Like