diff -rN -u old-irc/docs/configuration.txt new-irc/docs/configuration.txt
--- old-irc/docs/configuration.txt	2009-03-30 14:38:45.000000000 -0500
+++ new-irc/docs/configuration.txt	2009-03-30 14:38:45.000000000 -0500
@@ -279,6 +279,26 @@
  larger than N.
 
 
+== Chat Service Configuration ==
+
+[chat]
+enabled = (boolean, optional)
+
+ Tahoe client nodes can particpate in a simple IRC-style chat service. When
+ enabled, each node's Welcome page will show a transcript of recent messages,
+ and a panel to send messages to the group. The default is False.
+
+publish_activity = (boolean, optional)
+
+ If this is set to True, then a summary of local node activity will be
+ published to the chat channel. This means all file upload and download
+ operations will be announced, with a rough filesize and abbreviated storage
+ index string. It also includes directory reads/writes. No confidential
+ information will be transmitted (i.e. no readcaps). The intent is to
+ increase the visibility of the community centered around this grid: members
+ can tell that other members are using the grid.
+
+
 == Storage Server Configuration ==
 
 [storage]
diff -rN -u old-irc/src/allmydata/chat.py new-irc/src/allmydata/chat.py
--- old-irc/src/allmydata/chat.py	1969-12-31 18:00:00.000000000 -0600
+++ new-irc/src/allmydata/chat.py	2009-03-30 14:38:45.000000000 -0500
@@ -0,0 +1,27 @@
+from allmydata.util.observer import ObserverList
+
+class ChatClient(Referenceable):
+    MAX_RECENT_MESSAGES = 100
+
+    def __init__(self):
+        self.ic = ??
+        self.local_subscribers = ObserverList()
+        self.recent_messages = [] # list of (timestamp, from, message)
+
+    def broadcast(self, message):
+        for rref in self.ic.get_all_connections_for("chat"):
+            rref.callRemoteOnly("broadcast", me, message)
+
+    def remote_broadcast(self, fromwho, message):
+        now = time.time()
+        self.recent_messages.append( (now, fromwho, message) )
+        self.local_subscribers.notify(fromwho, message)
+
+    def subscribe_to_incoming_messages(self, observer):
+        return self.local_subscribers.subscribe(observer)
+    def unsubscribe_to_incoming_messages(self, observer):
+        self.local_subscribers.unsubscribe(observer)
+
+    def get_recent_messages(self):
+        return self.recent_messages # please don't modify this
+        
diff -rN -u old-irc/src/allmydata/test/test_chat.py new-irc/src/allmydata/test/test_chat.py
--- old-irc/src/allmydata/test/test_chat.py	1969-12-31 18:00:00.000000000 -0600
+++ new-irc/src/allmydata/test/test_chat.py	2009-03-30 14:38:45.000000000 -0500
@@ -0,0 +1,55 @@
+
+import os.path
+from twisted.trial import unittest
+from twisted.internet import defer
+from allmydata.test.common import SystemTestMixin
+
+class Chat(SystemTestMixin, unittest.TestCase):
+
+    def _enable_chat(self, clientdir):
+        cfgfn = os.path.join(clientdir, "tahoe.cfg")
+        oldcfg = open(cfgfn, "r").read()
+        f = open(cfgfn, "wt")
+        f.write(oldcfg)
+        f.write("\n")
+        f.write("[chat]\n")
+        f.write("enabled = True\n")
+        f.write("\n")
+        f.close()
+        return None
+
+    def _enable_chat_and_publish(self, clientdir):
+        cfgfn = os.path.join(clientdir, "tahoe.cfg")
+        oldcfg = open(cfgfn, "r").read()
+        f = open(cfgfn, "wt")
+        f.write(oldcfg)
+        f.write("\n")
+        f.write("[chat]\n")
+        f.write("enabled = True\n")
+        f.write("publish_activity = True\n")
+        f.write("\n")
+        f.close()
+        return None
+                     
+    def test_chat(self):
+        self.basedir = "chat/Chat/chat"
+
+        hooks = {0: self._enable_chat,
+                 1: self._enable_chat_and_publish }
+        self.set_up_grid(num_servers=0, client_config_hooks=hooks)
+        c0 = self.g.clients[0]
+        c0.chatter.broadcast("Hello World")
+        c1 = self.g.clients[1]
+
+        d = defer.Deferred()
+        EXPECTED = 3
+        def _got_message(fromwho, message):
+            messages = c1.chatter.get_recent_messages()
+            if len(messages) == EXPECTED:
+                d.callback(messages)
+        c1.chatter.subscribe_to_incoming_messages(_got_message)
+
+        def _check(messages):
+            self.failUnless("Hello World" in messages, messages)
+        d.addCallback(_check)
+        return d
diff -rN -u old-irc/src/allmydata/util/observer.py new-irc/src/allmydata/util/observer.py
--- old-irc/src/allmydata/util/observer.py	2009-03-30 14:38:45.000000000 -0500
+++ new-irc/src/allmydata/util/observer.py	2009-03-30 14:38:45.000000000 -0500
@@ -82,7 +82,7 @@
     def __init__(self):
         self._watchers = []
 
-    def subscribe(self, observer):
+    def subscribe(self, observer):   # todo *args, **kwargs
         self._watchers.append(observer)
 
     def unsubscribe(self, observer):

