#!/usr/bin/env npx tsx
/**
* Setup GTD Structure Script
*
* Run this once to initialize a GTD-inspired project and label structure in Todoist.
*
* Usage:
* TODOIST_API_TOKEN=your_token npx tsx scripts/setup-gtd-structure.ts
*
* Or if you have the token in your environment:
* npx tsx scripts/setup-gtd-structure.ts
*/
import { TodoistApi } from '@doist/todoist-api-typescript';
const API_TOKEN = process.env.TODOIST_API_TOKEN;
if (!API_TOKEN) {
console.error('Error: TODOIST_API_TOKEN environment variable is required');
console.error('Usage: TODOIST_API_TOKEN=your_token npx tsx scripts/setup-gtd-structure.ts');
process.exit(1);
}
const api = new TodoistApi(API_TOKEN);
// GTD-inspired structure
const PROJECTS = [
// Work
{ name: 'Work', color: 'blue' },
// Personal hierarchy
{ name: 'Personal', color: 'green' },
{ name: 'Health & Fitness', color: 'green', parent: 'Personal' },
{ name: 'Finance', color: 'green', parent: 'Personal' },
{ name: 'Home', color: 'green', parent: 'Personal' },
{ name: 'Learning', color: 'green', parent: 'Personal' },
// Recurring hierarchy
{ name: 'Recurring', color: 'violet' },
{ name: 'Daily', color: 'violet', parent: 'Recurring' },
{ name: 'Weekly', color: 'violet', parent: 'Recurring' },
{ name: 'Monthly', color: 'violet', parent: 'Recurring' },
// Someday/Maybe hierarchy
{ name: 'Someday/Maybe', color: 'grey' },
{ name: 'Ideas', color: 'grey', parent: 'Someday/Maybe' },
{ name: 'Books to Read', color: 'grey', parent: 'Someday/Maybe' },
{ name: 'Projects to Consider', color: 'grey', parent: 'Someday/Maybe' },
// Reference
{ name: 'Reference', color: 'charcoal' },
];
const LABELS = [
// Context - where/how you can do the task
{ name: 'computer', color: 'blue' },
{ name: 'phone', color: 'green' },
{ name: 'email', color: 'orange' },
{ name: 'errand', color: 'yellow' },
{ name: 'home', color: 'violet' },
{ name: 'office', color: 'blue' },
{ name: 'anywhere', color: 'grey' },
// Energy level required
{ name: 'high-energy', color: 'red' },
{ name: 'low-energy', color: 'grey' },
// Time estimates
{ name: '5min', color: 'mint_green' },
{ name: '15min', color: 'mint_green' },
{ name: '30min', color: 'sky_blue' },
{ name: '1hour', color: 'sky_blue' },
{ name: 'deep-work', color: 'grape' },
// Status
{ name: 'waiting-for', color: 'orange' },
{ name: 'next-action', color: 'green' },
{ name: 'delegated', color: 'yellow' },
];
async function main() {
console.log('š Setting up GTD structure in Todoist...\n');
// Get existing projects and labels
const existingProjects = await api.getProjects();
const existingLabels = await api.getLabels();
const existingProjectNames = new Set(existingProjects.results.map(p => p.name));
const existingLabelNames = new Set(existingLabels.results.map(l => l.name));
// Track project IDs for parent references
const projectIdMap = new Map<string, string>();
for (const p of existingProjects.results) {
projectIdMap.set(p.name, p.id);
}
// Create projects
console.log('š Creating projects...');
let projectsCreated = 0;
let projectsSkipped = 0;
for (const proj of PROJECTS) {
if (existingProjectNames.has(proj.name)) {
console.log(` āļø ${proj.name} (already exists)`);
projectsSkipped++;
continue;
}
try {
const parentId = proj.parent ? projectIdMap.get(proj.parent) : undefined;
const created = await api.addProject({
name: proj.name,
color: proj.color,
parentId,
});
projectIdMap.set(proj.name, created.id);
existingProjectNames.add(proj.name);
console.log(` ā
${proj.name}`);
projectsCreated++;
} catch (err) {
console.log(` ā ${proj.name}: ${(err as Error).message}`);
}
}
// Create labels
console.log('\nš·ļø Creating labels...');
let labelsCreated = 0;
let labelsSkipped = 0;
for (const label of LABELS) {
if (existingLabelNames.has(label.name)) {
console.log(` āļø @${label.name} (already exists)`);
labelsSkipped++;
continue;
}
try {
await api.addLabel({
name: label.name,
color: label.color,
});
existingLabelNames.add(label.name);
console.log(` ā
@${label.name}`);
labelsCreated++;
} catch (err) {
console.log(` ā @${label.name}: ${(err as Error).message}`);
}
}
// Summary
console.log('\nš Summary:');
console.log(` Projects: ${projectsCreated} created, ${projectsSkipped} skipped`);
console.log(` Labels: ${labelsCreated} created, ${labelsSkipped} skipped`);
console.log('\n⨠Done!');
}
main().catch((err) => {
console.error('Fatal error:', err.message);
process.exit(1);
});