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;})();