summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorJames Vasile <james@hackervisions.org>2011-02-22 13:32:45 -0500
committerJames Vasile <james@hackervisions.org>2011-02-22 13:32:45 -0500
commit35071d7212cec1fc23e8204bfd392a116a5313ed (patch)
tree1c75a525227769fc94f303b5c0233882d90ef2a8 /doc
...
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile118
-rw-r--r--doc/colophon.mdwn8
-rw-r--r--doc/design.mdwn196
-rw-r--r--doc/faq.mdwn37
-rw-r--r--doc/footer.html0
-rw-r--r--doc/hacking.mdwn97
-rw-r--r--doc/header.html0
-rw-r--r--doc/modules.mdwn71
-rw-r--r--doc/roadmap.mdwn64
l---------doc/style.css1
-rw-r--r--doc/themes.mdwn59
11 files changed, 651 insertions, 0 deletions
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..2e6037a
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,118 @@
+DOCDIR=../dist/doc
+
+PANDOC=pandoc
+PDFLATEX=pdflatex
+
+
+# List text files in the order in which you want them to appear in the
+# complete manual:
+SOURCES=README.mdwn INSTALL.mdwn themes.mdwn hacking.mdwn TODO.mdwn modules.mdwn scripts.mdwn design.mdwn roadmap.mdwn faq.mdwn COPYING.mdwn colophon.mdwn
+TODO_SOURCES=$(patsubst TODO.mdwn,,$(SOURCES))
+MAN_SOURCES=$(patsubst COPYING.mdwn,copyright_notice00,$(SOURCES))
+
+NEWLINE_SOURCES=$(patsubst %,% oneline.txt,$(SOURCES))
+NEWLINE_MAN_SOURCES=$(patsubst %,% oneline.txt,$(MAN_SOURCES))
+
+HTML=plinth.html $(patsubst %.mdwn,%.html,$(SOURCES))
+HTML_PART=$(patsubst %.html,%.part.html,$(HTML))
+LATEX=plinth.tex $(patsubst %.mdwn,%.tex,$(SOURCES))
+PDF=plinth.pdf $(patsubst %.mdwn,%.pdf,$(SOURCES))
+MAN=plinth.1
+
+OUTPUTS=$(HTML) $(LATEX) $(MAN) $(PDF) $(HTML_PART)
+DIST_OUTPUT=$(patsubst %,$(DOCDIR)/%,$(OUTPUTS))
+
+# Yes, do it twice. TODO created during the process requires a second run
+default:
+ make all
+ make all
+all: oneline.txt $(OUTPUTS) Makefile
+
+$(DOCDIR)/%: %
+ cp $< $@
+dist: $(DIST_OUTPUT)
+###############################################################################
+oneline.txt: Makefile
+ perl -e 'print "\n"' > oneline.txt
+
+$(SOURCES):
+ @rm -f $@
+ @ln -s ../$(patsubst %.mdwn,%,$@) $@
+
+../TODO : $(TODO_SOURCES) ../*.py ../modules/*.py ../Makefile Makefile ../templates/Makefile
+ grep -ro --exclude=.git* --exclude=plinth.1 --exclude=*.tex --exclude=*.html \
+ --exclude=README.mdwn --exclude=INSTALL.mdwn \
+ --exclude=TODO.mdwn --exclude=COPYING.mdwn \
+ "TODO\:.*" ../* 2>/dev/null | \
+ sed -e "s/TODO\://g" | \
+ sed -e "s/^..\//* /g" | \
+ sed -e 's/"""$$//g' | \
+ sed -e 's/<\/p>$$//g' \
+ > ../TODO
+###############################################################################
+##
+## MAN PAGES
+##
+$(MAN): $(SOURCES) ../TODO
+ @csplit -s -f copyright_notice COPYING.mdwn '/##/'
+ cat $(NEWLINE_MAN_SOURCES) | perl -pe 'BEGIN { $$/=undef } $$_ =~ s/\n\n#\s.*/\n/gm; $$_ =~ s/\n\n#/\n\n/gm; $$_ =~ s/(\n\n#\s.*)/uc($$1)/gme' > .make_man
+ $(PANDOC) -s -t man -o $@ .make_man
+ @rm -f copyright_notice0? .make_man
+manpages: $(MAN)
+###############################################################################
+##
+## LaTeX
+##
+%.tex: %.mdwn
+ $(PANDOC) -s --toc -f markdown --standalone -o $@ $<
+
+hacking.tex: hacking.mdwn ../TODO
+ $(PANDOC) -s --toc -f markdown -o $@ hacking.mdwn ../TODO
+
+plinth.tex: $(NEWLINE_SOURCES) ../TODO
+ $(PANDOC) -s --toc -f markdown -o $@ $(NEWLINE_SOURCES)
+
+latex: $(LATEX)
+###############################################################################
+##
+## HTML
+##
+
+
+# This gets us the html sections complete with TOC, but without the
+# HTML and head section boilerplate. /help/view uses the parts.
+%.part.html: %.html
+ csplit -s -f $@ $< '%.*<body>%'
+ sed '1d' $@00 > $@01
+ csplit -s -f $@ $@01 '/<\/body>/'
+ mv $@00 $@
+ rm $@01
+%.html: %.mdwn header.html footer.html style.css Makefile
+ $(PANDOC) -s --toc -c style.css -f markdown -o $@ header.html $< footer.html
+
+hacking.html: hacking.mdwn ../TODO style.css Makefile
+ $(PANDOC) -s --toc -c style.css -o $@ -f markdown hacking.mdwn ../TODO
+
+#plinth.html: $(NEWLINE_SOURCES) ../TODO style.css Makefile
+# $(PANDOC) -s --toc -c style.css -o $@ -f markdown $(NEWLINE_SOURCES)
+
+plinth.html: $(NEWLINE_SOURCES) ../TODO style.css Makefile
+ @csplit -s -f copyright_notice COPYING.mdwn '/##/'
+ $(PANDOC) -s --toc -c style.css -o $@ -f markdown $(NEWLINE_MAN_SOURCES)
+ @rm -f copyright_notice0? .make_man
+
+html: $(HTML) $(HTML_PART)
+###############################################################################
+%.pdf: %.tex
+ $(PDFLATEX) -interaction=batchmode $< >/dev/null
+ $(PDFLATEX) -interaction=batchmode $< >/dev/null # yes, do it twice so the toc works
+
+pdf: $(PDF)
+###############################################################################
+
+clean-latex:
+ rm -f *.log *.out *.aux *.toc
+
+clean: clean-latex
+ rm -f $(OUTPUTS) README.mdwn INSTALL.mdwn TODO.mdwn COPYING.mdwn \
+ copyright_notice0? \#*\# ../TODO oneline.txt
diff --git a/doc/colophon.mdwn b/doc/colophon.mdwn
new file mode 100644
index 0000000..8ab6932
--- /dev/null
+++ b/doc/colophon.mdwn
@@ -0,0 +1,8 @@
+# Colophon
+
+This manual was typed in emacs, formatted using markdown and converted
+to pdf, html, troff and latex using pandoc and pdflatex.
+
+The complete source code to this manual is available in the 'doc'
+directory of the Freedom Box front end source distribution.
+
diff --git a/doc/design.mdwn b/doc/design.mdwn
new file mode 100644
index 0000000..acaa17e
--- /dev/null
+++ b/doc/design.mdwn
@@ -0,0 +1,196 @@
+# Freedom Box Design and Architecture
+
+This article describes and documents architectural considerations for
+my vision of Freedom Box. It is not specific to the user interface
+and instead contains thoughts about the Freedom Box as a whole.
+
+The major immediate design problems that I see are authentication, ip
+addressing, and backup. I'm sure there are others.
+
+If the Freedom Box front end pulls together basic pieces and
+configures them properly, we'll have the start of the freedom stack.
+Then we can build things like free social networking applications on
+top.
+
+## Design Goals
+
+The target hardware for this project is the
+[GuruPlug](http://www.globalscaletechnologies.com/t-guruplugdetails.aspx).
+It has low power consumption, two wired network interfaces, one
+wireless hostapd-capable interface (802.11b), and two usb slots for
+connecting external drives and peripherals. The hardware target might
+change if a better unit becomes available (for example, with 802.11n
+or USB 3 capability). The GuruPlug is reputed to have availability
+problems involving shipping delays, and targetting a unit that cannot
+satsify high demand might be an issue.
+
+Freedom Boxes are not giant honking servers. They are small boxes
+that do perform a lot of functions. They are not heavily resourced.
+So keep things small and light.
+
+By the same token, there is no need to scale up to thousands of users.
+A box should happily serve a person and her family, maybe an extended
+group of friends. Call it 100 people at the most.
+
+The target user for this project is the home consumer of network
+appliances. It ranges from the most basic user (the kind of person
+who might have spent all of three minutes setting up her LinkSys
+WRT54G) to the home enthusiast who wants a local file server for media
+and backups, print server and dns service.
+
+
+## Authentication
+
+Authentication in the context of the Freedom Box is a diffiult
+problem. You need to be able to trust your box, and it needs to be
+able to trust you. What's more, security must withstand forgotten
+passwords, server destruction, changing email addresses and any other
+possible disaster scenario.
+
+In addition, your friends (and their boxes) need to trust your box
+when it acts on your behalf, even if it does so when you're not around
+to enter passphrases or otherwise confirm agency. But even as it
+needs to operate in your absence, it can't itself have authority to
+access all your data, because you might lack exclusive physical
+control of the box (e.g. if you have a roommate). If the box can act
+as you without limits, anybody who takes control of the box takes
+control of your online identity.
+
+What's more, security should be high. Freedom Boxes might contain
+emails or other sensitive documents. The box mediates network
+traffic, which means rooting it would allow an attacker to spy on or
+even change traffic. Demonstrating control of an email address should
+not be enough to gain access to the box and its admin functions.
+
+### Passphrases
+
+Most users habitually think of passwords. We need to force them to
+think of passphrases. It starts by using 'passphrase' in the
+literature. Second, we need to encourage users to pick phrases, and
+prompts should urge them to do so. We also need minimum password
+lengths and maybe even a requirement of at least a few spaces.
+
+Even better than passphrases are passfiles. We should keep a lookout
+for ways to use files instead of phrases when securing the Freedom
+Box.
+
+### A Scheme for Secure Web Login
+
+Passphrases should
+[never be stored in plain text](http://www.codinghorror.com/blog/2007/09/rainbow-hash-cracking.html).
+[MD5 is too fast for passphrases.](http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html)
+Therefore, my current plan for secure website login involves bcrypt:
+
+The server sends the client a permanent salt, PS, a random session
+salt, SS and a number of rounds, R. It brcypts the password using PS
+and stores the result, B.
+
+The browser
+[bcrypts the passphrase using javascript](https://code.google.com/p/javascript-bcrypt/)
+and PS. Then, it bcrypts that result with SS. It does R rounds of
+bcrypt with S. The browser then sends the result, C, back to the
+server.
+
+The server retrieves bcrypts its stored, hashed passphrase and does R
+rounds of bcrypt on it with SS. If that matches C, the passphrase is
+a match.
+
+The server must be able to keep track of sessions, as it needs to
+remember SS between giving it to the client and getting it back. The
+Server cannot rely on the client to remind it of SS. This would allow
+an attacker to dictate SS and leave the server vulnerable to replay
+attacks.
+
+This scheme has the dual advantage of not storing any cleartext
+passphrases and also never sending any cleartext passphrases between
+client and server.
+
+TODO: consult a security expert as to the strength of this scheme
+
+### Other Schemes
+
+#### Monkeysphere
+
+[Monkeysphere](http://web.monkeysphere.info/) is a promising project.
+Monkeysphere's major win is that it avoids the clunkiness of SSL
+certificate authorities. That's huge, except it replaces the
+certificate authority structure with the PGP web of trust. Relying on
+the web of trust is a good idea
+([much better than relying on SSL certificate authorities](http://www.crypto.com/blog/spycerts/)),
+except that new users might not have joined the web. It also requires
+a bunch of GPG infrastructure that might be difficult to setup
+automatically and with little user intervention.
+
+As of this writing, it does not appear to support Windows or Macintosh
+clients, making it unsuitable for this project.
+
+#### Secure Remote Password
+
+[SRP](http://srp.stanford.edu/) is an interesting technique. Patents
+are a concern. What does it buy us that my scheme, above does not?
+
+There is a
+[python implementation](http://members.tripod.com/professor_tom/archives/srpsocket.html),
+although it is not clear that it has been through the crucible. Even
+if SRP is solid, this implementation might be flawed.
+
+
+
+## Finding Each Other
+
+### Dynamic DNS
+
+Each box might need multiple dynamic DNS pointers. Every box is going
+to require its own set of dynamic names. For example, my Freedom Box
+might be known as both `fb.hackervisions.org` and
+`james.softwarefreedom.org`. My work colleagues might know me as
+`james@james.softwarefreedom.org` while my friends might reach me at
+`james@fb.hackervisions.org`. By default, when contacts come in via
+different names, my box might be smart enough to treat those contacts
+differently.
+
+If I share this box with my partner, Emily, she might be
+`emily@jv187.fboxes.columbia.edu`, in which case my box will need
+another dynamic DNS pointer.
+
+### Mesh Networking
+
+Freedom Boxes should be meshed. Rather than run in infrastructure
+mode, they should route for each other and create strong local meshes
+that will carry data for anybody that passes through.
+
+There are some problems, though.
+
+* I'm not sure how well nodes in ad-hoc mesh mode interact with
+others in infrastructure mode.
+
+* The Freedom Box only has one wireless radio, which will drastically
+hurt speed.
+
+* Routing can be difficult when connecting mesh network nodes to the WAN.
+
+## Backup
+
+Everybody should automatically and redundantly store encrypted backups
+on their friend's freedom boxes. Recovery should not assume you kept
+your key or know a password. We can recover the decryption key by
+having a bunch of friends encrypt the key in various combinations. If
+enough of my friends get together, they can decrypt it for me.
+Optionally, a passphrase can serve to slow my friends down if they
+turn against me. Maybe it takes 5 friends acting in concert to
+recover my key, but only 3 to recover a version protected by the
+passphrase.
+
+## Push vs Pull
+
+For a social network, real time communication is key. Asynch
+communication is good, but sometimes people just want to bash comments
+back and forth. For that, you need push, which is just a web fetch
+meaning "pull my rss feed".
+
+If, however, you have a lot of friends and they have a lot of friends,
+your extended network can be large, resulting in many "pull my rss
+feed" commands. We should only process push requests for friends to
+reduce load. You really don't need real time updates of the social
+networking activity of strangers. Friends of friends is as far out as
+things should ever go.
diff --git a/doc/faq.mdwn b/doc/faq.mdwn
new file mode 100644
index 0000000..08c7f16
--- /dev/null
+++ b/doc/faq.mdwn
@@ -0,0 +1,37 @@
+# Plinth and Freedom Plug FAQ
+
+## General Questions
+
+### What is the Freedom Plug?
+
+The Freedom Plug is .... insert links...
+
+The Freedom Plug is based on the GNU/Debian operating system. It is
+not a Linux distribution. It is a network appliance that depends on a
+series of Debian packages that configure a plug computer to behave as
+a Freedom Plug.
+
+### What is Plinth?
+
+Plinth is the web-based GUI administration front end for the Freedom Plug.
+
+### On what hardware is the Freedom Plug based?
+
+The current targets are the [Guru Plug](http://guruplug) and the
+[Dream Plug](http://dreamplug).
+
+## Accessing the Freedom Plug
+
+### Why does ssh listen on port 2222 instead of 22?
+
+If ssh listens on port 2222, bots and scripts will forever attempt to
+guess your username and password. Maybe your password isn't so
+strong. Maybe the bots get lucky. Either way, if you allow ssh
+access on port 22, you're taking a chance that can be avoided quite
+easily by moving your ssh activity to a slightly more obscure port.
+
+Because ssh activity on these boxes will be limited to programs
+configured to work specifically with Freedom Plugs as well relatively
+few people generally using ssh, the coordination necessary to use a
+non-standard port is easily achieved.
+
diff --git a/doc/footer.html b/doc/footer.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/footer.html
diff --git a/doc/hacking.mdwn b/doc/hacking.mdwn
new file mode 100644
index 0000000..38e59fb
--- /dev/null
+++ b/doc/hacking.mdwn
@@ -0,0 +1,97 @@
+# Hacking
+
+This codebase could really use a testing framework.
+
+If you are interested in helping out, writing tests is a great place
+to start-- you don't need to know much about the code or python to
+write useful tests.
+
+In addition to a testing framework, the code is in need of some
+general cleanup. I've been inconsistent in capitalization conventions
+as well as in my use of underscores.
+
+The plugin interface could use some attention as well. Right now,
+it's a a bit of a free-for-all until I see how the plugins actually
+code up. Channeling all that into a few plugin interface grooves
+would be a help.
+
+If you're feeling more ambitious than that, the best way to improve
+Plinth is to add modules. More functionality, especially in the
+router section, could convert the Freedom Box from a good idea to a
+must-have appliance.
+
+Beyond that, we need to train some expert eyes on the interaction
+between Freedom Boxes. Transparent, zero-config box-to-box backup is
+possible. We just need to build an auth and dns layer. There are
+lots of theories on how to do this well. The first theory reduced to
+practice wins!
+
+There is a list of TODO items below. Some of them are discrete pieces
+that can be tackled without diving too deep into the code.
+
+## Repository
+
+Plinth is available from github at
+`git://github.com/jvasile/plinth.git`. The [project page on
+github](https://github.com/jvasile/plinth) is at
+`https://github.com/jvasile/plinth`.
+
+## Bugs
+
+There are lots of bugs. We don't have a spec or tests, so a bug is
+really just any unexpected behavior. I am not easily surprised, but
+there are still lots of bugs.
+
+<a name="hacking_code_practices" />
+
+## Coding Practices
+
+I try to stick to [PEP 8](http://www.python.org/dev/peps/pep-0008/)
+recommendations. That's not to say I don't deviate, just that
+deviations are usually bugs that should be fixed.
+
+### Internationalization
+
+Every module should `from gettext import gettext as _` and wrap
+displayed strings with _(). We don't have the language stuff in place
+yet (we have no translation files), but we need to put the
+infrastructure in place for it from the start. Use it like this:
+
+ cfg.log.error(_("Couldn't import %s: %s") % (path, e))
+
+### Variables and Data Stores
+
+Plinth needs to keep information for short and long term
+future use, and it can't just store all of that on the stack.
+
+Global config information can be put in the `cfg` module namespace.
+Keep it thread and session safe, though, or you'll get undefined
+behavior as soon as multiple simultaneous users enter the picture.
+
+Cherrpy has support for session variables. Use those for short term
+user-specific data.
+
+For long term storage, the Plinth needs a back end
+storage solution. Databases are a bit opaque and can be hard for
+third party software or shell users to manipulate. For now, I've
+decided that persistent data should be placed in dicts and stored in
+json format. We'll need a file locking solution too.
+
+The `user_store.py` module implements the `UserStoreModule` interface
+specified in `plugin_mount.py`. Any new system that respects that
+interface can be used. The existing `user_store.py` holds entire user
+files in memory and caches user files as it goes. This has two
+downsides: first, if you have lots of users and store big things in
+the user dict, you'll run out of memory. Second, it's not thread
+safe. Maybe a database is a good idea after all.
+
+We do not yet have a means of storing module data for long terms. My
+current thinking is that modules can store data in their own
+directories. That makes removal easy.
+
+## Todo
+
+Plinth has a number of open todo items. Please help!
+
+* Implement the functions in the submenus of router.py
+* Unify our logging and cherrypy's.
diff --git a/doc/header.html b/doc/header.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/header.html
diff --git a/doc/modules.mdwn b/doc/modules.mdwn
new file mode 100644
index 0000000..6d8851a
--- /dev/null
+++ b/doc/modules.mdwn
@@ -0,0 +1,71 @@
+# Modules
+
+Almost all of the front end's functionality is contained in small,
+separate modules that reside in the directory tree beneath
+`/modules/installed`. Some are installed by default, some are
+required for operation, and some are entirely optional.
+
+## Installing and Loading Modules
+
+Eventually, the goal is for module to be separate Debian package so
+installation is as simple as `aptitude install freedombox-foo`. As an
+intermediate step, we'll start scripting module installation. But
+until then, we can install them manually.
+
+Modules are installed by copying them into the tree beneath the
+`/modules/installed` directory. They are activated by linking their
+.py files into the modules directory. (Freedom Box will not load
+modules unless they are symlinks.) If the module provides other
+resources, they can be linked from wherever in the working tree they
+need to be. So if a module provides a template, that template can be
+linked from `/templates`.
+
+Modules can be organized into subdirectories beneath the installed
+directory. As an initial matter, I've made separate directories for
+each major tab. Modules that extend the functionality of the Freedom
+Box code base (as opposed to being user-visible interface modules
+under specific major tabs) go in `modules/installed/lib`. This
+convention can be adjusted or ignored as needed. In fact, modules can
+be installed anywhere in the file system as long as the symlinks are
+in `/modules`.
+
+The names of the symlinks in the `modules` directory can be arbitrary,
+and if a name is already taken, (e.g. if `router/info.py` and
+`apps/info.p`y both exist), append a counter to the end (e.g. link
+`info.py` to `router/info.py` and `info1.py` to `apps/info.py`).
+
+If a module cannot be imported for any reason (e.g. it's a dead
+symlink), freedombox.py will log an error but will otherwise just keep
+going.
+
+TODO: automatically prune dead links to clear out old module installs.
+This is something the install scripts should do.
+
+## Pluggable Module Structure
+
+Plugin interfaces are contained in `plugin_mount.py`. Each interface
+is a metaclass. Classes that implement a given interface should
+inherit the metaclass and then provide the indicated properties. New
+metaclasses can be created to make new classes of plugins.
+
+Any place that might be affected by arbitrary addition of modules
+should have its own metaclass.
+
+### FromPlugin
+
+Each form displayed in the interface should inherit from FormPlugin.
+This will allow the system to display multiple forms on the page in
+the correct order. Forms will likely also want to inherit from
+PagePlugin because after the user clicks submit, the plugin usually
+displays a responsive message or an error (along with the form to fill
+out again).
+
+## Coding Practices for Modules
+
+All the
+[coding practices for hacking on the front end](#hacking_code_practices)
+also apply to modules. In addition, I try to stick to the other
+practices listed in this section.
+
+* Every module should `from gettext import gettext as _` and wrap
+displayed strings with _().
diff --git a/doc/roadmap.mdwn b/doc/roadmap.mdwn
new file mode 100644
index 0000000..31c00fb
--- /dev/null
+++ b/doc/roadmap.mdwn
@@ -0,0 +1,64 @@
+# Plinth Roadmap
+
+## 0.1 Basic Wireless Access Point
+
+* <strike>Basic/Expert mode toggle</strike>
+* SSH access
+* Connect to WAN via DHCP and static IP
+* Offer DHCP on wired and wireless interfaces
+* WEP
+* WPA2
+* Bridge WAN and LAN
+
+## 0.2 Basic Wireless Router
+
+* NAT
+* DMZ
+* Port forwarding and triggering
+* dhcp server (on by default, expert can disable)
+* dns server
+* MAC address filtering
+* NTP client
+
+## 0.3 Advanced Wireless Router
+
+* dynamic dns - This is special. See the notes in the section on
+ [dynamic DNS](#dynamic-dns) for details.
+* UPnP
+* Cron
+* Tx power management
+
+## 0.4 File Server, More Routing Features
+
+* boxbackupd
+* NFS
+* Samba
+* Auto mount usb volumes and create samba shares for them
+* TOR
+* Ad blocking web proxy
+* HTTPS everywhere (on by default, experts can disable)
+
+## 0.5 Print Server and Backups
+
+* Social backup to friend's boxes via ddns and boxbackup
+* printer discovery and sharing via samba and cups
+
+## 1.0 Plinth Lives!
+
+* Complete user documentation for every basic and expert menu item
+* Package management complete
+
+## Unscheduled Features
+
+There are a variety of other features to be implemented, but they are
+of lower priority than all the tasks scheduled above.
+
+* NTP Server
+* Provide virtual networks and multiple SSIDs
+* Radius Server
+* QoS
+* file explorer
+* Mesh networking
+* Chaining boxes so the furthest upstream knows to route messages down
+ the chain (e.g. if you and your roommate both have your own box, you
+ just plug one into the other).
diff --git a/doc/style.css b/doc/style.css
new file mode 120000
index 0000000..1d18299
--- /dev/null
+++ b/doc/style.css
@@ -0,0 +1 @@
+../static/theme/style.css \ No newline at end of file
diff --git a/doc/themes.mdwn b/doc/themes.mdwn
new file mode 100644
index 0000000..3546182
--- /dev/null
+++ b/doc/themes.mdwn
@@ -0,0 +1,59 @@
+# Themes and Templates
+
+The visual look and feel of the front end is described in theme files
+while <a href="http://cheetahtemplate.org">Cheetah templates</a>
+handle layout.
+
+## Themes
+
+Themes are stored in `/themes`. Themes consist entirely of static
+files (e.g. css, images and javascript) and templates. The default or
+active theme is linked from `/static/default` and `templates/default`.
+If your theme needs to change anything other than these items, you'll
+need a module (perhaps you'll need both).
+
+There is not currently any support for dynamically choosing a theme at
+runtime, but it is theoretically possible.
+
+## Templates
+
+Plinth uses the Cheetah templating system. Templates are stored in
+`/templates`. Template requirements are not specified.
+
+TODO: formalize the template spec so template writers know what they need to implement and where they can deviate.
+
+In this section, I'll attempt to document some of the assumptions the
+program has about templates. The goal is that if you write a tempate
+that implements the spec, it should work just fine.
+
+### The Template Stack
+The template is a hierarchical stack, where some templates extend on
+others. At the base of this stack is `base.tmpl`. It should specify
+variables as blocks (rather than using the $ notation). This allows
+other templates to easily override the base template.
+
+Next up is the `page.tmpl`. It extends `base.tmpl` and simply
+replaces all the blocks with interpolable variables. Most of the
+time, `page.tmpl` is what you will actually use to create pages.
+
+`err.tmpl` builds on top of `page.tmpl` by adding some decoration to
+the title field.
+
+### Layout
+
+Plinth expects a `main` block. This is where the
+meat of the content goes. It is the center pain in the default
+layout. There is a `title` block that the program will fill with text
+describing the current page. `sidebar_left` contains the submenu
+navigation menu, and `sidebar_right` is where we put all short text
+that helps the admin fill out forms. They don't have to be sidebars,
+and they don't have to go on the left and right.
+
+It is possible to override the `footer`, but I haven't yet found a
+reason to do so.
+
+## Cheetah
+
+This section is for Cheetah hints that are especially useful in this context.
+
+TODO: add Cheetah hints