Marcus' Development Environment and Notes

Hi Pavilioners, I thought I’d write some aide-memoire notes for myself about things I sometimes forget about Discourse development, but also thought while I was doing so I’d describe my setup in a bit more detail, in case this helps any members or the wider community - also because I might get helpful tips and feedback myself!

Development machine

  • I’m using my general purpose laptop which I use for everything else - a Dell XPS15 9560 laptop with 4K/QHD screen, 32Gb RAM and a 1Tb NVMe SSD.

  • I run Linux Mint (currently on 19.3 which is latest, and is built on Ubuntu 18.04 LTS

General development setup


I use Atom for most development (Nano if I’m editing a file on a server over SSH). I don’t have extensive editor customisations, it’s basically stock. I add a few custom keyboard shortcuts.


I use the ZSH shell, in the Terminator terminal emulator, which allows me to set up a terminal with 4 panes, without having to mess about with Tmux or Byobu or screen.

Installing ZSH


  • a community-driven suite of customisations, themes and tools for ZSH, including a lot of very useful Git aliases and helpers. The Git branch prompt and ruby version prompt is very useful.


I generally use Firefox now, unless I’m testing something across different browsers, or need a Chromium-based browser because some Google thing refuses to work, in which case I use Brave.

TIP: Ctrl-Tab

Firefox has the ability to Ctrl-Tab between tabs in Most Recently Used order, which I find super valuable for switching tabs quickly without mousing.


  • I use the CopyQ cross-platform open source clipboard manager, which I use to allow me to keep the last 1000 clips in a palette of clipboard, which is really useful and time saving.


  • You can drag any particularly useful snippets across into a ‘persistent’ tab.

  • It has a JavaScript command scripting interface through which you can define new commands, global keyboard shortcuts, and other useful tricks. For example a hotkey combination which pastes my email address looks like this:

copy(mimeText, '',
     mimeHtml, '<a href=""></a>')
  • a script which slugifies any clipped text for me: (I use this for filenames and Git feature branch names taken from a relevant Issue that it’s supposed to fix, for projects that work like that)
// lowercase, replace non-word with hyphens, trim multiple hyphens, trim leading and trailing hyphens

text=str(clipboard()).toLowerCase().replace(/\W/g, "-").replace(/-+/g, '-').replace(/^-|-$/g, '')
write(0, 'text/plain', text)
copy('text/plain', text)

wd - ‘warp directory’

  • neat little utility which is a plugin for oh-my-zsh that lets you jump to a directory quickly with less typing.
  • yes, I guess you could define aliases to do the same, but you’d need to keep echoing the aliases into a .*rc file to make them persistent.


Discourse development setup & workflow

Discourse Docker

  • I develop using Discourse Docker - the documentation on Meta was recently refreshed it seems, and it much clearer than it was.

  • Performance is acceptable, no worse than it was in a VM, probably better.

Useful commands to develop with Discourse Docker

| | |
| Run bundler to install/update gems | d/bundle |
| Migrate and seed the database | d/migrate |
| Clear cache and start server | rm -rf tmp; d/unicorn |
| tail the Rails logging output (the unicorn logs are not very detailed) | tail -f log/development.log |
| Run a Rails command | d/rails <COMMAND> |
| Run a Discourse CLI command | d/discourse <COMMAND> |

Quick way to install latest Docker:

curl -fsSL | sh
sudo groupadd docker
sudo usermod -aG docker $USER
sudo systemctl restart docker
(also need to log out and in again to pick up the addition of user to docker group)

plugins-available and plugins directories

  • try to keep things clean by moving the plugin symlinks in and out of the plugins directory. Plugins not currently being worked on are moved to a plugins-available folder, a bit like how sites are managed in NGINX/Apache.

Gotchas (mainly for me when I forget)

Symlinking plugins into the discourse-dev-env directory

  • symlinks MUST contain an absolute path not a relative path, or the d/boot_dev --init command will fail silently, and your discourse_dev Docker container will not exist.

cd plugins
ln -s /home/marcus/code/discourse/<MY-AWESOME-PLUGIN> .