Created
December 19, 2025 15:20
-
-
Save brokosz/a8164daee17d0edd9924e908b0b94ea8 to your computer and use it in GitHub Desktop.
JXA script to convert TaskPaper documents to Markdown format for Obsidian or other needs. Handles projects, tasks, tags, and completion status.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env osascript -l JavaScript | |
| function run(argv) { | |
| const app = Application.currentApplication(); | |
| app.includeStandardAdditions = true; | |
| let content; | |
| if (argv.length > 0) { | |
| // Use file from command line | |
| content = app.read(Path(argv[0])); | |
| } else { | |
| // Use current TaskPaper document | |
| content = Application('TaskPaper').documents[0].evaluate({ | |
| script: `function(editor, options) { | |
| return editor.getTextInRange(0, editor.textLength); | |
| }` | |
| }); | |
| } | |
| const lines = content.split('\n'); | |
| let markdown = ''; | |
| for (let line of lines) { | |
| if (line.trim() === '') { | |
| markdown += '\n'; | |
| } else if (line.trim().endsWith(':')) { | |
| // Project (header) | |
| markdown += `## ${line.trim().slice(0, -1)}\n`; | |
| } else if (line.trim().startsWith('- ')) { | |
| // Task - check if archived | |
| const task = line.replace(/\s*-\s*/, '').replace(/@(\w+)(?:\(([^)]*)\))?/g, (match, tag, value) => { | |
| if (tag === 'due' && value) return `#due-${value}`; | |
| if (tag === 'done' && value) return `#done-${value}`; | |
| if (tag === 'start' && value) return `#start-${value}`; | |
| if (tag === 'project' && value) return `#${value}`; | |
| return value ? `#${value}` : `#${tag}`; | |
| }).trim(); | |
| if (task) { | |
| const isArchived = line.includes('@done') || line.includes('@archived'); | |
| markdown += isArchived ? `- [x] ${task}\n` : `- [ ] ${task}\n`; | |
| } | |
| } else if (line.trim().startsWith('+ ')) { | |
| // Completed task | |
| const task = line.replace(/\s*\+\s*/, '').replace(/@(\w+)(?:\(([^)]*)\))?/g, (match, tag, value) => { | |
| if (tag === 'due' && value) return `#due-${value}`; | |
| if (tag === 'done' && value) return `#done-${value}`; | |
| if (tag === 'start' && value) return `#start-${value}`; | |
| if (tag === 'project' && value) return `#${value}`; | |
| return value ? `#${value}` : `#${tag}`; | |
| }).trim(); | |
| markdown += `- [x] ${task}\n`; | |
| } else { | |
| // Note | |
| markdown += `${line}\n`; | |
| } | |
| } | |
| markdown = markdown.replace(/\n+$/, '\n'); | |
| app.setTheClipboardTo(markdown); | |
| console.log("Converted TaskPaper to Markdown and copied to clipboard"); | |
| return markdown; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage
TaskPaper → Markdown:
Conversions
Project:## Project- task- [ ] task- task @done- [x] task@due(2025-12-18)#due-2025-12-18@start(2025-12-18)#start-2025-12-18@project(Name)#Name(capitalized)@tag#tagOutput goes to clipboard for easy pasting between apps.