Org does seem to lack programmatic interfaces for many aspects like this. I would recommend using heading ID's for the application you describe as it virtually eliminates any ambiguity in finding your desired heading. Be sure your desired heading has an ID (you can create it by calling org-id-get-create
with your point on the heading) like the following:
* Task A
:PROPERTIES:
:ID: 22cba7a6-137d-4f06-8547-47a8bf1eb19e
:END:
** Task B
:PROPERTIES:
:ID: 65d813d9-e513-482f-bb65-6430d1027666
:END:
You can then programmatically start the clock using a function like the following:
(defun my/start-heading-clock (id file)
"Start clock programmatically for heading with ID in FILE."
(require 'org-id)
(if-let (marker (org-id-find-id-in-file id file t))
(save-current-buffer
(save-excursion
(set-buffer (marker-buffer marker))
(goto-char (marker-position marker))
(org-clock-in)))
(warn "Clock not started (Could not find ID '%s' in file '%s')" id file)))
(my/start-heading-clock "65d813d9-e513-482f-bb65-6430d1027666" "~/your-task-file.org")
Note that there are other ways of locating the heading. To find a heading using the content of the heading itself you could use:
(find-file "your-task-file.org")
(org-find-exact-headline-in-buffer "Task B" (current-buffer))
(FWIW there is also org-find-exact-heading-in-directory
)
I would recommend something like org-id-find
as org can keep track of the locations of ID's in all agenda files (with org-id-track-globally
). Using that, you only need to specify the heading ID:
(org-id-find "65d813d9-e513-482f-bb65-6430d1027666" t)
The only downside to using this strategy is that org can take a long time updating its ID locations index. I hope this helps!