Skip to content

Instantly share code, notes, and snippets.

@brokosz
Created December 19, 2025 15:20
Show Gist options
  • Select an option

  • Save brokosz/a8164daee17d0edd9924e908b0b94ea8 to your computer and use it in GitHub Desktop.

Select an option

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.
#!/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;
}
@brokosz
Copy link
Author

brokosz commented Dec 19, 2025

Usage

TaskPaper → Markdown:

osascript taskpaper-to-markdown.js                    # Current TaskPaper doc
osascript taskpaper-to-markdown.js file.taskpaper     # Specific file

Conversions

TaskPaper Markdown
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 #tag

Output goes to clipboard for easy pasting between apps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment