diff --git a/Control/Concurrent/Chan/Class.hs b/Control/Concurrent/Chan/Class.hs
new file mode 100644
--- /dev/null
+++ b/Control/Concurrent/Chan/Class.hs
@@ -0,0 +1,52 @@
+module Control.Concurrent.Chan.Class
+    where
+
+import qualified Control.Concurrent.Chan as C
+import Control.Concurrent.MVar
+
+{-
+ - We create a set of classes for FIFO Chan types, using the function names from
+ - Control.Concurrent.Chan, but ommiting deprecated functions.
+ -     We also omit the 'dupChan' function because it is not central to the Chan
+ - concept. Similarly we omit getChanContents as a method, because it is not
+ - necessary that every Chan should have a stream interface.
+-}
+
+
+-- | A class for Chan types that can be written to. A minimum complete
+-- instance defines one of 'writeList2Chan' or 'writeChan'
+class WritableChan c where
+    -- | Write an entire list of items to a chan type
+    writeList2Chan :: c a -> [a] -> IO ()
+    writeList2Chan = mapM_ . writeChan
+
+    -- | Write a value to a Chan type.
+    writeChan :: c a -> a -> IO ()
+    writeChan c = writeList2Chan c . return
+
+-- | A class for Chan types that can be read from. 
+class ReadableChan c where
+    -- | Read the next value from the 'OutChan'.
+    readChan :: c a -> IO a
+
+
+
+-- -------------------------------
+-- INSTANCES FOR STANDARD TYPES --
+-- -------------------------------
+
+
+instance WritableChan C.Chan where
+    writeList2Chan = C.writeList2Chan
+    writeChan = C.writeChan
+
+instance ReadableChan C.Chan where
+    readChan = C.readChan
+
+
+-- an MVar is a bounded Singleton Chan. Think about it.
+instance WritableChan MVar where
+    writeChan = putMVar
+
+instance ReadableChan MVar where
+    readChan = takeMVar
diff --git a/Control/Concurrent/Chan/Split.hs b/Control/Concurrent/Chan/Split.hs
new file mode 100644
--- /dev/null
+++ b/Control/Concurrent/Chan/Split.hs
@@ -0,0 +1,76 @@
+{-# LANGUAGE GADTs #-}
+module Control.Concurrent.Chan.Split (
+    -- * Chan pairs
+      newSplitChan
+    , InChan()
+    , OutChan()
+    -- * Utility functions:
+    , getChanContents
+    , dupChan     
+
+    ) where
+
+import qualified Control.Concurrent.Chan as C
+import Data.Cofunctor
+import Control.Applicative
+import Control.Arrow
+-- provided by chan-split:
+import Control.Concurrent.Chan.Class
+
+-- TODO: test performance of this with and without fmaped / cofmaped values in
+-- comparison with standard Chan. Test to see if we can improve performance
+-- using special constructor for fmaped / cofmaped version
+
+
+-- | The "write side" of a chan pair
+data InChan i where
+    InChan :: (i -> a) -> C.Chan a -> InChan i
+
+-- | The "read side" of a chan pair
+data OutChan o where
+    OutChan :: (a -> o) -> C.Chan a -> OutChan o
+
+-- | Create corresponding read and write ends of a chan pair. Writes to the
+-- 'InChan' side can be read on the 'OutChan' side.
+newSplitChan :: IO (InChan a, OutChan a)
+newSplitChan = (InChan id &&& OutChan id) <$> C.newChan
+
+
+
+instance WritableChan InChan where
+    writeChan (InChan f c) = C.writeChan c . f
+    writeList2Chan (InChan f c) = C.writeList2Chan c . map f
+
+instance ReadableChan OutChan where
+    readChan (OutChan f c) = f <$> C.readChan c 
+
+instance Cofunctor InChan where
+    cofmap f' (InChan f c) = InChan (f . f') c
+
+instance Functor OutChan where
+    fmap f' (OutChan f c) = OutChan (f' . f) c
+
+
+
+
+-- | Return a lazy list representing the contents of the supplied OutChan, much
+-- like System.IO.hGetContents.
+getChanContents :: OutChan a -> IO [a]
+getChanContents (OutChan f c) = map f <$> C.getChanContents c
+
+
+-- | Duplicate an 'OutChan': the duplicate channel begins empty, but data
+-- written to the corresponding 'InChan' will appear in both, i.e. consuming a
+-- value from the copy will have no affect on the values in the original
+-- OutChan.
+dupChan :: OutChan a -> IO (OutChan a)
+dupChan (OutChan f c) = OutChan f <$> C.dupChan c
+
+{-
+-- | EXPERIMENTAL: combine multiple output chans, interleaving their values
+mergeOutChans :: [OutChan a] -> IO (OutChan a)
+mergeOutChans cs = 
+    as <- mapM C.getChanContents cs
+    ...
+    -}
+
diff --git a/Data/Cofunctor.lhs b/Data/Cofunctor.lhs
new file mode 100644
--- /dev/null
+++ b/Data/Cofunctor.lhs
@@ -0,0 +1,10 @@
+> module Data.Cofunctor (
+>     Cofunctor(..)
+>     ) where
+
+
+This doesn't seem to be a popular class, unfortunately but it's useful for us
+here: it lets us transform a Mailbox/sink/processor of one input type to another
+
+> class Cofunctor f where
+>     cofmap :: (b -> a) -> f a -> f b
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2011, Brandon Simmons
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Brandon Simmons nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/chan-split.cabal b/chan-split.cabal
new file mode 100644
--- /dev/null
+++ b/chan-split.cabal
@@ -0,0 +1,90 @@
+-- chan-split.cabal auto-generated by cabal init. For additional
+-- options, see
+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
+-- The name of the package.
+Name:                chan-split
+Homepage:            http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/
+
+-- The package version. See the Haskell package versioning policy
+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
+-- standards guiding when and how versions should be incremented.
+Version:             0.1.2
+
+-- A short (one-line) description of the package.
+Synopsis:            Concurrent Chans as read/write pairs. Also provides generic
+                     Chan, Cofunctor classes.
+
+-- A longer description of the package.
+Description:         A wrapper around Control.Concurrent.Chan that splits a Chan
+                     into a pair, one of which allows only read operations, the
+                     other write operations. 
+                     .
+                     This makes code easier to reason about, allows us to define
+                     useful instances ('Functor' and 'Cofunctor') on the chan
+                     pairs.
+                     .
+                     In addition this package provides a module that defines a
+                     pair of classes 'ReadableChan' and 'WritableChan' which
+                     defines the basic methods any Chan type should provide.
+                     .
+                     To use standard Chans with these polymorphic functions,
+                     import as follows:
+                     .
+                     > import Control.Concurrent.Chan hiding (readChan,writeChan,writeList2Chan)
+                     > import Control.Concurrent.Chan.Class
+                     .
+                     When used alongside standard Chans, the Split module can be
+                     imported qualified like:
+                     .
+                     > import qualified Control.Concurrent.Chan.Split as S
+                     .
+                     Note, we do not implement the deprecated unGetChan and 
+                     isEmptyChan functions.
+                     .
+                     This module is used internally by the simple-actors package.
+
+-- The license under which the package is released.
+License:             BSD3
+
+-- The file containing the license text.
+License-file:        LICENSE
+
+-- The package author(s).
+Author:              Brandon Simmons
+
+-- An email address to which users can send suggestions, bug reports,
+-- and patches.
+Maintainer:          brandon.m.simmons@gmail.com
+
+-- A copyright notice.
+-- Copyright:           
+
+Category:            Concurrency
+
+Build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or
+-- a README.
+-- Extra-source-files:  
+
+-- Constraint on the version of Cabal needed to build this package.
+Cabal-version:       >=1.2
+
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     Control.Concurrent.Chan.Split
+                     , Control.Concurrent.Chan.Class
+                     , Data.Cofunctor
+  
+  -- Packages needed in order to build this package.
+  Build-depends:       base >= 4 && < 5
+  
+  ghc-options:        -Wall
+
+  -- Modules not exported by this package.
+  -- Other-modules:       
+  
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:         
+  
