diff --git a/.travis.yml b/.travis.yml
new file mode 100644
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,60 @@
+# NB: don't set `language: haskell` here
+
+# See also https://github.com/hvr/multi-ghc-travis for more information
+env:
+ # we have to use CABALVER=1.16 for GHC<7.6 as well, as there's
+ # no package for earlier cabal versions in the PPA
+ - GHCVER=7.4.2 CABALVER=1.16
+ - GHCVER=7.6.3 CABALVER=1.16
+ - GHCVER=7.8.4 CABALVER=1.18
+ - GHCVER=7.10.1 CABALVER=1.22
+ - GHCVER=head CABALVER=1.22
+
+matrix:
+  allow_failures:
+   - env: GHCVER=head CABALVER=1.20
+
+# Note: the distinction between `before_install` and `install` is not
+#       important.
+before_install:
+ - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
+ - travis_retry sudo apt-get update
+ - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER
+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
+ - cabal --version
+
+install:
+ - travis_retry cabal update
+ - cabal install --only-dependencies
+
+# Here starts the actual work to be performed for the package under
+# test; any command which exits with a non-zero exit code causes the
+# build to fail.
+script:
+ # -v2 provides useful information for debugging
+ - cabal configure -v2
+
+ # this builds all libraries and executables
+ # (including tests/benchmarks)
+ - cabal build
+
+ # tests that a source-distribution can be generated
+ - cabal sdist
+
+ # check that the generated source-distribution can be built & installed
+ - export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ;
+   cd dist/;
+   if [ -f "$SRC_TGZ" ]; then
+      cabal install --force-reinstalls "$SRC_TGZ";
+   else
+      echo "expected '$SRC_TGZ' not found";
+      exit 1;
+   fi
+
+notifications:
+  irc:
+    channels:
+      - "irc.freenode.org#haskell-lens"
+    skip_join: true
+    template:
+      - "\x0313foreign-var\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.markdown
@@ -0,0 +1,3 @@
+0
+-
+* Initialized repository based on code from `Quine.StateVar` in [quine](http://github.com/ekmett/quine).
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2014-2015 Edward Kmett
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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/README.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,15 @@
+foreign-var
+===========
+
+[![Build Status](https://secure.travis-ci.org/ekmett/foreign-var.png?branch=master)](http://travis-ci.org/ekmett/foreign-var)
+
+This package provides an API for working with bits of state, usually foreign, which require mutation to change.
+
+Contact Information
+-------------------
+
+Contributions and bug reports are welcome!
+
+Please feel free to contact me through github or on the #haskell IRC channel on irc.freenode.net.
+
+-Edward Kmett
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/foreign-var.cabal b/foreign-var.cabal
new file mode 100644
--- /dev/null
+++ b/foreign-var.cabal
@@ -0,0 +1,32 @@
+name:          foreign-var
+category:      FFI, Mutable State
+version:       0
+license:       BSD3
+cabal-version: >= 1.10
+license-file:  LICENSE
+author:        Edward A. Kmett
+maintainer:    Edward A. Kmett <ekmett@gmail.com>
+stability:     provisional
+homepage:      http://github.com/ekmett/foreign-var/
+bug-reports:   http://github.com/ekmett/foreign-var/issues
+copyright:     Copyright (C) 2014-2015 Edward A. Kmett
+synopsis:      Encapsulating mutatable state in external libraries
+description:   Encapsulating mutatable state in external libraries
+build-type:    Simple
+extra-source-files: .travis.yml README.markdown CHANGELOG.markdown
+
+source-repository head
+  type: git
+  location: git://github.com/ekmett/foreign-var.git
+
+library
+  default-language: Haskell2010
+  hs-source-dirs: src
+  ghc-options: -Wall
+
+  exposed-modules: Foreign.Var
+
+  build-depends:
+    base         >= 4   && < 5,
+    stm          >= 2.0 && < 2.5,
+    transformers >= 0.2 && < 0.5
diff --git a/src/Foreign/Var.hs b/src/Foreign/Var.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Var.hs
@@ -0,0 +1,209 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE TypeFamilies #-}
+--------------------------------------------------------------------
+-- |
+-- Copyright :  (c) 2014-2015 Edward Kmett
+-- License   :  BSD2
+-- Maintainer:  Edward Kmett <ekmett@gmail.com>
+-- Stability :  experimental
+-- Portability: non-portable
+--
+--------------------------------------------------------------------
+module Foreign.Var
+  (
+  -- * Variables
+    Var(..)
+  , newVar
+  , mapVar
+  , SettableVar(SettableVar)
+  , GettableVar
+  -- * Classes
+  , HasSetter(($=)), ($=!)
+  , HasUpdate(($~), ($~!))
+  , HasGetter(get)
+  ) where
+
+import Control.Concurrent.STM
+import Control.Monad.IO.Class
+import Data.Functor
+import Data.IORef
+import Data.Typeable
+import Foreign.Ptr
+import Foreign.Storable
+--import Data.Void
+--import Data.Functor.Contravariant
+--import Data.Functor.Contravariant.Divisible
+
+--------------------------------------------------------------------
+-- * Var
+--------------------------------------------------------------------
+
+-- | This data type represents a piece of mutable, imperative state
+-- with possible side-effects. These tend to encapsulate all sorts
+-- tricky behavior in external libraries, and may well throw
+-- exceptions.
+--
+-- Inhabitants __should__ satsify the following properties.
+--
+-- In the absence of concurrent mutation from other threads or a
+-- thrown exception:
+--
+-- @
+-- do x <- 'getVar' v; 'setVar' v y; 'setVar' v x
+-- @
+--
+-- should restore the previous state.
+--
+-- Ideally, in the absence of thrown exceptions:
+--
+-- @
+-- 'setVar' v a >> 'getVar' v
+-- @
+--
+-- should return @a@, regardless of @a@. In practice some 'Var's only
+-- permit a very limited range of value assignments, and do not report failure.
+--
+-- The result of 'updateVar' should also be compatible with the result of getting
+-- and setting separately, however, it may be more efficient or have better
+-- atomicity properties in a concurrent setting.
+data Var a = Var
+  { getVar :: IO a                  -- ^ Used by 'get'
+  , updateVar  :: (a -> a) -> IO () -- ^ Used by @('$~')@
+  , updateVar' :: (a -> a) -> IO () -- ^ Used by @('$~!')@
+  , setVar :: a -> IO ()            -- ^ Used by @('$=')@
+  } deriving Typeable
+
+-- | Build a 'Var' form a getter and a setter.
+newVar :: (IO a)       -- ^ getter
+       -> (a -> IO ()) -- ^ setter
+       -> Var a
+newVar g s = Var g u u' s where
+  u f = do
+    a <- g
+    s (f a)
+  u' f = do
+    a <- g
+    s $! f a
+
+-- | Change the type of a 'Var'
+mapVar :: (b -> a) -> (a -> b) -> Var a -> Var b
+mapVar ba ab (Var ga ua ua' sa) = Var (ab <$> ga) (\bb -> ua (ba . bb . ab)) (\bb -> ua' (ba . bb . ab)) (sa . ba)
+{-# INLINE mapVar #-}
+
+newtype SettableVar a = SettableVar (a -> IO ())
+  deriving Typeable
+
+{-
+instance Contravariant SettableVar where
+  contramap f (SettableVar k) = SettableVar (k . f)
+  {-# INLINE contramap #-}
+
+instance Divisible SettableVar where
+  divide k (SettableVar l) (SettableVar r) = SettableVar $ \ a -> case k a of
+    (b, c) -> l b >> r c
+  conquer = SettableVar $ \_ -> return ()
+
+instance Decidable SettableVar where
+  lose k = SettableVar (absurd . k)
+  choose k (SettableVar l) (SettableVar r) = SettableVar $ \ a -> case k a of
+    Left b -> l b
+    Right c -> r c
+-}
+
+type GettableVar = IO
+
+--------------------------------------------------------------------
+-- * HasSetter
+--------------------------------------------------------------------
+
+infixr 2 $=, $=!
+
+class HasSetter t a | t -> a where
+  ($=) :: MonadIO m => t -> a -> m ()
+
+($=!) :: (HasSetter t a, MonadIO m) => t -> a -> m ()
+p $=! a = (p $=) $! a
+{-# INLINE ($=!) #-}
+
+instance HasSetter (SettableVar a) a where
+  SettableVar f $= a = liftIO (f a)
+  {-# INLINE ($=) #-}
+
+instance HasSetter (Var a) a where
+  Var _ _ _ s $= a = liftIO $ s a
+
+instance Storable a => HasSetter (Ptr a) a where
+  p $= a = liftIO $ poke p a
+  {-# INLINE ($=) #-}
+
+instance HasSetter (IORef a) a where
+  p $= a = liftIO $ writeIORef p a
+  {-# INLINE ($=) #-}
+
+instance HasSetter (TVar a) a where
+  p $= a = liftIO $ atomically $ writeTVar p a
+
+--------------------------------------------------------------------
+-- * HasUpdate
+--------------------------------------------------------------------
+
+infixr 2 $~, $~!
+
+class HasSetter t a => HasUpdate t a b | t -> a b where
+  ($~) :: MonadIO m => t -> (a -> b) -> m ()
+  default ($~) :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()
+  r $~ f = liftIO $ do
+    a <- get r
+    r $= f a
+  ($~!) :: MonadIO m => t -> (a -> b) -> m ()
+  default ($~!) :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()
+  r $~! f = liftIO $ do
+    a <- get r
+    r $=! f a
+
+instance HasUpdate (Var a) a a where
+  Var _ u _ _ $~  f = liftIO $ u f
+  Var _ _ v _ $~! f = liftIO $ v f
+
+instance Storable a => HasUpdate (Ptr a) a a
+
+instance HasUpdate (IORef a) a a where
+  r $~ f  = liftIO $ atomicModifyIORef r $ \a -> (f a,())
+  r $~! f = liftIO $ atomicModifyIORef' r $ \a -> (f a,())
+
+instance HasUpdate (TVar a) a a where
+  r $~ f = liftIO $ atomically $ do
+    a <- readTVar r
+    writeTVar r (f a)
+  r $~! f = liftIO $ atomically $ do
+    a <- readTVar r
+    writeTVar r $! f a
+
+--------------------------------------------------------------------
+-- * HasGetter
+--------------------------------------------------------------------
+
+class HasGetter t a | t -> a where
+  get :: MonadIO m => t -> m a
+
+instance HasGetter (Var a) a where
+  get (Var g _ _ _) = liftIO g
+
+instance HasGetter (TVar a) a where
+  get = liftIO . atomically . readTVar
+
+instance HasGetter (IO a) a where
+  get = liftIO
+
+instance HasGetter (STM a) a where
+  get = liftIO . atomically
+
+instance Storable a => HasGetter (Ptr a) a where
+  get = liftIO . peek
+
+instance HasGetter (IORef a) a where
+  get = liftIO . readIORef
