diff --git a/IO/Filesystem.hs b/IO/Filesystem.hs
new file mode 100644
--- /dev/null
+++ b/IO/Filesystem.hs
@@ -0,0 +1,161 @@
+{-# LANGUAGE RankNTypes, ImplicitParams, LambdaCase #-}
+module IO.Filesystem (
+  -- * Exported modules
+  module System.FilePath,module Definitive,
+
+  -- * The File interface
+  File(..),DirEntry(..),
+  getFile,
+  
+  workingDirectory,
+  Location(..),
+  pathTo,getConfig,
+
+  -- ** A useful monad for manipulating the filesystem as a state
+  FS(..),Filesystem,file,
+  
+  -- ** Status
+  modTime,
+  
+  -- ** Useful Lenses
+  contents,children,child,descendant,subEntry,anyEntry,entryName,entryFile,
+  named,withExtension,
+  fileName,entry,text,bytes
+  ) where
+
+import Definitive
+import Control.DeepSeq
+import IO.Time
+import System.Directory 
+import System.FilePath ((</>),FilePath)
+import System.IO.Unsafe
+import System.Posix.Process (getProcessID)
+import Data.Time.Clock.POSIX
+import qualified Prelude as P
+
+data File = File (Maybe String) (Maybe Bytes)
+          | Directory (Map String File) 
+instance Show File where
+  show (File _ _) = "File"
+  show (Directory d) = show d
+instance Semigroup File where
+  Directory d + Directory d' = Directory ((d*d')+(d+d'))
+  a + _ = a
+instance Monoid File where zero = File zero zero
+
+data DirEntry = DirEntry FilePath File
+              deriving Show
+instance Lens1 String String DirEntry DirEntry where
+  l'1 = from _DirEntry.l'1
+instance Lens2 File File DirEntry DirEntry where
+  l'2 = from _DirEntry.l'2
+fileName :: Lens' DirEntry String
+fileName = l'1
+entry :: Lens' DirEntry File
+entry = l'2
+
+il :: IO a -> IO a
+il = unsafeInterleaveIO
+getFile :: FilePath -> IO File
+getFile path = do
+  d <- doesDirectoryExist path
+  if d then do
+    files <- unsafeInterleaveIO (getDirectoryContents path)
+    return $ Directory $ fromList [
+      (name,unsafePerformIO (getFile (path</>name)))
+      | name <- files, not (name`elem`[".",".."])]
+    else File<$>il (tryMay $ force<$>P.readFile path)
+         <*>il (tryMay $ readBytes path)
+
+_File :: ((Maybe String,Maybe Bytes):+:Map String File) :<->: File
+_File = iso f' f
+  where f (File x y) = Left (x,y)
+        f (Directory d) = Right d
+        f' = uncurry File <|> Directory
+_DirEntry :: (FilePath,File) :<->: DirEntry
+_DirEntry = iso (uncurry DirEntry) (\ ~(DirEntry p f) -> (p,f))
+contents :: Traversal' File (Maybe String,Maybe Bytes)
+contents = from _File.t'l
+children :: Traversal' File (Map String File)
+children = from _File.t'r
+child :: Traversal' File File
+child = children.traverse
+descendant :: Fold' File File
+descendant = id .+ child.descendant
+subEntry :: Traversal' DirEntry DirEntry
+subEntry = entryFile.children.keyed.traverse._DirEntry
+anyEntry :: Fold' DirEntry DirEntry
+anyEntry = id .+ subEntry.anyEntry
+entryName :: Lens' DirEntry String
+entryName = from _DirEntry.l'1
+entryFile :: Lens' DirEntry File
+entryFile = from _DirEntry.l'2
+text :: Traversal' File String
+text = contents.lens fst (const (,zero)).folded
+bytes :: Traversal' File Bytes
+bytes = contents.l'2.folded
+
+named :: (String -> Bool) -> Traversal' DirEntry DirEntry
+named p = sat (\(DirEntry name _) -> p name)
+withExtension :: String -> Traversal' DirEntry DirEntry
+withExtension e = named (\s -> drop (length s-(length e+1)) s==('.':e))
+
+-- |The working directory, as a DirEntry
+workingDirectory :: IO DirEntry
+workingDirectory = DirEntry "." <$> (getFile =<< getCurrentDirectory)
+
+modTime :: FilePath -> IO (TimeVal Seconds)
+modTime p = try (return minBound) (getModificationTime p <&> pure . realToFrac . utcTimeToPOSIXSeconds)
+
+data Location = Here | Cache | Owner | System
+
+pathTo :: ( ?progName :: FilePath ) => Location -> FilePath
+pathTo Here = getCurrentDirectory^.thunk
+pathTo Cache = (getTemporaryDirectory^.thunk) </> ?progName + "-" + show (getProcessID^.thunk) 
+pathTo Owner = getHomeDirectory^.thunk </> "." + ?progName
+pathTo System = "/usr/share" </> ?progName
+
+getConfig :: ( ?progName :: FilePath ) => IO File
+getConfig = sum<$>sequence [getFile (pathTo d) | d <- [Owner,System]]
+
+instance NFData File where
+  rnf (File _ (Just b)) = rnf b
+  rnf (File (Just a) _) = rnf a
+  rnf (Directory d) = rnf d
+  rnf _ = ()
+
+{-|
+The FS monad is a wrapper around the IO monad that provides a
+MonadState instance for interacting with the filesystem through the
+Filesystem type.
+
+Thus, you may use lenses to access the representation of files as
+though they were variables, like so :
+
+> runFS $ (file "x.bmp".bytes.serial.from bmp) fs ^>= \r ->
+>     file "foo".bytes.serial.from jpg =- r
+
+-}
+newtype FS a = FS { runFS :: IO a }
+               deriving (Functor,Unit,Applicative,Monad,MonadFix)
+instance MonadState Filesystem FS where
+  get = FS (return zero)
+  put (Filesystem fs) = FS $ fs`deepseq`for_ (fs^.keyed) $ \(k,f) -> remove k >> putFile k f
+    where putFile k (File _ (Just b)) = writeBytes k b
+          putFile k (File (Just s) _) = P.writeFile k s
+          putFile _ (File _ _) = unit
+          putFile k (Directory d) = for_ (d^.keyed) $ \(k',f) -> putFile (k+k') f
+          remove f = doesDirectoryExist f >>= \case
+            True -> getDirectoryContents f >>= \c -> traverse_ (remove . (f+)) ([]+refuse (`elem`[".",".."]) c)
+                                                     >> removeDirectory f
+            False -> try unit (removeFile f)
+  
+newtype Filesystem = Filesystem (Map String File)
+                   deriving (Semigroup,Monoid)
+instance DataMap Filesystem String File where
+  at k = lens f g
+    where f (Filesystem m) = Just $ fromMaybe (getFile k^.thunk) $ m^.at k
+          g (Filesystem m) x = Filesystem (insert k (fold x) m)
+
+file :: String -> Lens' Filesystem File
+file f = at f.folded
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,39 @@
+THE FREE BEER PUBLIC LICENSE
+--------
+
+The Free Beer Public License is designed to provide free (as in beer,
+hence the name), unlimited access to any content for anyone who wishes
+it, without restrictions such as property rights or affordability.
+
+This license embodies the philosophy that all software (and more
+generally all good ideas) is designed to solve a particular problem,
+and that the only way to judge its quality is by how well it solves
+that problem, rather than other unrelated criteria such as sellability
+or merchandability.
+
+All kinds of works may be licensed under the FBPL, as long as the
+aforementioned works are within the legal rights of the provider to
+give.
+
+TERMS AND CONDITIONS
+--------------------
+
+### 1. Free as in Beer
+
+The provider of this work shall make it available, free of any charge,
+monetary or otherwise, to the consumer, to use without restrictions or
+any kind of supervision.
+
+### 2. Freely taken is freely given
+
+The consumer of this work may redistribute it as well as derived works
+in any way he or she chooses, as long as the work itself and any
+derived work remain Free as in Beer, as per the first clause.
+
+### 3. The Burden of Proof
+
+The provider of this work shall also supply explanations for how the
+work was realized if requested, in the form of source code for example, or
+supply the means to access such explanations.
+
+Every such explanation shall be Free as in Beer, as per the first clause.
diff --git a/definitive-filesystem.cabal b/definitive-filesystem.cabal
new file mode 100644
--- /dev/null
+++ b/definitive-filesystem.cabal
@@ -0,0 +1,23 @@
+-- content information
+name:          definitive-filesystem
+category:      Filesystem
+synopsis:      A library that enable you to interact with the filesystem in a definitive way.
+description:   
+
+-- meta-information
+author:        Marc Coiffier
+maintainer:    marc.coiffier@gmail.com
+version:       1.2
+license:       OtherLicense
+license-file:  LICENSE
+
+-- build information
+build-type:    Simple
+cabal-version: >=1.10
+
+library
+  exposed-modules: IO.Filesystem
+  build-depends: base (== 4.6.*), definitive-base (== 1.2.*), containers (== 0.5.*), deepseq (== 1.3.*), array (== 0.5.*), bytestring (== 0.10.*), vector (== 0.10.*), primitive (== 0.5.*), definitive-reactive (== 1.0.*), clock (== 0.4.*), directory (== 1.2.*), filepath (== 1.3.*), time (== 1.4.*), old-locale (== 1.0.*), unix (== 2.7.*)
+  default-extensions: TypeSynonymInstances NoMonomorphismRestriction StandaloneDeriving GeneralizedNewtypeDeriving TypeOperators RebindableSyntax FlexibleInstances FlexibleContexts FunctionalDependencies TupleSections MultiParamTypeClasses Rank2Types
+  ghc-options: -Wall -fno-warn-orphans -threaded
+  default-language: Haskell2010
