The function below evaluates Lisp forms stored in properties of a task, when it changes to a certain state. The function is supposed to be added to the =org-after-todo-state-change-hook=. The property should be named =ON_= where =STATE= is a state defined in =org-todo-keywords=. See also the example task below (open this file in [[https://apps.bram85.nl/gitea/bram/gists/raw/branch/main/gists/evaluate-code-on-task-state-change.org][raw mode]] to see the properties). #+begin_src elisp (defun my/task-state-event-handler () "Evaluate a Lisp form attached to the task whose state is being changed. When this function is added to org-after-todo-state-change-hook, it looks for a Lisp form stored in the property called ON_ where STATE is the new state of the todo item. When the state is cleared, ON_CLEAR will be used. Example: ,* TODO Example task :PROPERTIES: :ON_PROGRESS: (message \"Busy!\") :ON_DONE: (message \"Done!\") :ON_CLEAR: (message \"No state.\") :END:" (when-let* ((state (or org-state "CLEAR")) (event-property-name (concat "ON_" state)) (code-string (cdr (assoc event-property-name (org-entry-properties)))) (code (car (read-from-string code-string)))) (org-eval code))) (add-hook 'org-after-todo-state-change-hook 'my/task-state-event-handler) #+end_src * TODO Example task :PROPERTIES: :ON_PROGRESS: (message "Busy!") :ON_DONE: (message "Done!") :ON_CLEAR: (message "No state.") :END: