I have a Markdown list like this:
* Problem: Three bodies
* Solution: Use two bodies only
* Action: Take a body away
and I want to convert this list into a Markdown table like
| Category | Description |
|----------|-------------|
| Problem | Three bodies |
| Solution | Use two bodies only |
| Action | Take a body away |
In the past I have done these type of changes with a few replace commands in my editor, but AI (I’m running gemma3 via ollama) is pretty good at it as well. In a Gemma chat this is easily done, but I have copy the portion first into the chat and then the result back.
Is there a way to use one of DEVONthink’s AI tools for this? I tried Edit → Transformations → Transform Text via Chat, but couldn’t get it to work (I don’t see how I can give there the AI instructions…)
Any pointers are appreciated!
EDIT I leave that here, though the OP wasn’t looking for a solution to the problem they posted. Perhaps the code is useful for someone else.
Well, here’s an alternative that is a bit nicer to the planet than asking AI to burn another kiloton of petrol for a trivial task.
(() => {
Application("DEVONthink").selectedRecords()
.filter(r => r.recordType() === 'markdown')
.forEach (r => {
const matchingLists = [...txt.matchAll(/((^\*.*?(?:\n|$)){2,})/gm)];
matchingLists.forEach(singleListMatch => {
const list = singleListMatch.shift(); /* the whole list */
const table = list
.split('\n')
.filter(listElement => !/^$/.test(listElement))
.map(listElement => {
const parts = listElement.replace(/^\*\s+/,'').split(':');
return `| ${parts[0].trim()} | ${parts[1].trim()} |`;
})
r.plainText = txt.replace(list,
`| heading 1 | heading 2|
------------------------
${table.join('\n')}\n`);
}) /* map listElement
}) /* forEach singleListMatch*/
})
Standalone JavaScript that converts all lists with at least two elements in the selected markdown files into tables. The headings are, of course, not chosen very intelligently.
How it works
- First, only MD records are kept from the current selection (
filter(r => r.recordType()...
)
- Then a
forEach
loop handles all these records
- The regular expression in the line
const matchingLists
greps all lists in the MD file using a capturing group so that the whole list is captured if it consists of at least two items ({2,}
)
- The first non-capturing group is needed so that the “at least two” operator gobble up all lines, not only the last one.
- The second non-capturing group (
(?:\n|$)
) ensures that a list without a following newline (ie the last one in an MD file) is handled correctly
- So
matchingLists
is an array of arrays, where the first element of each sub-array is an MD list.
forEach
then loops over each of these inner arrays and puts its first element into list
. That is simply the list as a string.
- This string is then
split
at the newlines, resulting in an array consisting of the lines of the list.
filter
removes empty lines from this array
- Then
map
converts each line into an MD table line after having removed the leading '* '.
- Finally, the
plainText
attribute of the MD file is updated by replacing the original list with the newly created table.
Disclaimer: The code is only rudimentarily tested, i.e., with an arbitrary text, not with a selection of MD files. You should first test it on copies of your files and verify that it does what you want.
If you want to use it at all, that is – given that it’s only the product of HI.
5 Likes
Thanks @chrillek. HI is always appreciated! 
However, the transform to a table was meant as an example. If I know how to ask the AI inside DEVONthink, I might ask it other things as well like convert headings and following paragraphs into defnition lists or vice versa.
And if the AI doesn’t do a good job (which is quite often the case), then JS or Elisp are always alternatives of fun.
So the question stands for me: How can I do the transform of a text portion of a DEVONthink document through DEVONthink’s own AI tools?
See e.g. Scripts > Chat > Translate Text… or Scripts > Chat > Transform Text… for some examples.
1 Like
Saying so would have saved me some time.
If you know Elisp and JS, I don’t really see the point of jumping through all these AI loops. Especially given the CO2 differential between these approaches. Call me old-fashioned.
3 Likes
Why are you trying text transformations versus a prompt?
Sent to GPT 5 (Mini) via the Chat assistant
convert this text into a Markdown table and append it to the document's text.
PS: The documentation states what transformation does so there’s no reason to guess or overthink these things.
You can even ask the Help Assistant about it…
2 Likes
My apologies! I certainly didn’t phrase this well. My question was intended to be about how to use DEVONthink’s AI capabilities for text transformation. Really sorry again!
Well, I want to get better at using AI – and at knowing when not to use it. For this I attempt to do more experiments with it.
Very good point. Certainly to be kept in mind. I hope using a local model mitigates thsi somewhat.
Thanks @cgrunenberg. Will look at them.
Interesting that the Chat assistant can do this! Thanks for this. Will for sure try this out!