My Obsidian Generic Meeting Template

Contents

In many of my posts I share solutions to technical challenges I have come across. In this post there is certainly an element of that, but it is building on some earlier work and is perhaps more about sharing a real view of what I use day to day, as a way of providing a bit of insight or inspiration into how you may be able to employ something similar. Specifically, in this post I am going to share some details of my “general” meeting template in Obsidian. Oh, and that’s “general meeting” template as in a generic template for a general, run of the mill, ad hoc meeting, not a general meeting as in governance (e.g. AGM, EGM).

A Bit About My Template

As a bit of advanced warning, if you are looking for a great template to help you master your meetings, this is not going to be what you are looking for. I am not sharing any deep insights into running “better” meetings (for that check out something like “The Surprising Science of Meetings”) or how to create a template to allow you to take perfect meeting notes. Rather I am showcasing some of the technical elements I utilise in creating notes for general meetings in Obsidian.

My general meeting template is intentionally fairly sparse on headings and is intended to be open ended. I have more specific templates for recurring meetings, but this one is, of course, intended to cover me for infrequent or ad hoc meetings, which is what at least half the meetings I attend could be categorised as.

Prerequisite Plugins

I have two prerequisite plugins for my general meeting template.

The first is the Templater plugin which provides a vast amount of additional functionality over Obsidian’s core Template plugin. This plugin is used to create a link to the meeting, to capture information about the meeting, and to create the new meeting note content.

Templater is a template plugin for Obsidian.md. It defines a templating language that lets you insert variables and functions results into your notes. It will also let you execute JavaScript code manipulating those variables and functions.

The second is the Dataview plugin which provides an advanced query language with which to interrogate your Obsidian vault for information about your notes. My template incorporates a little bit of Dataview syntax to help me provide links to some recent and potentially related content.

Treat your Obsidian Vault as a database which you can query from. Provides a JavaScript API and pipeline-based query language for filtering, sorting, and extracting data from Markdown pages

These are probably my two most utilised plugins, so if you do not have them installed in your Obsidian vaults, I would heartily recommend that you do, and you will need them if you want to employ the things I will go through here.

Each day, I generate a daily note in my main Obsidian vault. I use my daily note to keep a track of the activities I have been involved in that day and to manage my rolling task list, logging any completed items to that daily note. This includes creating links to any meetings that took place that day.

While I could use Dataview to build a list of those meetings, based on all my meetings starting with the day’s date stamp, I opt instead to link them into the note in the order they occur during the day. I can create notes ahead of time, so sorting on time data is not really an option for me, and if I want to add any additional notes alongside links to individual meetings, I can; though I do so rarely - usually they are in the note.

I have written about a couple of approaches previously in generating links to notes and the notes they link to, and I am still employing the approach I created in 2022. This utilises a Templater script I created for buildPageAndLink, and the details about the approach, the script, and how to set things up can be found in that post. If you are unfamiliar with how to use scripts in Templater, I would recommend you read that post before continuing with this one as I have employed the same approach below, but with a small addition.

The buildPageAndLink function takes five parameters.

  1. The Templater object.
  2. The name of the template to create the new note from.
  3. The name of the new note file.
  4. The relative path of the folder to hold the new note file.
  5. A Boolean to indicate if the note file name should be prefixed with a date stamp.

My meeting template is called “M.Meeting - General (Template)”, and I create new general meetings in my vault root (ready to be filed), with a date stamp prefixed. A template with a call to buildPageAndLink might therefore look like this.

<%* tR += await tp.user.buildPageAndLink(tp, "M.Meeting - General (Template)", "Change the Title", "", true); %>

Of course, unlike other standard meetings, the title could vary, so here I have a placeholder of “Change the Title”. That isn’t great, but Templater has a feature we can take advantage of. With a small amendment, we can replace the placeholder with some script that will have Templater prompt us for the name of the note.

<%* tR += await tp.user.buildPageAndLink(tp, "M.Meeting - General (Template)", await tp.system.prompt("Enter a title for the meeting", "", true), "", true);%>

I have this saved to a template called “L.Link - General Meeting (Template)”, so to insert the link at the cursor position and create the file, I select my Templater keyboard shortcut, type in the “l.gen”, which due to my naming approach and set of templates available, filters my list and places “L.Link - General Meeting (Template)” right at the top. I then tap return, At this point, Templater prompts for the name of the meeting, and so this is fed into the creation of the link and the file.

I also have variations on this. The first is one that also prompts me to enter the date stamp for a meeting. This is useful when I am preparing notes (e.g. with questions to ask), days before the meeting. I can create the daily note ahead of time, and create the link and note in the same way as before, other than it uses the specified date stamp rather than the date stamp of the current day.

<%* tR += await tp.user.buildPageAndLinkSetDate(tp, "M.Meeting - General (Template)", await tp.system.prompt("Enter a date stamp for the meeting", tp.date.now("YYYY-MM-DD"), true), await tp.system.prompt("Enter a title for the meeting", "", true), "", true);%>

You may have noticed that this uses a different function. This is because I get a bit more re-use by centralising the logic this way.

async function build(p_tp, p_strTemplateName, p_strDatestamp, p_strName, p_strFolderPath, p_bPrefixDateStamp = false)
{
	let strName = p_strName;
	if (p_bPrefixDateStamp) strName = p_strDatestamp + " " + strName;
	let fFolder = app.vault.getAbstractFileByPath(p_strFolderPath);
	let fTemplate = await p_tp.file.find_tfile(p_strTemplateName);
	let strContent = await app.vault.read(fTemplate);
	await p_tp.file.create_new(strContent, strName, false, fFolder);
	return "[" + "[" + strName + "]]";
}
module.exports = build;

I also have a version that creates it with tomorrow’s date. The day I most often prepare for an upcoming meeting is the day before, so I have a version just for that too.

<%* tR += await tp.user.buildPageAndLinkTomorrow(tp, "M.Meeting - General (Template)", await tp.system.prompt("Enter a title for the meeting", "", true), "", true);%>

As I am sure you will have noted, there is indeed another function to help support this.

async function build(p_tp, p_strTemplateName, p_strName, p_strFolderPath, p_bPrefixDateStamp = false)
{
	let strName = p_strName;
	if (p_bPrefixDateStamp) strName = p_tp.date.tomorrow("YYYY-MM-DD") + " " + strName;
	let fFolder = app.vault.getAbstractFileByPath(p_strFolderPath);
	let fTemplate = await p_tp.file.find_tfile(p_strTemplateName);
	let strContent = await app.vault.read(fTemplate);
	await p_tp.file.create_new(strContent, strName, false, fFolder);
	return "[" + "[" + strName + "]]";
}
module.exports = build;

The General Note Template

At this point, the note and a link to the note for the general meeting have been created. Actually that’s a lie, but the reason for that will become clear as we take a look at my template.

Below is my M.Meeting - General (Template) template in its entirety. I’ll break it down and explain the purpose of each section below.

---
projectid: ""
notetype: "meeting"
meetingtype: ""
---
# Attendees
- Stephen Millard
- ???

# Meeting Details
- **Topic:** <% tp.file.title %>  
- **Location:** <% tp.system.suggester(["Virtual", "In Person"], ["Virtual", "In Person"]) %>
- **Date:** <% tp.file.title.split(" ")[0] %>
- **Time/Duration:** xx:xx - xx:xx

# Agenda
- 

# Notes
- 

# Actions
- 

# Recent Meetings
```dataviewjs
dv.view("/00-09 Meta/00 System Data/00.08 Data View/dv_MeetingListing");
```
---
**Tags:** 

Template Section: Meta Data

---
projectid: ""
notetype: "meeting"
meetingtype: ""
---

My standard template contains a section at the start that contains a set of meta data about the note. You may also hear this referred to as “front matter”, or even as YAML, which is the syntax it uses.

There are three properties defined in this section, and they are intentionally set to single text-based values.

projectid is an ID I use to indicate what area of work the meeting falls into. I match this up to my Johnny Decimal structure, and have some generic IDs that are useful ‘buckets’ as well as IDs for specific projects.

If you also use a Johnny Decimal set up in your Obsidian vault, then after you finish this post, you might find it useful to read my post on utilising Johnny Decimal indices for searching in Obsidian.

notetype is the only pre-populated property. It is set to meeting indicating for my purposes that this is a note for a meeting. I have many other types of note, but this will always be meeting as the template will always be used for meeting notes.

meetingtype is a property I use for sub-classification of meetings. Often this is blank, but I did find I used it extensively in my previous job.

Template Section: Attendees

# Attendees
- Stephen Millard
- ???

My attendees section is just a bulleted list of people who were in the meeting. I rarely bother to note who was not in the meeting, but occasionally I might note something in the body of the notes if, for example, a particular point could not be discussed because a requested attendee was unable to join.

It may be worth noting that I also add each attendee as a link, and I have pages about many of the people I interact with. Things like lists of projects we have worked on together, who their line manager or alternative contact is, what part of the world they live in (useful for considering time zones for meetings), what specialist skills they have, etc. Anything non-sensitive and useful in the context of my work that I risk forgetting if I don’t write it down.

An attendee list for an internal meeting might end up looking like this.

# Attendees
- Stephen Millard
- [[Bruce Wayne]]
- [[Dick Grayson]]

Whereas for an external meeting, I might break it into sub lists for different organisations

# Attendees
- Conflict Resolutions Services Inc.
	- Stephen Millard
	- [[Marian Fitzwater]]
- Nottingham Forestry Commission
	- [[Robin Loxley]]
	- [[John Little]]
	- [[William Scarlett]]
- Nottingham Council
	- [[Guy Gisborne]]
	- [[Robert de Rainault]]

Template Section: Meeting Details

# Meeting Details
- **Topic:** <% tp.file.title %>  
- **Location:** <% tp.system.suggester(["Virtual", "In Person"], ["Virtual", "In Person"]) %>
- **Date:** <% tp.file.title.split(" ")[0] %>
- **Time/Duration:** xx:xx - xx:xx

This section incorporates several uses of Templater, so I will step through each of the bullet points beneath the heading and explain what it does.

Topic

- **Topic:** <% tp.file.title %>  

The topic of the meeting should be described by the title of the meeting, otherwise I have the title wrong. If I need to export the meeting notes (e.g. to a PDF), then I want to ensure the topic is included in the content. For this I use some Templater syntax to insert the name of the note (without the .md file extension). I could strip out the date stamp component at the start, but it means that if someone sends me the meeting title, I can just copy and paste to find it in my vault. Including the date stamp works well for me here.

Location

- **Location:** <% tp.system.suggester(["Virtual", "In Person"], ["Virtual", "In Person"]) %>

Next is the location. I have used another Templater entry here, this time one that pops up an option for me to specify whether the meeting is a virtual or in person meeting. It will then insert the same text at this point in the note.

While the topic is automatic, this requires interaction with the user, and so when the note is being created from the template, Obsidian prompts you to specify the location as virtual or in person. This is why it was a white lie earlier that once you run the link and page building function, entering the name (and potentially date stamp) of the meeting that the note is created. The reality is that I get prompted for the location before the note is created, and if you add your own prompts or additional data entry elements to your own template, this will follow the same operational flow.

Date

- **Date:** <% tp.file.title.split(" ")[0] %>

The date explicitly pulls out the date stamp of the note, but it bases it on the first portion of the title (the text before the first space), rather than the current date. I used to just use the current date, but as you may recall from earlier, sometimes I create meeting notes for other dates, and so by extracting it from the title of the note, I can always ensure that the right date is populated. It works by splitting the title into elements of an array, splitting by spaces, and then taking the first element of the array. Because it is JavaScript-based, the first element is element zero in the array.

At some point I will probably mass modify all of the notes in my vault (using a regular expression-based find and replace, and an appropriate level of backup), including all of my meeting note templates, to include the date information in a different way. Because the date is always in the title/topic, I don’t think it adds much value to the template as it is. Instead I think it is more useful as meta data, and so I expect to switch things around to that at some point, but here’s where I have some options

The first option would be to include it as front matter meta data at the top of the file:

---
projectid: ""
notetype: "meeting"
meetingtype: ""
date: "<% tp.file.title.split(" ")[0] %>"
---

The second would be to keep it in place in the file as in-line meta data, that like front matter meta data, is also accessible to Dataview.

- **Location:** <% tp.system.suggester(["Virtual", "In Person"], ["Virtual", "In Person"]) %>
- **Date**:: "<% tp.file.title.split(" ")[0] %>"
- **Time/Duration:** xx:xx - xx:xx

My instinct is to go front matter, but not all meetings necessarily have existing front matter which complicates things - maybe just requiring multiple steps of update. I have not thought through all of the pros/cons/opportunities/limitations yet on which path to take. It has been low on my to do list, and so both options are on the table. If you have any insights on this and want to make a recommendation, feel free to send me a message on Mastodon.

Time/Duration

- **Time/Duration:** xx:xx - xx:xx

Finally, I note the start and end time of any meeting.

Template Sections: Agenda, Notes, and Actions

# Agenda
- 

# Notes
- 

# Actions
- 

The agenda, notes and actions sections are the core of the template where I note down everything discussed, and particularly any actions for the meeting. If I come away with any, I’ll add them to my rolling to do list. For larger pieces of work, particularly where it is cross-organisation, I might end up putting them in another task management system, but ultimately, I want to be able to track down actions back to the meeting notes where the action came up so I can get any additional context or background I might need.

Template Section: Recent Meetings

# Recent Meetings
```dataviewjs
dv.view("/00-09 Meta/00 System Data/00.08 Data View/dv_MeetingListing");
```

It has taken a while to get here, but the Recent Meeting section is where the Dataview plugin comes into play. A single line of Dataview syntax hides the details of what is going on, but from the title it is of course obvious that I am using Dataview to generate some details about recent meetings. The dv.view() function loads a Dataview JavaScript file in this case, called dv_MeetingListing.js that is located within my vault.

Including Dataview code in this way makes it easy to centralise your Dataview-driven code, and as you update and refine the code, any note built from a template containing a reference to it receives the benefit of the updated code, rather than having legacy code from old versions of the template littering your vault.

The dv_MeetingListing.js file contains the following code.

dv.execute(`

LIST
FROM -"00-09 Meta/03 Templates"
WHERE
	notetype = this.notetype
AND meetingtype = this.meetingtype
AND projectid = this.projectid
AND file.name != this.file.name
SORT file.name DESC
LIMIT 10

`);

The dv.execute() tells Dataview that it wants a standard Dataview query executed, so really the bit that is of key interest is the string that defines that query. Again, I’ll break this down.

LIST

This just means that the output will be a list of notes, rather than say a table of notes.

FROM -"00-09 Meta/03 Templates"

This one looks at first like it is going to search in my templates folder structure, but if you look closer, you’ll see that there is a leading hyphen. This is a negation and effectively this line says to generate the listing from my entire vault, excluding my templates folder structure. Because I use this Dataview block across my specific meetings too, I needed to ensure that those other templates do not inadvertently get pulled into my actual listings.

WHERE
	notetype = this.notetype
AND meetingtype = this.meetingtype
AND projectid = this.projectid
AND file.name != this.file.name

This section sets the logical criteria of how to match what to include in the listing. This is where those front matter meta data properties I included at the top of the template come into effect. Dataview can access them and use those to filter to meetings of the same type in the same project, and that is exactly what the three lines below the WHERE does. The this object references the current file, so it will look for matches based purely on the data in the current file which means this code has a high level of reusability across my vault.

The last line refers to the file name of a note, but rather than being matching (equality), it is looking for a mismatch (inequality). This ensures that the note does not link to itself.

SORT file.name DESC

This line ensures the results are sorted into a reverse order. Because my meeting notes are all prefixed with a date stamp, a standard reverse alphanumeric sort will put the meetings in reverse chronological order - i.e. the most recent meetings occur first. Sorting based on file modified or created dates is insufficient for my needs as I may create and modify meeting notes at times other than during the meeting. For example if I add notes in advance to the not, or if I create a meeting note after the fact because it was a stand up meeting and it was easier to take notes in a notebook.

LIMIT 10

A somewhat arbitrary constraint, but given I typically want recent meetings if I am jumping out from a meeting note to a related one, I constrain the list to just the last 10 meetings (excluding this one). This seems to work for me so far, but I could change it to a higher value if necessary, and all of my notes would automatically update.

I find this listing really useful where I need to refer back to the last meeting, or if someone refers to something from a few meetings back. I can very quickly jump to the bottom of my current note, find the listed note, and open it in a new tab or pane in Obsidian.

Template Section: Tags

**Tags:** 

The last entry is titled tags, but I don’t actually put any tags here, rather I put links to other notes. You can read about why I tend to use note links over tags, but the gist is I simply find more flexibility in it.

I add entries here based on things such as the anchor of the call (for me it is often a particular system or technology), and to any organisations involved. For example, for my fictional external meeting above with people from Nottingham, I might set up the following.

**Tags:** [[Woodland Maintenance]] | [[Nottingham Forestry Commission]] | [[Nottingham Council]]

I tend to use pipe characters (“|”) as separators as I think it has a nice visual look and these are highly unlikely to appear as part of a note title as they have special meanings to some file/operating systems, and a particular meaning in Obsidian’s internal wiki-links (they are used to enable the display of alternative text but still link to a particular note).

A Final Example

To illustrate how this works, I put together a few notes using the process above and displayed them across a set of panes.

Top Row, Left
This note is the one I used to create a set of general notes, notes that span four days and I have added a sequence number to the end for additional clarity when you scan the order. In this note, I created the notes in date order and incremented the sequence number accordingly.
Bottom Row, First on the Left
This note is the earliest meeting note (meeting note #1). It has been set to have a projectid of “fake” as have all of the meeting notes I created for this example. It has no meetingtype specified.

In the recent meetings section, you can see the Dataview query has generated links for meeting #4 and meeting #3 (reverse chronological order). Note that there are no links for note #1 (as we would expect given the constraint on the Dataview query), and there is no link for meeting note #2 … which at first seems suspicious.

At the bottom, you can see I have added a link under ‘Tags’ for a note called “Fakery”.
Bottom Row, Second from the Left
While meeting note #2 is very similar to meeting note #1, as you would expect from using the same template, there are a few readily apparent differences.

The first of these is that the meetingtype is different. It is set to workshop. This is the reason why this note does not appear in the recent meetings list in meeting note #1. It has a different meeting type.

Looking further down, we can see that the ‘Recent Meetings’ section is devoid of links. This is again due to the meetingtype property. This is the only note with that meeting type, so there are no recent meeting notes to link to that match its front matter values for the query match criteria.
Bottom Row, Third from the Left
Again, this third note (meeting note #3) is very similar to meeting note #1. This time all of the front matter meta data matches, and hence why this note appears in meeting note #1’s list of recent meetings and why meeting note #1 shows up in this note’s list of recent meetings.
Bottom Row, Fourth from the Left
Meeting note #4 exhibits the same behaviours as the first and third notes.
Top Row, Right
This is the “Fakery” note that is referenced in the “Tags” sections in each of the meeting notes.

I included some of my standard Dataview code to list the notes that link to it in the usual reverse name sort order. I use this all the time in notes about particular organisations and projects as it then gives me a full listing of related meetings rather than just recent ones.

BONUS: More Dataview Content

While not the focus of this post, it would be rather cruel of me not to also share some further details of that “Fakery” note, in case you want to make use of it in a similar way.

Just as with the previous Dataview snippet, I can get re-use here and so I call out to a separate script file from the note.

```dataviewjs
dv.view("/00-09 Meta/00 System Data/00.08 Data View/dv_InboundLinks");
```

The JavaScript file it references (dv_InboundLinks.js) contains the following code.

jsdv.execute(`

LIST without id map(reverse(sort(map(file.inlinks, (theLink) => theLink.file.name))), (f) => link(f))
WHERE file.name = this.file.name

`);

I am not going to divert into breaking down this query, but just know that it finds the inbound links, creates the note links, sorts them into order, and inserts them into the note.

You can just copy and paste this as is to reproduce the effect. You just need to point your note’s dv.view function to the JavaScript file’s location.

Summary

As I noted at the start, this post is not intended to provide you with a generic meeting template. The intention was to provide you with some ideas that you could pick and choose from to help you implement your own. If you want to just copy and paste the details for mine as a starting point, go for it, but I urge you to tailor everything to meet your own needs. The ‘personal’ element of personal knowledge management is key in optimising your system for your own needs. There is no magic one size fits all solution, which is why I offer this purely as a reference for inspiration in building your own solution.

If you think there’s anything I might be interested in adding to my own set up, again, feel free to reach out to me on Mastodon and point me in the direction of more details. Otherwise, I hope you have found this useful and that your Obsidian use will benefit as a result.

Author: Stephen Millard
Tags: | obsidian |

Buy me a coffeeBuy me a coffee



Related posts that you may also like to read