Plug-In: Help Me Plan
REQUIRES: macOS 26, iOS 26, iPados 26, visionOS 26 • OmniFocus 4.8+
This plug-in uses the on-device Apple Foundation Models (AFM) frameworks to assist in the planning of steps for the selected task.
NOTE: Both the task title and its note text serve as the prompt for the AFM.
Related Links: AFM and Omni Automation documentation • AFM Plug-In Collection
Help Me Plan
/*{
"author": "Ken Case",
"targets": ["omnifocus"],
"type": "action",
"identifier": "com.omnigroup.kcase.help-me-plan",
"version": "1.1",
"description": "A plug-in that helps me plan a task",
"label": "Help Me Plan",
"mediumLabel": "Help Me Plan",
"longLabel": "Help Me Plan",
"paletteLabel": "Help Me Plan",
"image": "apple.intelligence"
}*/
(() => {
const schema = LanguageModel.Schema.fromJSON({
arrayOf: {
name: "task-schema",
properties: [
{name: "name", isOptional: false},
{name: "note", isOptional: true},
]
}
});
const session = new LanguageModel.Session();
const helpMePlanTask = async (task, selection) => {
const temporaryItem = addResponseItemToTask({"name": "Thinking…", "note": ""}, task);
console.log("Processing Task:", task.name);
console.log("Schema:", schema);
console.log("Session:", session);
const taskProperties = {"name": task.name, "note": task.note};
console.log("Task properties:", taskProperties);
const prompt = "You're a GTD expert helping someone plan out a project in OmniFocus. Provide a list of steps for the following JSON task: " + JSON.stringify(taskProperties);
const responseJSON = await session.respondWithSchema(prompt, schema);
console.log(responseJSON);
const response = JSON.parse(responseJSON);
for (const responseItem of response) {
addResponseItemToTask(responseItem, task);
}
expandNotes(task, selection.window);
selection.database.deleteObject(temporaryItem);
}
const addResponseItemToTask = (responseItem, task) => {
let responseTask = new Task(responseItem.name, task);
responseTask.note = responseItem.note;
return responseTask
}
const expandNotes = (object, window) => {
console.log("expandNotes: object = ", object);
const contentTree = window.content;
const node = contentTree.nodeForObject(object);
node.expandNote(true);
}
const saveEdits = (selection) => {
const previousSelection = selection.databaseObjects;
selection.window.selectObjects([]);
selection.window.selectObjects(previousSelection);
}
const action = new PlugIn.Action(async (selection) => {
try {
console.log("Help me plan…");
saveEdits(selection);
const projects = selection.projects;
for (const project of projects) {
await helpMePlanTask(project.task, selection);
}
const tasks = selection.tasks;
for (const task of tasks) {
await helpMePlanTask(task, selection);
}
} catch (err) {
console.error(err.name, err.message)
new Alert(err.name, err.message).show()
}
});
return action;
})();