What is Plan 9..?

Briefly, Plan 9 from Bell Labs is a computer operating system designed by the original UNIX design team, after decades of work on Research UNIX in the late 80's, the team decided to rewrite a new operating system from scratch, their new system was finally released in 1996, a year later they released yet another operating system called Inferno, which share many of the same characteristics as its sister project. These systems, and variations thereof, have more or less been in continual development since. The history and design philosophy behind these operating systems, is interessting, but we will not talk about this here. Instead, this article will focus on the practical aspects of using Plan 9 as day-to-day desktop systems.

Beware that prior exposure to UNIX is a double-edged sword. There are similar sounding commands and conventions between the two platforms, and Plan 9 does follow the UNIX philosophy (much closer in fact then UNIX itself). Nevertheless, Plan 9 is not UNIX! It is an operating system written entirely from scratch, backwards compatibility was not a goal. If you expect just another Ubuntu spin-off, you will be very disappointed. In fact, lets be very clear here: You will be disappointed, period. Now with that disclaimer out of the way, lets have some fun!

The official version of Plan 9 was actively used and developed by Bell Labs until 2015. The original website,, is no longer in use. But the original version of Plan 9, and all of its website resources, are available at Several community forks of Plan 9 also exists, One of them, 9legacy, tries to keep very close to the original system. But the version we will be focusing on in this article, is the community fork 9front. This fork was started around 2015 to continue active development, and they have added many modern features to Plan 9 that most users would expect, such as auto-mounting USB sticks, wifi support and working audio. 9front has an excellent fqa (be prepared for quirky humor!), that you really should read, if you are insane enough to actually use the system, and we will refer to this article throughout this article.

Limitations and workarounds

More then anything, Plan 9 is a simple operating system. The kernel is only 200,000 lines of code, and the userland about a million. In comparison the source code for the Firefox web browser is more than 24 million lines of code! As you might imagine then, there are no modern web browsers in Plan 9. There are no office suits, tripple A games, video playback, or repositories of 30,000 pre-compiled packages. Plan 9 is not for the faint of heart!

Of course there are workarounds for the above mentioned limitations, here are some suggestions:


It is simple enough to connect to a remote UNIX/Windows machine from Plan 9 using VNC, or vice versa. From Plan 9 you can connect to a VNC server using vncv, or run a VNC server with vncs. (there is little reason to run a VNC server on Plan 9 though, use drawterm, mentioned below, instead)

For example, assuming you have tigervnc installed on a UNIX machine, with the ip address, and a desired vnc screen ressolution of 1366 x 768 pixels: You can run vncserver -geometry 1366x768 :1, and give it a login password (if you are not prompted for a password you may need to run vncpasswd). Now, on the Plan 9 machine, run the command vncv, and login. By default this will probably run a very basic twm desktop, which makes most newbs suspect that the desktop failed somehow. You probably want to change ~/.vnc/xstartup, to run a more tastefull setup. To use the openbox window manager instead of twm:

exec /usr/bin/openbox-session

Or you can use whatever window manager suits your fancy. Beware though that configuring xstartup gets vastly more complex if you use some bloated mess like Gnome or KDE...

Porting applications

There exists a fairly good port of Plan 9 userland programs and services for UNIX, called Plan9Port (or p9p - a more lightweight alternative is 9base), it is available in the repositories of most popular UNIX systems. Once installed, use the 9 command to run the Plan9Port programs rather then the UNIX versions, eg. 9 acme. It does not fully replicate the Plan 9 experiance of course, but it does make UNIX less painful to use.

To run a full Plan 9 shell, using Plan9Port commands instead of the UNIX equivalents, either run 9 acme, execute win in acme and run 9 rc. Or run 9 9term, then run 9 rc. You can configure your ~/.xinitrc file to start the Plan 9 look-alike window manager, with exec 9 rio, and set up a very authentic looking Plan 9 desktop. But there is litte point in doing so, unless you really want to hide the fact that UNIX is running in the background. Plan9Port's rio only looks like the Plan 9 window manager, but it doesn't have the same useful features, and it is quite flakey to boot. In my opinion there are far better native UNIX alternatives, including the Plan9 inspired wmii/dwm/awesome/i3 window managers.

It is possible, but much harder, to go in the other direction. Plan 9 has a UNIX compatibility suit of programs and libraries in /bin/ape, such as ape/sh, which gives you a ksh like UNIX shell. (run vt first to fully emulate a VT-100 terminal) And ape/cc a POSIX compliant C compiler, with corresponding UNIX-friendly libraries. Plus a few other UNIX'y utilities.

Note however that simply having a UNIX shell, does not mean that all your shell scripts will magically work. Plan 9 has it's own version of cat, echo, ls, sed and so on. If your script uses these programs, it needs to be adapted to use the Plan 9 version of these programs. As always, read the man pages. (no really - read them!)

Finally, even though Plan 9 has had a very good POSIX compliance, its by no means certain that UNIX programs will compile. Most will not. The majority of UNIX software does not restrict itself to POSIX alone, but require large extensions. Most of which are not supported. For example, Plan 9 does not have Xorg, curses, sockets or links, any programs depending on such things needs to be patched and rewritten before they will compile. In practise only the simplest programs can be ported with resonable amount of effort.

Emulating other operating systems

In a traditional Plan 9 network, one or more CPU servers are providing file and authentication services to multiple diskless workstations, called "terminals". These terminals are desktop systems connected to the CPU server. This is a bit confusing for UNIX users, so in this article we will refer to a diskless workstation as a remote desktop, and a window running a shell as a terminal, as is the custom in UNIX. If you have set up a CPU Server in Plan 9 (see section 7.5 and 7.6 in the 9front fqa), either physically, or on a virtual machine, you can emulate a Plan 9 remote desktop on a UNIX/Windows machine with drawterm. (for the original version of drawterm use this link) drawterm works very well, it also has access to the host filesystem under /mnt/term, making it easy to work on files across operating systems.

There is a 3rd party port of Xorg for Plan 9 [link], together with linuxemu, it can be used to run Linux software natively (see section 8.7.1 in the 9front fqa). This implementation is not perfect however, it is tedious to work with, and I have not had much success with it myself.

Virtualizing other operating systems

There are many different virtualization solutions available for UNIX/Windows capable of running Plan 9, such as qemu and VirtualBox. [citation needed] Plan 9 has very limited hardware support, especially if you want to use the classic versions of this operating system. Virtualization is a practical way to eliminate such concernes.

9front also includes its own hypervisor (see section 8.7.5 in their fqa), vmx, capable of running Linux, OpenBSD, allegedly Windows, and plausibly other operating systems. But you need modern Intel hardware for this to work.


I assume you have already downloaded and installed Plan 9, either on a physicall machine or on a virtual one. If not you can get the 9front iso, and follow the installation instructions in section 4 of their fqa. Again, this is not a guide for installing and configuring a Plan 9 system, use the 9front fqa for that. Our focus here is doing day-to-day tasks after the initial setup is done.

Window Management

The window manager in Plan 9 is called rio, it provides a remarkably clean and simple desktop, somewhat akin to twm in UNIX. Unlike twm though, it doesnt look like crap by default, and the source code is only 6000 lines of code, which incidentally is also about the same size as Plan 9's graphical library, libdraw. In contrast twm's source is closer to 30,000 lines, and the Xorg backend more then 8 million! Programming graphical applications in Plan 9 is a breeze.

Window management is streight forward: rio provides only one menu, which you can access by right clicking the mouse on the desktop background. Hold down the mouse button while you are selecting a menu option, and release the mouse button when you have marked the option you want. To create a new window, which is always a terminal, choose New. The mouse pointer changes to a cross, this tells you that rio is waiting for you to specify a window size. Right click in a corner and drag the mouse, a red rectangular box appears, release the mouse button when the window has the size you want.

If you choose the Delete option in the rio menu, the mouse pointer changes to a cross with a circle, this tells you that rio is waiting for you to specify a window. Right click on the window you wish to delete. If you Hide a window, it will appear in the rio menu, just select it from this menu to make it visible again.

You can also Resize and Move a window by using the rio menu, but its easier to click and drag the windows directly: To resize a window, left click the blue border and drag, to move it, right click and drag.

Right clicking in a terminal window will also bring up the rio menu, but other programs will not necessarily do this. If you need to access the window manager menu while running a fullscreened acme window for instance, you must first shrink the window or move it out of the way, and then right click the grey rio background. There are no key-bindings to control rio, you can only do so using your mouse ("What?!? The mouse actions are required?!?" I know right, Plan 9 is so radical...).

Copy Pasting

In order to use Plan 9 effectively, you need a 3-button mouse. Such mice are quite common nowadays, with the scroll wheel doubling as the middle mouse button. The 3 mouse buttons, and combinations of clicks, are used throughout Plan 9 for manipulating text. If you don't have a mouse with 3 buttons, you can simulate the middle click by holding down the Shift key and right clicking. But this will quickly become tedious, so go out and buy a 3-button mouse ASAP.

You can select text in the normal way, by left click and drag. You can also double left click a word to select it. If you double click the end of a line, the whole line will be selected, and if you double click a parenthesis or square bracket or some such, the text inside these parenthesis will be selected.

To cut the selected text, hold down the left button and click the middle mouse button. To paste the text, click the left button and while holding down this button, click the right button. To "copy" text, left click and middle click, release the middle mouse button and click the right button. Such combinations of mouse clicks are called mouse chording. They are used very consistently in Plan 9 programs, and feel intuative once you get the hang of it.

Essential Programs

There are only a handful of programs in Plan 9, they are simple to learn and work very well. Some essential applications are:

Manipulating Text in the Terminal

You do not have to play around much in the Plan 9 terminal before you realize that it works quite differently then the UNIX variant. The first annoyance might be that there is no Tab completion. Don't worry, use Ctrl-f instead, it does much the same thing. There is no advanced completion of program names and flags, like hipster zsh and fish users might be accustomed to. But this really isn't an issue since Plan 9 doesn't have any programs or flags, as you will discover soon enough.

The second thing you may notice is that the terminal text can be freely edited. You can add any text anywhere and copy paste the text arbitarily, the Plan 9 terminal thus feels much more like a text editor then a UNIX terminal. (a consequence of this free-form text editing is that the mouse cursor has to be at the end of the last line in order to execute a command with the return key, otherwise it will just add a literal newline to the text - this is only mildly annoying once you get used to it) What's the point of this novel design? First of all it eliminates a host of special purpose programs that UNIX requires, for example there is no clear command in Plan 9, you just cut the text. There is no reset or redline either, as they are not needed. Secondly, once learned, this behavior feels very intuative. Why shouldn't you be able to cut and paste text and freely sprinkle your terminal output with random comments? Going back to a UNIX terminal, after having spent some time in Plan 9, really feels like leaving the 90's - and going back to the 70's.

Lastly, there is no history command in the Plan 9 terminal, hitting the up arrow key on the keyboard will just move the pointer one line up, like any text editor would. What else did you expect? Relax though, you can rerun the previous command with "" (" will reprint it).

Hang on! The command "", isn't double quotes used for quoting?!? Not in Plan 9, double quotes are just ordinary characters. Whereas UNIX has three escape characters, Plan 9 has only one, the single quote (well, ok, backslash is also used in some situations). The UNIX command "$message has a literal \$$ and '", would be ''$message' has a literal $$ and ''' in Plan 9. (two single quotes within single quotes is interpreted as one literal single quote)

Back to our topic of rerunning commands, note that the need to auto complete text and rerun commands are much greater in UNIX then Plan 9. It is easy to copy paste text in the terminal, so use that functionality for what it's worth! You don't need to use insane syntax like ls !$ to run ls with the previous arguments, or ^foo^bar to spell correct the last argument and rerun it. Just type ls in the terminal and copy paste the previous arguments, and if you need to spell correct the last argument, then just do so, copy paste the result to your prompt when done. There is also a full copy of the terminal text in /dev/text. So the command cat /dev/text > transcript is essentially the same as script in UNIX, and the command grep '^; ' /dev/text the same as history. (assuming of course that your shell prompt is ; ) Note that you can search this log for other things then just your previous commands, and you can manipulate this data in many other interesting ways as well.

In addition to /dev/text you also have /dev/snarf, which holds the "snarf" buffer, which is the clipboard in Plan 9 speak. (if you want to write to the window, use /dev/cons). All of these files refer to your current window, if you want to use these files for a different window, see the rio scripting section below.

But what if you want a system wide history log for all of your windows? There is no such file in Plan 9, but you can create one if you really want to. For example, you could add this line to your $home/lib/profile: fn quit{ grep '^; ' /dev/text >> $home/lib/text ; exit }. You can then quit all your terminals with the quit command, rather then exit, and all their history will be saved in $home/lib/text.

Acme - The Do It All Application

The acme text editor is arguably the main application for Plan 9, it doubles as the systems file manager, terminal, mail reader and more. It can even be used as a fully fledged window manager, by replacing rio with acme in your $home/lib/profile (but I don't recommend it - you will not be able to run any other program - but then again, why would you need to..?).

Let's do a whirlwind tour of acme: The first blue row contains commands for the entire acme window, such as Exit, if you middle-click this button, acme will exit. Dump will create a file called acme.dump, this can be used to save a particular window arrangement, and restored with acme -l acme.dump. Pullall will save all modified text files.

If you middle-click Newcol a new column will appear. The column has it's own row of commands, in the second blue row. Delcol will delete the column. Cut, Paste and Snarf (eg. "Copy"), will do text manipulations. But it's easier to use mouse chords for this: Left-click and middle-click to Cut, Left-click and right-click to Paste, and finally Left-click and middle-click, then right-click (while holding down the left button) to Snarf, or Copy. The mouse chords are awkward to explain with text, but try it out, it will feel very intuative with a little practice.

Middle-clicking New will create a new window in the column. Again, it too, will have it's own row of commands. Del will delete the window. The window is initially empty, try writing some random text into it. You will see that a new command appears, Undo. (it's meaning should be obvious) After typing in some text, you can also hit the Esc key to mark the recently added text, hitting Esc again, will cut the text. How do we save our file? First we need to give it a name: Click on the far left of the menu, left of Del, and type /usr/glenda/testfile. (glenda is the default user in Plan 9, and /usr/glenda is the default home directory) Yet another command will appear, Put, middle click it to save your work. This is a lot of typing! Isn't there an easier way to do this? Sure, remember that Plan 9 allows you to copy paste pretty much anything. Find the directory you want in a terminal, with Control-F autocompletion and everything, then print the directory name with pwd, and just copy paste that into the acme window, and append your new filename.

By now you will have noticed a very unique feature of acme, it's menus are pure text. The "buttons" are just regular words. To illustrate: Type Del (case sensitive!) somewhere in the yellow text window, then middle click it. The window will disappear. Del is just a command, same as echo or cat. Another test: Type echo hi there and middle click, and drag, so that the red mark covers all three words. hi there will be printed in a new window.

You can use the Look command to search for words in the window. Type monkey a couple of times in the yellow text window, now type Look monkey in the blue window menu, and middle click and drag, to mark the two words. The first occurance of monkey will be highlighted, run the command again, and the second occurance will be highlighted, and so on. An easier method however would be to just right-click the word monkey, anywhere in the text, the next occurance of the word will be highlighted, and the mouse pointer will be moved there. Just right-click again to see the next occurance of the word, and so on.

The Zerox command in the column menu will duplicate a window, this is very useful if you are editing a long file, and you need to see or edit different parts of the file at the same time, any changes made in one window will appear in the other. Sort will sort the column windows by name, it does not sort the content of the windows. To do that, mark the text, type |sort in the window menu, and middle-click it. As you can see, you can freely use arbitrary Plan 9 commands to manipulate the text in acme.

If you want to do search and replace operations, use the Edit command. This command is a back end for the sam text editor, which uses much the same text editing commands as ed (which again is similar to sed or vi). For example, double click one of the monkey words to highlight it, then type Edit s/monkey/chimpanzee/, and middle click and drag to execute this command. The highlighted word will be changed to chimpanzee. To change all the occurances of monkey, type Edit ,s/monkey/chimpanzee/g. (in vi the equivalent would be :%s/monkey/chimpanzee/g)

Side note: Although the above ed style substitution works in sam, sam is not a line-based editor like ed, and a more propper sam command for the above would be: Edit ,x/monkey/c/chimpanzee/. (that is: for each /monkey/ change to /chimpanzee/) To read the sam tutorial, run: page /sys/doc/sam/sam.tut.out

acme lacks many built-in features that UNIX user might expect, but you can create much of this functionality simply by piping the text through standard utilities. Here are some examples:

Open a New window and type in the filename /usr/glenda to the far left, then type Get to the far right, right of Look, and middle click it. The contents of the /usr/glenda directory will fill the window. If you right-click on a directory in this window, the contents of that directory will be opened in a new window. On the other hand, if you right-click a text file, the contents of that file will be opened for editing in a new window.

Exactly what happens when you right-click something in acme, depends on the word you click. For example clicking on the word /usr/glenda/pictures/cirno.png, will open this picture in the image viewer page, and clicking jazz.mp3, will start playing the audio file with play. Provided of course that the files in question exist on your system. The last example also assumes that the jass.mp3 file is located in the same directory as the one you launced acme from, if not you need to specify a correct filepath. The actual work of connecting the right files to the right program is handled by plumber, which we will talk about later, but for now its enough to know that right clicking a filename anywhere in acme will usually just "do the right thing".

Each window has a dark blue square to the far left of the menu, you can click and drag this box to resize or move the window to another column. The columns themeselves also have a dark blue square, click and drag this to resize or move the column.

You can also right-click on the dark blue window square, to hide all the column windows except that one, left-click on it to bring the windows back. Left-clicking on the square will increase the window size a little, middle-clicking will maximize the window.

Left-clicking on the scroll bar will scroll upwards, right-clicking downwards. Clicking towards the bottom of the scroll bar will scroll a lot, clicking towards the top will only scroll a little. Middle clicking will transport you directly to that portion of the file. Play around and experiment with these mouse actions, pretty soon you will get the hang of it.

Multiple Workspaces

rio does not have virtual workspaces, there exists a fork, called rio-virtual, that does. Note however that this fork does not compile on 9front! It is easy enough though to create pseudo-workspaces in rio: Just create a new terminal window and run plumber ; rio. This will run a rio desktop in this window. (plumber is not required here, but it will make sure that files automatically opened will only be opened in this isolated rio and not outside it)

You can maximize this "virtual workspace" and do your work, hide this window when you want to go back to your first "workspace", then switch back to it by selecting the hidden window in the rio menu. You can have as many of these "workspaces" as you like, and you can run rio inside rio inside rio ad infinitum...

Another simple "workspace" solution is drawterm. Once a Plan 9 CPU server (see section 7.5 and 7.6 in the 9front fqa) has been configured, you can connect as many drawterm clients to it as you wish. For yet another approach to this problem, see the rio scripting section.

Tiling Windows

First of all, acme is a tiling window manager. Just maximize the editor and do your stuff.

Secondly, you can use your rio startup file, $home/bin/rc/riostart, to automatically set up a desktop that suits your needs. For example, if you have a 1366x768 screen, you can add this instructions to add an acme window to the left half of the screen, and a terminal window on the right half:

window 0,0,683,768 acme
window 683,0,1366,768

Unlike UNIX, graphical programs executed in a Plan 9 terminal will not launch a new window, but the terminal will morph into this new program. In other words, running the PDF/Image viewer page, or the web browser mothra in a terminal for instance, will in no way effect window placement. So having an initial window placement that works on your desktop, will seriously reduce the need for automatic window tiling. But if you need that, take a look at the rio scripting section below.

System Administration

Basic System Administration

To shutdown or reboot a Plan 9 system, you can use the fshalt and reboot commands. The fshalt command only halts the filesystem, but if you have enabled ACPI support, by adding *acpi=1 in plan9.ini (see section 9.2.3 in the fqa), it will also power off the system on supported hardware. (in either case it is perfectly safe to turn off the machine using the power button once the filesystem is halted)

If you are using a remote Plan 9 desktop, such as drawterm, it is safe to just kill the application directly. The remote desktop is stateless, and thus shutting it down will in no way effect the host filesystem. In fact, the system is designed to run a cpu server 24/7, and connect to it with diskless clients. Probably because of this design, Plan 9 is quite careless about its shutdown procedure. The filesystem uses a memory buffer, which is synced to the disk after a few seconds. During shutdown the system makes sure that there are no actuall disk writes in progress, but it makes no effort to sync the buffer to disk befor halting. So if you have made some last minute changes in a file before powering down, that data may be lost. As stated elseware, Plan 9 is simple, shockingly so in fact. But there is an easy workaround to this issue, just wait an while before shutting down. How long depends on your level of paranoia, but 10 seconds should be about forever as far as your hardware is concerned. You can add this line to your lib/profile to automate this: fs halt { sleep 10 ; /bin/fshalt }

To monitor your remaining battery, memory usage, ethernet traffic, system load and other resources, you can use the stats and memory commands. Simply cat'ing around in /dev will also provide much system information, for instance cat /dev/kmesg is essentially equivalent to the dmesg command in UNIX. There is also limited support for suspend and hibernate if you add the apm0= value to plan9.ini (see section 9.2.3 in the fqa and apm(8)). Don't expect this to work thoungh, ACPI and APM is a hairy business!

Speaking of not working, battery monitoring usually doesnt on most hardware. And if you are unlucky, plugging in a headset will not automatically redirect audio output to them. I had both problems on my cheap Acer laptop (note to self: only buy Lenovo ThinkPads from now on...). The last problem will be revisited in the audio section, but the following crude workaround solved my battery situation somewhat: I knew that my laptop had about 2 hours worth of battery life when fully powerd up, and I habitually power up my laptop after use. So, I wrote a script that sleeps for a bit less then 2 hours, and then wakes up and gives me a heads up before the computer goes down. The script can be rerun to reset the timer. It's not exactly glorious, but it worked ok for my use case:

# battery - print a stern warning before the battery runs out
# usage: battery [s] &
# bug: the script doesnt acctually know anything about your battery.

rfork ne
time=7000	# hardware dependent
if (! ~ $#* 0) time=$1
clock=`{date -n}
low=`{echo $clock + $time | hoc}

# rerunning battery will reset the timer
echo $low > $battery

# give warning when battery is low
while(sleep 60){
	clock=`{date -n}
	low=`{cat $battery}
	if (test $clock -ge $low){
		echo Your battery is about to run out! > '#c/cons'
		if (test -f $ping) play $ping >[2]/dev/null

Configuring startup and shutdown

Plan 9 has no /etc directory like UNIX, instead it is configured through a small handfull of files. The most important of these is probably $home/lib/profile, the user startup file. This is where you customize your user spesific settings, it is somewhat analogous to ~/.profile in UNIX, but more important since desktop and shell are much more integrated in Plan 9. Personally I like to add this line to my lib/profile: . $home/lib/aliases, which enables me to add custom aliases to this separate file. But that is just a matter of taste.

Beware that the settings in $home/lib/profile needs to cater to very different situations! Whether you are booting a cpu server, a standalone "terminal", or a diskless one, or are logging in through a remote connection (rcpu or drawterm for example), they all read lib/profile, but often need different customizations. The moral is, be careful when editing your profile, hubris causes debris...

The kernel configuration is in the plan9.ini file, which resides in a special boot partition. To read the contents of this partition you must first run 9fs 9fat, you can then read this file in /n/9fat/plan9.ini. (note: like all Plan 9 commands this manipulates the namespace of your current process, so you will not see this file in other processes) It is by editing this file that you configure your system to run as a cpu server or terminal, you may also need to tweak some hardware spesific values here. See plan9.ini(8) and section 3 of the fqa.

Network configuration is handled in /lib/ndb/local, with additional related files in that directory. But you dont need to mess around with this file if you just want to connect to the internet on a laptop. (see section 6 in the fqa) Mail configuratin is handled by a number of files in /mail/lib. (see section 7.7 in the fqa)

Lastly there is also a desktop spesific startup file in $home/bin/rc/riostart, which is useful for specifying what programs and windows to auto launch, it is discussed more indepth in the tiling windows section of this article.

User Management

To add a new user called bob, that is also a member of the upas (ei. mail) group, on a system using the hjfs filesystem type:

echo newuser bob >> /srv/hjfs.cmd
echo newuser upas +bob >> /srv/hjfs.cmd
auth/changeuser bob

If you are using the cwfs filesystem instead, use cwfs.cmd instead of hjfs.cmd. The very first thing this Bob needs to do when he first logs in to the Plan 9 box, is type /sys/lib/newuser. This will create an initial home directory with basic files such as a profile and a tmp directory. You may also wish to add the new user to secstore (see section in the fqa).

Disk Management

For an example of how to format a USB stick and use it in Plan 9, see the section about USB sticks below. The process for creating a Plan 9 partition is fairly similar. Assuming the usb stick is called sdUc59fd, here is how to format it with an hjfs filesystem:

disk/fdisk -baw /dev/sdUc59fd/data
disk/prep -bw -a fs /dev/sdUc59fd/plan9
hjfs -r -f /dev/sdUc59fd/fs
mount -c /srv/hjfs /n/hjfs # this does not work!
touch /n/hjfs/anewfile

The above example is for 9front, you can run disk/prep -bw -a^(fscache fsworm other), if you want to use the cwfs64x filesystem instead. As for legacy Plan 9 systems, here is how you create a kfs filesystem:

disk/fdisk -baw /dev/sdUc59fd/data
disk/prep -a fs /dev/sdUc59fd/plan9
disk/kfs -f /dev/sdUc59fd/fs
mount -c /srv/kfs /n/kfs
touch /n/kfs/anewfile

Package Management

Plan 9 does not really have package management facilities in the sense that a UNIX user would expect. The system is intended to be "fully-featured" (albeit minimalistic) and few 3rd party software exists, those that do tend to be distributed as plain source requiring the user to compile them manually. Here are a few examples to demonstrate what "package management" may entail in Plan 9:

Updating the 9front system:

sysupdate	# download latest sources
cd /		# rebuild system
. /sys/lib/rootstub
cd /sys/src
mk install
mk clean
cd /sys/man	# optionally rebuild documentation
cd /sys/doc
mk html
cd /sys/src/9/pc
mk install	# optionally rebuild (32-bit) kernel
9fs 9fat
rm /n/9fat/9bootfat
cp /386/9bootfat /n/9fat
chmod +al /n/9fat/9bootfat
cp /386/9pc /n/9fat
reboot	# if you have installed a new kernel

Install xscreensaver package from the 9front extras:

cd /tmp
9fs 9front	# download package
tar xzf /n/
cd xscr	# compile programs and install them
for(f in 8.*){ mv $f $home/bin/$cputype/^`{echo $f | sed 's/8.//'} }
attraction	# run one of the many xscreensaver ports

Install hack9 game from the 9front extras:

cd /tmp
9fs 9front	# download package
tar xzf /n/
cd hack9	# compile and install it
mv 8.out $home/bin/386/hack9
hack9		# have fun

Install vim port from Bell Labs contrib repository:

9fs 9contrib	# install the binary
cp /n/sources/contrib/stefanha/root/386/bin/vim $home/bin/386

Install snake game from Bell Labs contrib repository:

cd /tmp
9fs 9contrib	# download file
cp /n/sources/contrib/john/snake.c /tmp
8c snake.c	# compile and install it
8l snake.8
mv 8.out $home/bin/386/snake
snake		# have fun

Install the Bell-Labs port of perl:

9fs 9contrib	# download iso and mount it
bunzip2 < /n/sources/extra/perl.iso.bz2 > /tmp/perl.iso
mount <{9660srv -s >[0=1]} /n/iso /tmp/perl.iso
cp /n/iso/386/bin/perl $home/bin/386	# install the binary
perl		# happy hacking

Recompile to amd64 and install golang:

cd /			# cross compile from 32 to 64-bit if needed
. /sys/lib/rootstub
cd /sys/src
objtype=amd64 mk install
cd /sys/src/9/pc64	# build and install a 64-bit kernel
mk install
9fs 9fat
rm /n/9fat/9bootfat
cp /386/9bootfat /n/9fat
chmod +al /n/9fat/9bootfat
cp /amd64/9pc64 /n/9fat
sam /n/9fat/plan9.ini	# make sure bootfile=9pc64 (not 9pc!)
reboot		# reboot to a 64-bit system, download Go stuff
hget > /sys/lib/tls/ca.pem
hget > $home/bin/rc/git
chmod 775 $home/bin/rc/git
git clone
cd go
git checkout go1.4.2
cd src
./make.rc		# bootstrap with 1.4.2, then build newer go...
go get


A very good UNIX to Plan 9 translation of various sysadmin commands are given here. You will note that many essential tools that nix greybeards take for granted, such as find or top, are not available in Plan 9. Standard tools may not work as you expect either, the shell does not tab-auto-complete, cp does not copy recursively, ls does not list multiple columns, and so on. This can be very unsettling for seasoned UNIX veterans, but don't panic, the Plan 9 way of doing things will make sense if you give it time. Insidentily, walk (or even du -a) can be used as a lightweight alternative to find, pstree, memory and winwatch should help you monitor your programs, Control-F auto completes filenames in the shell, dircp copies recursively and lc lists files in multiple columns. You can usually reach your goal in Plan 9, you just have to learn to walk a different path...


Shell Scripting

Plan 9's shell, rc is heavily inspired by the classic UNIX shell, sh (the Bourne Shell). Nevertheless it is a complete rewrite and behaves quite differently. One obvious difference is the syntax. The original UNIX shell was designed to mimic the syntax of a user-friendly programming language called ALGOL. In retrospect this was undoubtedly a mistake. rc however mimics the C syntax, which makes a lot more sence, since this is the programing language used elsewere in the system.

Another big difference is that sh treats everything as a string, support for arrays were added later. This means that correct quoting is super important in the UNIX shell, and arrays are clunky. The Plan 9 shell on the other hand treats everything as a list, so arrays are seamless. Quoting is also simpler since there is only one escape character, and strings aren't all that important.

You will find several rc scripts in this article that demonstrate it's use, but here is a short list of sh to rc translations:

mesg="Hello World!"		mesg=(Hello World!)
echo "\$mesg is $mesg"		echo '$mesg' is $mesg
echo "& a literal '" 		echo '& a literal '''
echo ${one}${two}		echo $one^$two
echo contents: `ls`		echo contents: `{ls}
list=(`ls`)			list=`{ls}
echo 1st: ${list[0]}		echo 1st: $list(1)
echo all: ${list[@]}		echo all: $list
echo nr is ${#list[@]}		echo nr is $#list
echo 2>/dev/null			echo >[2]/dev/null
echo >/dev/null 2>&1		echo >/dev/null >[2=1]
if [ "$1" = yes ]; then		if (~ $1 yes)
	echo hi				echo hi
else				if not{
	echo goodbye			echo goodbye
	exit				exit
fi				}
while true; do			while(true){
	something			something
done				}
for i in "$@"; do			for(i in $*){
	echo $i				echo $i
done				}
case in "$@"; do			switch($*){
	a) echo Abe		case a
	   ;;				echo Abe
	b) echo Bill		case b
	   ;;				echo Bill
	c) echo Charles		case c
	   ;;				echo Charles
	*) echo Who?		case *
	   ;;				echo Who?
esac				}
alias l='ls -l'			fn l{ ls -l }
f(){				fn f{
	echo funky!			echo funky!
}				}

Many short script examples in this article are written as functions, this is because I usually add them to a custom alias file, as mentioned in the configuring startup and shutdown section. But you can easily rewrite these functions as standalone shell scripts if you want to.

Rio Scripting

The desktop in Plan 9 is fully scriptable, and in true UNIX fashion, you control it by using a file interface.

For example, if you only have one window open, and run the command ls /dev/wsys/wsys, you should see something similar to this: /mnt/wsys/wsys/1/ This tells you that there is only one window currently open, which has the ID 1.

Now run the command echo new sam > /mnt/wsys/wctl, this should open up a new sam window. If you ls the /mnt/wsys/wsys directory again, you should see two windows listed. You can now delete the sam window with the command echo delete > /mnt/wsys/wsys/2/wctl, assuming that it had the ID 2. To resize the first terminal window, either run echo resize -r 0 0 1360 1080 > /mnt/wsys/wsys/1/wctl, or more simply echo resize -r 0 0 1360 1080 > /dev/wctl.

rio also provides other files that you can use to control its interface, some of these are discussed in the manipulating text in the terminal and taking a screenshot sections. For all of these files, the ones in /dev refer to your current window, use /mnt/wsys/wsys/n/ to manipulate another window. Here is the full list of files that rio provides:

The fact that the window manager can be easily scripted with standard shell tools gives it enormous flexibility. Just a quick example to wet your appetite: The following command will print the window ID number for each window on the screen: for (win in /mnt/wsys/wsys/*) cat $win/winid > $win/cons (if you only want to print ID's on visible windows use this command: for (win in /mnt/wsys/wsys/*) if (dd -if $win/wctl -bs 128 -count 1 -quiet 1 | grep -s visible) cat $win/winid > $win/cons)

max - Maximizing Windows

The following script lets you maximize windows in various ways, eg. max will make your current window fullscreened, and max u will restore its previous dimentions. max l 2 will place window with ID 2 on the left half of the screen, and so on, enjoy...

# max - maximize windows
# usage: max [orientation] [winid]
# orientation can be: f (fullscreen), l (left), r (right), t (top), b (bottom),
# tl (top-left), tr (top-right), bl (bottom-left), br (bottom-right) or u
# (unmaximize), default is fullscreen.
# bugs: if you are maximizing another window, orientation is required
#		unmaximize is only useful right after maximizing a window.

# set some defaults
if(~ $#screensize 0) screensize=(0 0 `{echo $vgasize | sed -e 's/x/ /g' -e 's/...$//' })
if(~ $#windowsize 0) windowsize=`{dd -if /dev/window -bs 1 -count 70 -quiet 1 | awk '{ print $2, $3, $4, $5}'}
if(~ $#* 0) echo resize -r $screensize > $window
if(~ $#* 2) window=/mnt/wsys/wsys/$2/wctl
if(test $#* -gt 2){
	echo usage: max [orientation] [winid] >[2=1]

# maximize window
echo current > $window
switch $1 {
case f
	echo resize -r $screensize > $window
case l
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3, $4, $5/2, $6) }' > $window
case r
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3/2, $2, $3, $4) }' > $window
case t
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3, $4, $5, $6/2) }' > $window
case b
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3, $6/2, $5, $6) }' > $window
case tl
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3, $4, $5/2, $6/2) }' > $window
case tr
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $5/2, $4, $5, $6/2) }' > $window
case bl
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $3, $6/2, $5/2, $6) }' > $window
case br
	echo resize -r $screensize | awk '{ printf("%s %s %d %d %d %d", $1, $2, $5/2, $6/2, $5, $6) }' > $window
case u
	echo resize -r $windowsize > $window

ws - Multiple Workspaces

This script provides a virtual workspace-like service for rio. You use it by typing ws n, where n is an arbitray workspace number. The script works by registering which windows belongs to which "workspace", and then automatically hides or unhides the correct windows as you "switch" between them. Of course this is only a pseudo-virtual workspace, all the windows are still available in the rio menu, and plumbing a file in one "workspace" may pop-up a window in a different one, but its surprisingly practical nontheless.

# ws - pseudo virtual workspaces for rio
# usage: ws n
# bugs: the ws workspaces are not isolated from each other, if you need
#       that open a fullscreen window in each ws workspace and run
#       plumber followed by rio in it.

# set some defaults
rfork ne
winid=`{cat /dev/winid}

# initialize 1st desktop on first run
if(! test -d $tmp){
	mkdir -p $tmp
	touch $tmp/1
	echo 1 > $tmp/currentws
	ls -np /mnt/wsys/wsys > $tmp/`{cat $tmp/currentws}

# update window lists
ls -np /mnt/wsys/wsys > $tmp/riowindows
cat $tmp/[0-9]* | sort -n > $tmp/wswindows
comm -23 $tmp/riowindows $tmp/wswindows >> $tmp/`{cat $tmp/currentws}
for(i in `{comm -13 $tmp/riowindows $tmp/wswindows}){
	for(w in $tmp/[0-9]*) sed '/^'$i'$/d' $w > $tmp/TMP && mv $tmp/TMP $w
currentws=`{cat $tmp/currentws}
# no args: echo current ws (after updating windows) and exit
if(~ $#* 0){ echo $currentws && exit }
touch $tmp/$1

# switch desktop
if(~ $1 $currentws){ echo this is workspace $1 && exit }
for(i in `{cat $tmp/`{cat $tmp/currentws} | sed '/^'$winid'$/d' }) echo hide > /mnt/wsys/wsys/$i^/wctl
echo $1 > $tmp/currentws
for(i in `{cat $tmp/`{cat $tmp/currentws}}) echo unhide > /mnt/wsys/wsys/$i^/wctl
echo hide > /mnt/wsys/wsys/$winid^/wctl

tile - Tiling Window Manager

tile will auto arrange your windows in a tiling fasion. The algorithm is simple, place one window on the left half of the screen, and carves up the right half in even slices for the remaining windows. tile 2 specifies that window with ID 2 should be placed on the left. You can also tile windows manually with tile -v or -h, which carves the current window in half vertically or horizontally, and creates a new window in the other half. But this will not reclaim space if a window is deleted, or auto adjust them if they are resized or moved.

# tile - tile windows
# usage: tile [-vh] [ winid ]

# set some defaults 
rfork ne
screensize=(0 0 `{echo $vgasize | sed -e 's/x/ /g' -e 's/...$//'})
fn visiblewin{
	# ignore hidden windows
	for (win in /mnt/wsys/wsys/*){ 
		if(dd -if $win/wctl -bs 128 -count 1 -quiet 1|grep -s visible) 
			echo `{basename $win} 
if(~ $#* 2){
	# tile -v/-h n; dont use current window as target for -v/-h

fn split{
    # dimentions of current window
    dimentions=(`{ dd -if $wininfo -bs 1 -count 60 -quiet 1 | awk '{ printf("%d %d %d %d", $2, $3, $4, $5) }' })

    # calculate horizontal split
    if (~ $1 h){
        echo $dimentions | awk '{ printf("%d %d %d %d", $1, $2, (($3-$1)/2)+$1, $4) }' > $tmp/a
        echo $dimentions | awk '{ printf("%d %d %d %d", (($3-$1)/2)+$1, $2, $3, $4) }' > $tmp/b

    # calculate vertical split
    if (~ $1 v){
        echo $dimentions | awk '{ printf("%d %d %d %d", $1, $2, $3, (($4-$2)/2)+$2) }' > $tmp/a
        echo $dimentions | awk '{ printf("%d %d %d %d", $1, (($4-$2)/2)+$2, $3, $4) }' > $tmp/b

    # resize current window and create new one
	echo current > $window
    echo resize -r `{cat $tmp/a} > $window
    echo new -r `{cat $tmp/b} > $window

fn left{awk '{ printf("%s %s %d %d %d %d", $1, $2, 0, 0, $5/2, $6) }'}
fn right{awk '{ printf("%s %s %d %d %d %d", $1, $2, $5/2, '$begin', $5, '$end') }'}

fn tile{
    if(~ $#* 1){
        echo resize -r $screensize > /mnt/wsys/wsys/$1/wctl
    if not {
        echo current > /mnt/wsys/wsys/$1/wctl
        echo resize -r $screensize | left > /mnt/wsys/wsys/$1/wctl
        step=`{ echo $screensize(4) / $#* | bc }
        for(i in $*){
            echo current > /mnt/wsys/wsys/$i/wctl
            echo resize -r $screensize | right > /mnt/wsys/wsys/$i/wctl
            begin=`{ echo $begin + $step | bc }
            end=`{ echo $end + $step | bc }

# tile windows
if(~ $#* 0) tile $windows && exit
if(~ $1 -v) split v && exit
if(~ $1 -h) split h && exit

Acme Scripting

In the above section several window manager scripts are demonstarted, but if you middle click tile or any of the other commands, nothing will happen. The reason for this is that the namespace of a terminal window, and acme, are different. If you middle click win and look around in /dev and /mnt you will see that there are a few differences. But dont fret, you can ask acme to run a command using the namespace of the shell that invoced it with the Local command. So middle clicking Local tile will tile your rio windows (to "middle click" two words you need to middle click and drag to select the text).

-- add clear, slide, chat, web, sheet -- -- investigate games, pbar... -- -- ssh keyboard verification fails, is it possible to work around that? --

Web Scripting

As mentioned elseware, Plan 9 networks are controled through plain files. This implementation is unusual, and you should read /sys/doc/net/ to familiarise yourself with the concept. As with the notion that a desktop is controled by writing text strings to files, this idea that networks are plain files, may seem bizarre or even amusing. But any smirk you may have quickly fades as the rio scripting section describes how to develop advanced desktop features with simple shell scripts (try enabling virtual workspaces in Windows 7 with CMD!). I think the same will be true for web scripting. Here is a fully-fledged telnet implementation just to wet your appetite:

<[4] $clonefile {
	netdir=`{basename -d $clonefile} ^ / ^ `{cat /fd/4}
	echo connect $1|$2 >$netdir/ctl || exit 'cannot connect'
	cat $netdir/data &
	cat >$netdir/data

9front Web Scripts

9front ships with the IRC client ircrc, the pastebin command webpaste, and the hget and hpost commands. All of these programs are shell scripts. hget and hpost are somewhat like wget and curl in UNIX, but they are only a hundred, and two hundred, line shell script respectfully (in contrast wget and curl are 300,000 lines of C each!). We will not print their source code here, but they are worth studying if you plan on writing web scripts in Plan 9 yourself. As for webpaste it is just a few lines long, and it is a good demonstration of how to transmit data to a web servince (note that it depends on hpost):

if(~ $#* 0)
if not
hpost -u -p / a_body@file submit:submit fake:fake a_func:add_post url: |
grep -e '\/body\"' |
sed 1q | sed 's/^.*href=\"//g; s/body\".*$/body/g'

ircrc is also about two hundred lines of code, and is well worth studying. But here is a stripped down version to illustrate what is possilbe in Plan 9. It is a very primitive IRC client that only supports a few IRC commands and hardcodes your nick and channel, but it is a working IRC client nonetheless. And at under 70 lines of shell that isnt bad at all:

rfork ne

fn sighup {
	exit 'hang up'
fn sigint sigterm {
	if (! ~ $#netdir 0)
		echo QUIT : Leaving... > $netdir/data
fn mshift {
	echo $*
fn etime {
	date | awk '{print $4}' | awk -F ':' '{print "[" $1 ":" $2 "]"}'

fn work {
	echo USER $user foo bar :$realname > $netdir/data
	echo NICK $nick > $netdir/data
	echo PRIVMSG 'nickserv :'identify $"pass > $netdir/data
	echo JOIN $target > $netdir/data
	while (cmd=`{read}) {
		if(~ $s *eof) {
			echo QUIT : Leaving... > $netdir/data
		switch ($cmd(1)) {
		case /j
			if (~ $#cmd 2) {
				msg = (JOIN `{mshift $cmd})
		case /q
			msg = `{mshift $cmd}
		case /x
			echo QUIT : Leaving... > $netdir/data
		case /*
			echo unknown command
		case *
			msg = 'PRIVMSG '^$target^' :'^$"cmd
			out = '('^$target^')	⇐	'^$"cmd
		echo $msg > $netdir/data
		echo `{etime}^' '^$out

userpass=`{auth/userpasswd 'server='^$server^' service=irc user='^$nick >[2]/dev/null}
if(~ $#userpass 2) {

bind '#|' $p
echo connecting to tcp!$server!$port...
aux/trampoline tcp!$server!$port <>$p/data1 >[1=0] &


As this article is about using Plan 9 as a desktop, we will only mention development in passing. The programming language used throughout the system is C, or more specifically a Plan 9 dialect of C. The system also has its own set of compilers and linkers, one set for each supported architecture. Here is a quick example:

% ed take.c
a # ed: append text
#include <u.h>
#include <libc.h>
main(int, char*[])
  print("take me to your leader!\n");
. # ed: end text input
w # ed: write file
q # ed: quit
% 8c take.c
% 8l take.8
% 8.out
take me to your leader!

Dont worry about the ed stuff if your not used to this editor, there are alternative text editors in Plan 9 that will also be unfamiliar to you, such as acme or sam. Plan 9 users will often open a file with the B command, which will open the file in whatever text editor happens to be open, or it will launch the default editor if none is running. At a cassual glance the C program looks much like a UNIX equivalent, but a kind observer will notice many startling differences. Most Plan 9 programs only have two included headers, the architecture dependent code u.h and the standard library libc.h. Notice also that its perfectly legal for a main to return void, and an exit to return a string.

There are other differences too. For one we see that a program in the current directory can be executed just by giving its name, in UNIX this isnt usually allowed. Although trivial, this detail hints at a big philosophical difference in security (see the user management section). Another difference is that compiler and linker are two seperate programs, and that each architecture has their own set. This makes it very easy to cross-compile programs. For instance, in the above example a 32-bit PC architecture is assumed, but on a 32-bit PC you can easily compile 64-bit programs using 6c and 6l, or you can compile ARM programs using 5c and 5l (see 2c(1)). Of course you cannot run ARM programs on PC hardware, but a Raspberry Pi running Plan 9 can easily compile its software on a PC running Plan 9 (or vice versa for that matter). In fact the only way to install a 64-bit PC system in Plan 9, is to compile it from a 32-bit system (this sounds terrible, but its actually very simple - see section in the 9front fqa).

The details of the Plan 9 C dialect is discussed in /sys/doc/ Other important papers in this directory for programmers are, the acid debugger paper and the mk paper (equivalent to make in UNIX) (note that some of these papers are a bit dated). Of course the other papers here, not to mention the manpages, are an invaluable source of documentation. Another resource that I highly recommend is Introduction to Operating Systems Abstractions Using Plan 9 from Bell Labs, by Francisco J. Ballesteros. You can download the PDF for free from the internet, and despite its tedious name, it is a marvelous programming introduction to Plan 9. Naturally many classic UNIX resources are also useful for Plan 9, even though many details arent directly applicable, such as The C Programming Language by Kernighan and Pike, The Unix Programming Environment by the same, and The AWK Programming Language by Aho, Kernighan and Weinberger.

Beyond shell and awk programming, there are also some support for external programming languages, such as POSIX C and sh (see /sys/doc/, perl, python, go, and of course you can install Inferno and program in its Limbo language (see appendix L in 9fronts fqa). Generally though C and shell programming are by far the best supported languages.

Version Control

All the Plan 9 filesystems (cwfs or hfs in 9front, or fossil or kfs in classic Plan 9) have built-in support for snapshots. Snapshots are usually taken at regular intervals automatically, but you can take one manually if you want, e.g. echo dump >>/srv/hjfs.cmd in 9front (use /srv/cwfs.cmd if you are using the cwfs filesystem). To read the snapshot run 9fs dump, the file will be located in /n/dump. For example if you are looking for the snapshot of /usr/dan/prj/code.c taken 23 February 2020, it will be located in /n/dump/2020/0223/usr/dan/prj/code.c. The yesterday command is a quick way to print the path of the most recent snapshot. history will print all available snapshots where the file contents differs.

The developers of Plan 9 used the built in snapshot feature as their version control system, and for personal use this works great. But if you are collaborating online with other programmers, or if you are working on non-Plan 9 software, you probably want to use a more traditional version control software. The 9front developers use mercurial to handle their project, so the hg command for mercurial ships out of the box. CVS, and a very limited git script, is also available as 3rd party software.

Files and Namespaces

The big difference between UNIX and Plan 9, which is especially important for developers to note, is that while "everything" is a file in UNIX, everything is a file in Plan 9! There are no sockets or ioctl for instance, all networks and devices are controled through plain files. It is hard to emphasize just how much simpler this makes programming, but some illustrative examples can be found in the web scripting and rio scripting sections above.

In order to make everything in this dynamic and complex world work as files, Plan 9 uses some conventions and mechanics that are unfamiliar to UNIX users. For example, devices often need control interfaces as well as input/output interfaces, so Plan 9 often implements a device as a directory with multiple files. For example audio input/output is handled through /dev/audio, but the control interface is /dev/audioctl, and hardware statistics are available through /dev/audiostat. Another example is the /bin directory, which unlike UNIX contains all available programs in Plan 9. But the files in /bin can be directories that group related programs together. All games are in /bin/games for instance, so launching /bin/games/sudoku requires you to type games/sudoku.

There are no links in Plan 9, instead files and directories can be bound to different locations using the bind command. Lets again consider /bin: Programs are actually sprinkled in different places throughout the system, 32-bit PC binaries are in /386/bin, 32-bit PC binaries for acme are in /acme/bin/386. Shell scripts are in /rc/bin and personal shell scripts are in $home/bin/rc, and so on. When the system boots, the relevant program directories are all bound to /bin. If the system is 32-bit PC /386/bin is bound to /bin, if its a 64-bit Sparc system /sparc64/bin is bound in stead, and so on. The important lesson here is that the correct filestructure is assempled during boot. To see the full details of how your filestructure is assempled, use the ns command. This namespace can be manipulated freely, and it only effects the current process (and any child processes executed afterwards).

One example of such manipulation is the rcpu (cpu in classic Plan 9) command, which binds a remote CPU servers processor to the current process, while the local files and devices, such as the keyboard, are kept unmodified. The window still looks and behaves like a normal Plan 9 terminal, but its now using the remote machines processor. This is handy if the remote machine is fast, while the local machine is slow or over taxed. It is also useful if you are testing software for a different architecture, such as running ARM programs from a PC or vice versa. Other remote resources can be imported as well, such as an external audio or ethernet device, and of course regular files. Note that only the process in question is manipulated, other running processes are uneffected. Namespaces lies at the very heart of Plan 9's capabilities, but its hard for UNIX users to grasp the concept. If it helps, think of each Plan 9 process running inside its own jail. The difference is that namespaces in Plan 9 were not created for the purpose of isolating resources, but to share resources between processes (isolation is possible, but its a side effect).

The Web

If you have a wired connection to the internet (you do if your using a virtual machine), you should already be connected. If not run the command ip/ipconfig.

Wireless Network

Wireless networking is only supported in 9front. During startup you may see a line similar to #l1: '/lib/firmware/iwn-6005' does not exist (you can check startup messages later with cat /dev/kmesg). This tells you that firmware for the wireless device #l1 is missing.

9front uses firmware from OpenBSD, so download the correct package for your device from, and unpack it in /lib, reboot, and then you can connect to a wireless network. To illustrate:

% cd /lib
% hget
% tar xzf iwn-firmware-5.11p1.tgz
% reboot
% aux/wpa -s mynetwork -p /net/ether1
!Adding key: proto=wpapsk essid=mynetwork
password: ******
% ip/ipconfig ether /net/ether1

You can easily automate the last two steps with a script:

fn wifi{
	aux/wpa -s $1 -p /net/ether1
	ip/ipconfig ether /net/ether1

Browsing The Web

The prefered web browser for 9front is mothra, but the classic Plan 9 browser, abaco, is also available. Both of these web browsers have only basic support for HTML, they do not support any CSS, let alone javascript. Also, you must supply a full url with a protocol prefix, eg., not just

To open a local HTML file in mothra, write file:///path/to/file. To download content from a website in mothra, right-click and choose moth mode. The mouse cursor will change to a moth, you can now click on any link or image to download it. Choose moth mode again, to return to the default mode, where clicking on a link will follow it instead of downloading it. (abaco cannot open local files or download content)


mail, faces...


To join the fairly active #cat-v channel where 9front developers hang out, run this command ircrc -n myusername -P mypassword -t '#cat-v'. You can register your username and password at A few alternative 3rd party IRC clients are also available, but so far no other chat protocol has been supported in Plan 9.



Adjusting the volume, to say 80%, can be done like this: echo master 80 80 > /dev/volume. But switching between headphones and speakers can be a bit tricky. If your lucky the hardware will just take care of it, but if you arent you have to manually redirect audio pins. On one of my machines the command echo pin 21 > /dev/audioctl switches audio output to the jack port, on another the command echo pin 33,12,2 > /dev/audioctl does the trick. It varies from machine to machine, you can figure out the correct command by analysing the output of cat /dev/audiostat. This can be a bit daunting, but dont panic, just look for the words such as jack, speaker, out, pin, and experiment. Dont worry, the machine will not blow up if you get it wrong ;)

You might find some of the following custom functions helpful, but keep in mind that some of the specifics here are hardware dependent:

fn volume{ echo master $1 $1 > /dev/volume }
fn headphones{ echo pin 21 > /dev/audioctl ; volume 40 }
fn speaker{    echo pin 20 > /dev/audioctl ; volume 80 }
fn mute{   volume 0 }
fn pause{  stop pcmconv  | rc }
fn resume{ start pcmconv | rc }
fn skip{   kill pcmconv  | rc }
fn shufplay{ play <{fortune <{ls $*}} }

Technically you can play a raw audio file just by cat file > /dev/audio, or you can decode it first: audio/mp3dec < file.mp3 > /dev/audio. But there is a userfriendly shell script that makes life much easier: play file.mp3.

There is also a more elaborate, and buggy, music application called juke. But before you can use it, a fairly verbose database of your music must be written first. I am sure it is possible to write a clever script that automates this, but it hasn't been done so far, and I dont have much motivation to write it myself (play is a far better application anyway). But if you really cannot be persuaded to leave it alone, the juke(7) manual will tell you all about it.

The 9front FQA brags about adding device support for audio recording, but I have yet to figure out how this works...




Viewing Images/Documents

There is only one program to display images and documents alike, and that is page. It is truely a fantastic application, despite lacking support for some documents types such as docx or odt, and poor support for others such as epub. PDF's, old Microsoft Office documents, images and other simple formats usually work.

Creating Images

paint is also available, though you would be hard pressed to use it for anything but kindergarten art. resample(1), crop(1) and rotate(1) on the other hand, are useful little tools for image manipulation, see their manpages for more information.

Taking a Screenshot

Not only is there a file in dev for your window text, but there is also a file for your window screen, /dev/window. To take a screenshot of your current window, you can run this command: cat /dev/window > windowdump ; page windowdump. To take a screenshot of your entire screen, do this: cat /dev/screen > screendump.

Now these images are saved as the native Plan 9 image format, which of course the document/image viewer page can read. But if you want to use these images on other operating systems, you should convert them to a more popular format, such as PNG or JPEG: cat /dev/screen | topng > sshot.png or tojpg < /dev/window > window.jpg

As for taking a screenshot of a different window then the current one, take a look at the rio scripting section above.


USB sticks

In 9front USB sticks are automatically mounted in /shr, but if you need to manually mount it, run ls /dev | grep sd before and after plugging in your memory stick, to find its device name. Supposing its sdUc59fd run the following command to mount the memory stick in /n/dos: mount <{dossrv -s} /n/dos /dev/sdUc59fd/dos, and unmount it with unmount /n/dos, see dossrv(4) for more information. If the device doesnt show up in /dev after plugging it in, there is either some hardware/driver issue, or the device uses a filesystem that isnt supported. (only DOS and Plan 9 filesystems are supported).

If you need to reformat a memstick as FAT (ei. DOS), assuming it is still called sdUc59fd:

% disk/fdisk /dev/sdUc59fd/data
% p # print a table of partitions
% ? # get help instructions
% d p1 # delete a couple of partitions
% d p2
% a p1 # add a new partition
% 1 # just follow suggested size
% 971
% t p1 # set partition type
% ? # list available types
% FAT32
% w # write and quit
% q
% disk/format -d /dev/sdUc59fd/dos


To mount an iso image in /n/iso run the command mount <{9660srv -s} /n/iso /path/to/your/cdrom.iso. This may look cryptic, but it's actually very easy to work with CD/DVD/BD's in Plan 9 (see cdfs(4)), the following demonstration shows how to mount an audio cd (you only need to specify the device if it isnt /dev/sdD0), play it, and rip it:

% cdfs -d /dev/sdE1
% cat /mnt/cd/a* > /dev/audio
% cp /mnt/cd/a* /tmp/songs

You might find these custom functions helpful:

fn mem{   mount <{dossrv -s >[0=1]}  /n/dos $1 }
fn iso{   mount <{9660srv -s >[0=1]} /n/iso $1 }
fn eject{ echo eject > /mnt/cd/ctl }
fn cdfs{  /bin/cdfs -d /dev/sdE1   }
fn cddb{ # query the internet CD database
	grep aux/cddb /mnt/cd/ctl | rc
fn rip{  # rip a CD and convert it to ogg
	for(t in /mnt/cd/a*) audio/oggenc < $t > `{basename $t}^.ogg

The next example shows how to burn an audio CD. Simply change 'a' for 'd' to change from an audio to a data disk (DVD's and Bluerays only support data). The last command fixates the disk, which is not necessary on rewritable or data disks:

% cdfs -d /dev/sdE1
% cp /tmp/files/* /mnt/cd/wa
% rm /mnt/cd/wa


Let me save you a lot of trouble: put LPDEST=stdout in your $home/lib/profile, now lp will print its postscript to standard output. Convert files to ps or pdf as you see fit, then copy or email them to a Windows/UNIX machine, and print out a hardcopy from there if you really need it:

% lp doc.html | ps2pdf > doc.pdf
% doctype | rc | lp | ssh unixmonster 'cat | lpr'


Gaming is a potentially contentious topic when it comes to computers, although massively popular of course, nothing is more detrimental to productivity (except a modern web browser of course). So the trick to creating a good computer game, is making a fun distraction for a few minutes of recouperation, but a game that is booring enough not to keep you from doing important tasks. By this definition Plan 9 has a few "good" games.

Included Games

Plan 9 comes with a collection of games in /bin/games. My favorites include:

Included Game Emulators

The collection also includes a handful of game emulators, assuming you can get hold of a legal copy of the Mario World ROM for instance, you can play it like so: games/snes -a -3 mario.sfc (beware though some of these oldschool games can be dangerously fun!)

3rd Party Games

3rd party games, or indeed software, for Plan 9 is rare. But there are exeptions, some good ones are 2048, hack and snake. See the Package Management section on how to install them.


There are a few educational applications in Plan 9, such as scat, map and graph for drawing star charts, maps and graphs (all of which use plot to actually draw the graphics). Many of the programs in /bin/games are also more edutainment then actual games. This includes simulators such as galaxy, life and timmy. You also have some very computer science nerdy "games" such as blit and mix.


The classic bsdgames collection provides UNIX with many simple edutainment programs, most of which are not available in Plan 9. No matter, we can just write them from scratch. Or at least, I can demonstrate how to implement some of the basic ones. Who knows, manybe these simple scripts will inspire you to write an actually entertaining game yourself :^)

# arithmetic - basic arithmetic quiz
# usage: arithmetic [-q n][-r n][-o '+-*/%^']

# set some default values
rfork ne
range=1							# in digits
start=`{date -n}

# parse optional flags
for(i in $*){
		case -q
			questions=$2 && shift 2
		case -r
			range=$2 && shift 2
		case -o
			operands=''$2'' && shift 2

# rnum: generate a random digit based on cpu clock
fn rnum{
	awk '{ print $2 }' /dev/time | sed 's/.*(.)$/\1/'

# ask math questions
for(i in `{seq $questions}){
	# generate random math puzzle
	if(test $range -gt 1){
		for(i in `{seq `{echo $range - 1 | bc}}){
			a=`{echo $a^`{rnum}}
			b=`{echo $b^`{rnum}}
	if(~ $#opleft 0) opleft=$operands
	if not{
		opused=`{echo $opleft | sed 's/^(.).*/\1/'}
		opleft=`{echo $opleft | sed 's/^.(.*)/\1/'}
	echo $a $"opused $b
    correct=`{ echo $a $"opused $b | bc }
    answere=`{ read }
    # evaluate given answere
    while(! ~ $answere $correct){
    	if(echo $answere | grep -s '^[-+]?[0-9]+$'){
    		echo What?
    		wrong=`{ echo $wrong + 1 | bc }
    	if not echo Please type a number '(no decimals!)'
    	answere=`{ read }
    echo Right!
    right=`{ echo $right + 1 | bc }

# print ressult of math quiz
finish=`{date -n}
time=`{echo $finish - $start | bc}
total=`{echo $right + $wrong | bc}
timepq=`{echo $time / $total | bc}
if(~ $right 0){ prct=0% }
if not prct=`{ echo 'scale=2 ; '$right' / '$total'' | bc | sed 's/\.//' | sed 's/$/%/' }
echo $right right, $wrong wrong '('$prct' correct)' in $time secounds '('$timepq's per answere)'        


Quiz is another simple classic from bsdgames, it just asks you a bunch of questions and keeps track of your progress. Originally the UNIX quiz programs could ask you some fairly dated questions about geography, star trek or the ed editor, but the real beauty of this program is that you can write your own quiz files. In theory you could even use this program for serious purposes, such as training vocabulary or prepping for an exam.

# quiz - ask questions and look for correct answeres
# usage: quiz [-l lang][-as][-q questions][file]
# bug: case is normally ignored, but not for exotic unicode characters, this is
#      a grep bug.
# bug: special characters in the correct answeres must be escaped (eg. \?\!)

# variables
rfork ne
is=(Correct answere is)
if(~ $1 -l){
	lang=$2 && shift 2
	rightanswere=`{echo $rightanswere | sed -f $langfile}
	wronganswere=`{echo $wronganswere | sed -f $langfile}
	is=`{echo $is | sed -f $langfile}
if(~ $1 -a) printanswere=yes && shift 1
if(~ $1 -s) silenterror=yes && shift 1
if(~ $1 -q) questions=$2 && shift 2

# parse args
if(~ $#* 0) ls -p $dir && exit
if(~ $#* 1) file=$dir/$1
if not echo usage: quiz [-q questions][file] && exit
if(test `{cat $file | wc -l} -le $questions) questions=`{cat $file | wc -l}

# ask questions, and check answeres
for(i in `{sed -e '/^$/d' -e '/^#/d' $file | shuf | sed ''$questions'q'}){
	question=`{ echo $i | awk -F@@@ '{ print $1 }' }
	if(echo $question | grep -s '^cmd ') eval `{ echo $question | sed 's/^cmd //'}
	if not echo $question 
	correct=`{ echo $i | awk -F@@@ '{ print $2 }' }
	correct_answere=`{ echo $i | awk -F@@@ '{ print $3 }' }
	if(~ $#correct_answere 0) correct_answere=$correct
	answere=`{ read }
    if(echo $answere | grep -si '^'$correct'$'){
    	if(~ $printanswere yes) echo -n $"rightanswere $"is $"correct_answere
    	if not echo -n $"rightanswere
        right=`{ echo $right + 1 | bc }
    if not{
    	if(~ $silenterror yes) echo -n $"wronganswere
    	if not echo -n $"wronganswere $"is $"correct_answere
        wrong=`{ echo $wrong + 1 | bc }

# calculate ressults
if(~ $right 0){ prct=0% }
if not prct=`{ echo 'scale=2 ; '$right' / '$questions'' | bc | sed 's/\.//' | sed 's/$/%/' }
if(! ~ $lang E){ 
	echo $right right, $wrong wrong '('$prct' correct)' | sed -f $langfile
if not echo $right right, $wrong wrong '('$prct' correct)'

This program expects a plain text database in $home/lib/quiz with two, optionally three, fields separated by @@@. The fields are: question, answer. The correct answer can be written as a regex, to allow for variations, if so then a third field must also be written, the default answer. Here is what the end of my $home/lib/quiz/capitols file looks like:

United Kingdom@@@London
Vanuatu@@@Port Vila
Vietnam@@@Ha ?Noi@@@Ha Noi


Learning to touchtype is a must for any serious computer user, and even for the seasoned sysadmin it is a skill that one might want to brush up on from time to time. There are elaborate touchtyping tutors in UNIX, such as ktouch, but the basic method of learning this skill is fairly simple: Print out a picture of your keyboard layout and stick it to the wall, then type what you need and look at this picture, do not look down at your keyboard (ideally you should also hold your finger on the middle line with both your pinkyfingers on the two keys that have little bumps on them). This is hard to do in the beginning, but if you keep at it, you will gradually learn to touchtype. The following script will not take away the pain and discipline required to learn this skill, but it can help you track your progress. The method is very simple, retype each line that you are given - do not hit backspace and correct your mistakes! -, when you are done the script will tell you how well/bad your typing was.

# touchtype - check your typing speed and accuracy
# usage: touchtype [ file ]

# choose input sample
rfork ne
fortune > $tmp
if(~ $#* 1) cat $1 > $tmp

# do some touchtyping
start=`{date -n}
for(line in `{cat $tmp}){
    echo $line
    read >> $out
stop=`{date -n}

# calculate ressults
time=`{echo $stop - $start | bc}
char=`{cat $tmp | wc -c}
speed=`{echo '('$char' / '$time') * 60' | bc}
err=`{cmp -l $out $tmp | wc -l}
if(~ $#err 0) prc=0
if not prc=`{echo 'scale=2 ; '$err' / '$char'' | bc | sed 's/\.//'}

# print ressults
rm $tmp $out
echo 'RESULT (<2% errors and >200 c/m is good):'
echo your write speed is $speed c/m with $prc^% errors

Playing With Telnet

Believe it or not, but there are actually a lot of fun stuff to be done with telnet, even in 2019! Not least of which is playing MUD's, multi-user-dungeons are still alive and kicking. You can find a list of popular ones on Here are some fun telnet examples (ps: run vt first for a better user experiance):

Miscellaneous Fun

You can do a lot of fun stuff on Plan 9, that do not strictly fall into the category of "gaming". A classic UNIX example is fortune, which will display a random quote. Plan 9 also ships with troll and theo, which does much the same thing, but are more specific. Another fun program is games/festoon, which generates a gibberish troff document, you can use it like so: games/festoon -pet | pic | eqn | tbl | troff -mm | page

Some of the programs in /bin/games are essentially screensavers, such as blabs, juggle, mole, packet, and catclock (although it doubles as a clock too). There is also a 3rd-party port of classic UNIX screensavers available for Plan 9, called xsr.

Of course you can do a lot of fun beyond what we have discussed here, such as reading comics with page, playing music with play, surfing the web with mothra, or learn to program C. But even so, the urge to go back to your mainstream operating system of choice and play a game or watch a video, may be just to great to resist. In such cases vncv is your friend!


There are a great many office suits on most operating systems, and other office utilities besides too numerous to count. So many are the choices in fact that it's easy to forget that "office" is just a fancy word for text. Plan 9 does not delude it's users: You need to be a proficient reader and writer to use the system, and you need to organize and manage your files. In other words, you need to learn essential office skills to use the system.

For an idea of what office tasks simple UNIX tools can do, see the office section in my console desktop howto article. The shell scripts discussed here can easily be converted to Plan 9 scripts.

Reading Office Documents

As far as it's up to you, I'm sure all your documents are plain text as a matter of course. Plain text is editable, searchable, pipeable, programmable. You can mangle it freely with standard tools such as grep, sed and awk, and it doesn't require a flippin terrabyte of diskspace. In Plan 9 text is even more powerful, its always unicode, its plumable, acmeable, zeroxable, yesterdayable, snarfable and devable (yes, these are "real" words). It's the magic goo that holds everything together, much like the real world. You would be insane not to write documents as plain text! But sadly it's not always up to you. Your pesky boss may send you important word documents, with little or no regard for your taste in operating systems. Don't panic. Many office documents are readable with page (naturally html files can be read with mothra). Those documents that aren't handled by page, such as docx or odt, can easily enough be converted to pdf before importing them to your Plan 9 box.

Writing Office Documents

For all it's wonderous benefits, plain text documents has an obvious flaw. They don't look good. If you need to write an article or even just a professional looking letter, you need something a little more sophisticated then monospace fonts. Troff is your friend. Don't be too quick to dismiss this venerable old tool! While the command man man will print a rather unimpressive manual in boring monspaced text, try running the command man -t man | page, and compare the ressults. Clearly, troff can produce professionl looking documents! Besides the man macros for writing manual pages, Plan 9 also includes the ms(6) macros for writing generic articles and letters, and it fully supports unicode of course (a feture sadly lacking in UNIX troff, not to mention tex and docbook). You also use the mpictures(6) macros for including images and the html2ms/ms2html commands for converting troff articles to/from html. See the console desktop howto article mentioned above for further tips.

Spellchecking and PIM

The spellcheker spell(1), and the acme equivalent aspell, is a simple but useful tool for spellcheking english text. But sadly it does not support user supplied dictionaries. Speaking of which, dict(7) is an excellent english dictionary, somewhat equivalent to WordNet in UNIX. To use this tool you need to install some dictionaries from the internet, see the README's in /lib/dict for instructions.

You can use various strategies for spell checking non-english text, as an example consider these functions for spell cheaking norwegian:

fn lower{
	tr A-ZÆØÅ a-zæøå
fn words{
	tr -c 'a-zæøåA-ZÆØÅea''' '
	' | sed 's/''//g' | sort | uniq
fn addwords{
	odict=$1 && shift
	for(word in $*) echo $word >> /tmp/ndict-$pid
	mv /tmp/ndict-$pid $odict

nodict=/lib/		# dictionary of correct norwegian spellings
fn nospell{
	for(word in `{deroff $* | lower | words | comm -13 $nodict -}){
		if(! grep -s '^'$word'$' $nodict) echo $word
fn addnoword{
	addwords $nodict $*

noundict=/lib/	# dictionary of norwegian misspellings
fn nomiss{
	cat $* | lower | words > /tmp/nomiss-$pid
	for(word in `{deroff $noundict}){
		if(grep -s '^'$word'$' /tmp/nomiss-$pid) echo $word
	rm /tmp/nomiss-$pid
fn addnounword{
	addwords $noundict $*

fn nolook{
	look $* $nodict

These functions require you to have a dictionary of correctly spelled norwegian words in /lib/ If you have aspell with a norwegian dictionary in UNIX, you can convert this to a plain text file and then use it in Plan 9. The lower and words shorthands take the special norwegian letters æøå into account. nospell breaks up your document into individual, unique words stripped of any troff syntax, and prints any word not found in the dictionary (much like the standard spell command). nomiss is similar, but uses a dictionary of commonly misspelled words, and prints any word in your document that matches the dictionary (unfortunately comm doesn't handle non-english letters well, which is why we need an extra grep line to catch words that contain the norwegian letters æøå). Finally nolook looks for correct sepellings of norwegian words.

These custom tools are crude, and in particular they do not handle suffixes/prefixes at all. This means that you will have a great many false positives when you first start using them (eg. "computer" may be in the dictionary, but not "computers", "computing" ect...). But as you keep adding the correct spellings to your dictionary with noaddword the number of false positives will grow less and less. If you also record your misspellings with noaddunword, these tools will gradually become honed to your style of writing, and may indeed prove very useful. At least that has been the case for my usage.

As for PIM the simple, but useful, calendar and tel commands are available. And of course date, cal and cron can help you keep track of time and schedule tasks. And with just a little bit of awk you can easily make your own custom PIM software tailored to your needs. Again, take a look at the office section in my UNIX desktop howto article for ideas.

Math, Graphs and Units

There are three calculators available bc, hoc and dc. All of these have more or less the same capabilities, and the old UNIX warhorse bc is probably the one you will be most familiar with.

The units command is helpful for converting different units, such as meter to feet or kilogram to pound (it has some limitations though). As for graphs, we have already mentioned the edu tool graph. Suppose you have the following stock exchange printout:

102	"102"
97	"97"

The command graph -y 80 120 -a < stocks | plot will draw a graph, with the y axis set to vary between 80 and 120, and the x axis set to increment automatically. The lowest and highest points in the graph are also labeled with "97" and "102". Of course you can make much more complicated graphs, suppose you had three columns of numbers in the database, one for each company you have invested in (each optionally tagged with a label). You can then run the command graph -y 80 120 -a -o 3 -p rgb < stocks | plot, to produce a graph of the three companies each with its own color (red, green and blue).

With all its capabilities, the graph program has a fatal flaw: you cannot easily incorporate its graphs into you documents. Fear not though, troff has its own graph tool called grap. It has much the same capabilities as graph but uses a slightly different syntax. To add the stock exchange graph from above in a troff document you could write it as follows:


And you could view the graph by running the command grap | pic | troff | page. Of course if you have a graph of three companies, each with its own style and label, things would become more complicated. Supposing the plot data is in a file called stocks, and looks like this:

1 98 67 88
2 99 69 84
3 102 76 81
4 100 82 77
5 97 84 78

You could write the grap graph like so:

frame invis ht 2 wid 4 left solid bot solid
label left "CompA" left .5 up .7
label left "CompC" left .5
label left "CompB" left .5 down .7
draw compa solid
draw compb dotted
draw compc dashed
copy "stocks" thru X
	next compa at $1,$2
	next compb at $1,$3
	next compc at $1,$4

Like the other troff preprocessors, such as tbl, pic and eqn, it takes a bit of effort to learn their language. But once you get used to the semantics its easy enough.