Back to the schedule
Previous: One effective CS grad student workflow
Next: Creating technical API documentation and presentations using org-babel, restclient, and org-treeslide

Using Org-Mode For Recording Continuous Professional Development

Philip Beadling


Q&A: live Q&A or IRC
Duration: 10:33

If you have questions and the speaker has not indicated public contact information on this page, please feel free to e-mail us at and we'll forward your question to the speaker.


I recently had the pleasure of being audited for my CPD record with one of the large engineering professional bodies. I decided to harness org-mode's TODO lists to record CPD items and my progress against them completely within Emacs. I also wanted the ability to export the data in a well presented, compact format for auditing submission.

The project was a success (I passed the audit) and the resulting system integrates really well into my wider daily Emacs workflow, making future CPD recording seamless.

The talk will explain how I tweaked and extended org-mode to get it to record the data I wanted, followed by a demo.

A basic demo org file with embedded elisp can be seen here:

A basic generated PDF from the basic demo is here: img

I have a much more involved example I could also use for the demo.

The template contains a few examples. Examples are Goals that are split up into Activities. All Activities must have a Goal, and within a Goal all activities must be complete for the Goal to be automatically set to complete.

It's basically leveraging Org Capture Templates to create custom Goals and Activities.

On save or update these are then rendered into a table using Column View.

Activities are sorted by date they were completed on.

The Column View is pre-configured to be exported to PDF in a condensed but readable format for submission. It stays fairly readable even when the pages get busy.

The elisp required is all under the "Config" bullet and Emacs will ask to execute it on opening the Org file. The elisp concerns itself with nice custom org capture functions and a few functions to ensure nice formatting on export, etc.


IRC nick: pbeadling

  • Very impressive use of capturing
  • This is madness, and I am a little ashamed of saying that I have wanted to do something similar for personal reasons. I feel it is an overkill I cannot justify to myself
    • pbeadling: For me it largely motivated by trying to make the whole task more interesting
      • i think of like lots of us falling in lots of rabbit holes, making for quite a cavernous attack surface, when we consider Emacs is including it's various package arcives.
  • hmm, hooking is a neat way to check in/ouut
  • the workflow looks good but why he isn't integrating this with org agenda ?
    • pbeadling: Agree - merging with org-agenda is the next thing I want to do with this
    • pbeadling: For the CPD thing the biggest limitation I think is that you have to have the org file in the current buffer to add items - really you want to be able to capture CPD items from anywhere in your workflow - when I get some time I'll update the script to integrate better with capture and agenda like this.


  • 5-10 minutes:

A quick walkthrough of the setup and functions, followed by a demo of how to add CPD items, and update them. Finally show generation of a PDF containing all the items tabulated and ready for audit review. I estimate this at approx 10 minutes.


Hello everyone! My name is Philip Beadling. Just to give you a bit of background, I'm the enterprise architect in a company called Quantile Technologies. I've been using Emacs certainly for the last four or five years as part of my day-to-day workflow, but I've used it on and off for the last 20 years depending on the jobs or the task at hand.

[00:00:22.423] Now, today I'm here in a personal capacity to talk about a use I had for Emacs last year where I had to record my continuous professional development, and I was required to be audited by my professional body on it. My CPD record is a bit of a mess, or certainly was. It was over various different services and systems that have been provided to me by previous employers. And, I had bits of it in Excel spreadsheets, and I was looking for like a one single golden source where I could store it all and use in the future.

[00:00:56.719] So, I had a look online. I didn't find anything I'd like, so I decided I would use Emacs, and I quickly came to the conclusion that using Org mode was a nice fit for this, you know, both the TODO lists and the properties seem to fit nicely with building a very basic database, which is what in effect this is, what this is.

[00:01:16.159] Without further ado, I will start by just downloading. This is available on my public Git, handle is falloutfill, and it's under a project called Misc. It's just a single file called, I can stick that in the chat when we actually do this live, so that people will have a link to it. So, I'll start this up.

[00:01:41.119] Okay. To start with, I am just going to close down various Lisp stuff, and just give you a demo of how it actually works. Let's go up here. Okay, so, basically to make this work, the way I subdivide it is that I would have professional goals, and professional goals would be made up of activities, and each of those activities would contribute to the goal. So, in order to represent this, this is just a nested TODO list in Emacs Org mode. I sort of change things like the naming, Pending, In-Progress and Complete rather than TODO, DONE because that's more like what my professional body likes to categorize things, but essentially it's the same thing. So, I've got an Org capture template or two Org capture templates in order to grab this information, and then stick it in the TODO list, and also tabulate it using column view.

[00:02:36.540] I'll start off just by showing you an example here. So, what I'm going to do is create a new goal, and then under it, I will create a couple of activities relevant to that goal. For the goal I'm going to have, let's say, something relevant, so, 'Improve Public Speaking', and then I'm going to say, the type of that goal is, well, it's a 'Presentation' I suppose. The outcome of that goal is, well, I don't want to go into too much detail here, but it would be, you know, 'Get feedback from colleagues', and so forth. I won't fully and completely inaudible about what the goal was. Now, the retrospective value, my understanding is that you fill that in afterwards, so you want to talk after completing the action, so this is not relevant for the day. I'm just going to leave it blank, although I'm sure you can imagine I could say: having completed this action I felt that, blah blah blah, and so forth. Okay, so I will add that, and then you will see that I now have a new goal, both in my column view and in my TODO list, and just to make it a little bit realistic, I'm going to then add two activities to that. When I come in to add an activity, I have to select a goal. I'm going to select 'Improve Public Speaking'. Yeah, so, the activity I'm going to say is, well, let's say, 'Speak at EmacsConf 2021', that we can use a type of 'Presentation', outcome of that is, stating the obvious, 'Present on an Emacs idea'. Right, something along the lines of that. And, then retrospective, again I'm not going to fill that in at the moment. Then, last but not least, I will come up with a slightly different activity. So, again selecting 'Improve Public Speaking', the activity would be 'Watch lecture series on public speaking', you know, blah blah blah, so forth. Type value would be Lecture, for this outcome would maybe be 'Use new knowledge in EmacsConf presentation'. Right, might be a good one there. Again, retrospective value, I'm just going to leave that blank, and I'm going to save that.

[00:04:51.440] Now, we're in a position where we've got a goal and two activities, which are represented here, you can see here that I can move an activity, cycle it forward to In-Progress. When I do that, I get a STARTED timestamp here. If I then cycle it again, I get the more familiar CLOSED timestamp here. The STARTED timestamp is a bit of custom code, I'll show you that in a moment. And then likewise, let's say that…, we'll move this one from PENDING to STARTED. Okay. Now, if I save the document, that will trigger the updating of the column view, you can see now that we have the various started and completed statuses, this is up to date. So, that's pretty much.

[00:05:32.937] You can imagine that we could add lots of goals and lots of activities, and this would grow into, you know, several sheets worth of a work, and then last but not least, is obviously the most important thing. How do you submit it? We could just use the standard export facility in Org mode for doing that. That's just Control c Control e l o (C-c C-e l o). And there you can see, there you've got the goals and activities. I spent a bit of time, I won't go too much in the LaTeX formatting, but coming up with something that I felt and got as much information compactly on a page without making it difficult to read, should we say, and it's always a find-the-balance thing. I'm not saying I'm an expert on it, but I thought what I came up with here was reasonably clear but allowed you to write enough information. The goals and activities were reasonably well explained. Okay, we can just kill that.

[00:06:35.039] So, how does all of that work? Well, underneath is config tab here, we have a bunch of Lisp that I'm going to sort of fly through here. You can ask me any questions afterwards. First thing is, we have the org-capture templates, which are here. The goal one is not doing anything special. It's just writing it back to this file, so there is a limitation there that you must have this file open when you add them, which is something I'd like to improve in future.

[00:07:02.000] For the activities, it specifies the file, but it also specifies this function set-activity-pos-from-goal, which (is) above here. What this does is, it iterates through the various Org entries looking for goals, and once it has a list of goals, it presents them to you using ido-completing-read, so that you can select the goal that you want the activity to live underneath, and it then searches forward, and it finds the appropriate spot in that goal that the Emacs can then dump the captured activity.

[00:07:36.000] Okay, the next one is pretty straightforward. Because I changed the names of the TODO, DONE, I now need a new way of aggregating the summary completion statuses. So, for this I'm just looking at the number of completed activities over the total number of activities, and I make that available on the C+ here, which we will see when I go and show you the top configuration in the Org document in two minutes.

[00:08:05.199] I mentioned that we needed to have our own start date. The way this works is we add a hook to org-after-todo-state-change-hook, which means that we test the state change results in one of the items being In-Progress, and if that's true and it already doesn't have a time stamp, then it creates a timestamp with the current time and date. The second hook here is just ensuring that when we save the document, that the column view is dynamically updated, so that everything is up to date. And then last but not least here, the tmp-f-timestamp, what this does is, on the export, it modifies the timestamps, so that it removes the angle brackets, and it removes the hours and minutes. That is a space-saving thing and a tidiness thing in the PDF. I'll show you in a second how that's used. We then allow bind-keywords. We use them above. Then we just have a simple key that allows us to hotkey for org-capture. And then at the start, when we evaluate the startup block that I have of Lisp, just so it's already there, and set the number of sublevels to one so only the top levels exist. Coming back over the top to put that all back together again. The startup just tells you that you want log times. The title, author, description, and…, they should be obvious, right, that's just text for the PDF. Options, we disable the table of contents, we do not want that.

[00:09:34.320] Now, the output config here, the first two are resulting in the timestamp formats, so, that was the tmp-f-timestamp function I showed you below. And, we got a better LaTeX stuff here, just saying that we want a landscape, and we want to use A4 paper size, and then the columns here. What we want is just to rename the properties to something which just looks a little bit nicer in the table. So you can see that: goals, activities, status, completed, and so forth.

[00:10:00.979] Then last but not least, on the actual thing, we use a longtable in LaTeX. We align, so we specify very exactly that we want five centimeters for the first and last two columns, and that we want all the other columns to use the remaining space. And that's it.

[00:10:19.040] Appreciate, I've absolutely whirlwinded through that, but please do feel free to ask me any questions, or speak to me offline. Thank you very much.

Back to the schedule
Previous: One effective CS grad student workflow
Next: Creating technical API documentation and presentations using org-babel, restclient, and org-treeslide