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/biocore.cabal b/biocore.cabal
new file mode 100644
--- /dev/null
+++ b/biocore.cabal
@@ -0,0 +1,24 @@
+Name:      biocore
+Version:   0.1
+License:   LGPL
+
+Cabal-Version:       >= 1.6
+Author:              Ketil Malde
+Maintainer:          ketil@malde.org
+
+Category:            Bioinformatics
+Synopsis:            A bioinformatics library
+Description:	     A set of core definitions and data structures
+		     commonly used in bioinformatics.  The intention is that bioinformatics
+		     libraries will use this as a common ground to avoid needless incompatibilities
+		     and duplicated work.
+-- Homepage:
+Tested-With:         GHC==6.12.3
+Build-Type:          Simple
+-- Data-Files:
+
+Library
+  Build-Depends:     base >= 3 && < 5, bytestring
+  Exposed-Modules:   Bio.Core, Bio.Core.Sequence, Bio.Core.Strand
+  Ghc-Options:       -Wall
+  Hs-Source-Dirs:    src
diff --git a/src/Bio/Core.hs b/src/Bio/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/Bio/Core.hs
@@ -0,0 +1,7 @@
+{-| Re-exporting everything from sub-modules for simplicity -}
+
+module Bio.Core ( module Bio.Core.Sequence
+                , module Bio.Core.Strand ) where
+
+import Bio.Core.Sequence
+import Bio.Core.Strand
diff --git a/src/Bio/Core/Sequence.hs b/src/Bio/Core/Sequence.hs
new file mode 100644
--- /dev/null
+++ b/src/Bio/Core/Sequence.hs
@@ -0,0 +1,81 @@
+{-| This module defines common data structures for biosequences,
+    i.e. data that represents nucleotide or protein sequences.
+
+    Basically, anything resembling or wrapping a sequence should
+    implement the 'BioSeq' class (and 'BioSeqQual' if quality information
+    is available).
+
+    The data types are mostly wrappers from lazy bytestrings from
+    'Data.ByteString.Lazy' and 'Data.ByteString.Lazy.Char8'.
+-}
+
+{-# Language GeneralizedNewtypeDeriving #-}
+
+module Bio.Core.Sequence (
+  -- * Data definitions
+  Qual (..), Offset (..),
+  SeqData (..), SeqLabel (..), QualData (..),
+
+  -- * Class definitions
+  BioSeq (..), BioSeqQual (..),
+
+  -- * Helper functions
+  toFasta, toFastaQual, toFastQ
+  ) where
+
+import qualified Data.ByteString.Lazy.Char8 as LC
+import qualified Data.ByteString.Lazy as L
+import Data.Int
+import Data.Word
+import Data.String
+
+-- | Sequence data are lazy bytestrings of ASCII characters.
+newtype SeqData  = SeqData { unSD :: LC.ByteString } deriving (Eq,Ord,IsString)
+
+-- | Sequence data are lazy bytestrings of ASCII characters.
+newtype SeqLabel = SeqLabel { unSL :: LC.ByteString } deriving (Eq,Ord,IsString)
+
+-- | A quality value is in the range 0..255.
+newtype Qual     = Qual { unQual :: Word8 } deriving (Show,Eq,Ord,Num)
+
+-- | Quality data are lazy bytestrings of 'Qual's.
+newtype QualData = QualData { unQD :: L.ByteString } deriving (Eq,Ord)
+
+-- | An 'Offset' is a zero-based index into a sequence
+newtype Offset   = Offset { unOff :: Int64 } deriving (Show,Eq,Ord,Num)
+
+-- | The 'BioSeq' class models sequence data, and any data object that
+--   represents a biological sequence should implement it.
+class BioSeq s where
+  seqlabel  :: s -> SeqLabel
+  seqdata   :: s -> SeqData
+  seqlength :: s -> Offset
+
+-- | Any 'BioSeq' can be formatted as Fasta, 60-char lines.
+toFasta :: BioSeq s => s -> LC.ByteString -- any kind of string-like data type?  Use builder?
+toFasta s = LC.concat (gt:unSL (seqlabel s):nl:wrap (unSD $ seqdata s))
+  where wrap x = if LC.null x then [] else let (ln,rest) = LC.splitAt 60 x in ln : nl : wrap rest
+        nl = LC.pack "\n"
+        gt = LC.pack ">"
+                                         
+-- | The BioSeqQual class extends BioSeq with quality data.  Any correspondig data object
+--   should be an instance, this will allow Fasta formatted quality data 'toFastaQual', as
+--   well as the combined FastQ format (via 'toFastQ').
+class BioSeq sq => BioSeqQual sq where
+  seqqual  :: sq -> QualData
+
+-- | Output Fasta-formatted quality data (.qual files), where quality values are output as 
+--   whitespace-separated integers.
+toFastaQual :: BioSeqQual s => s -> LC.ByteString
+toFastaQual s = LC.concat (gt:unSL (seqlabel s):nl:wrap (L.unpack $ unQD $ seqqual s))
+  where wrap x = if null x then [] else let (ln,rest) = splitAt 20 x in LC.pack (unwords $ map show ln) : nl : wrap rest
+        nl = LC.pack "\n"
+        gt = LC.pack ">"
+
+-- | Output FastQ-formatted data.  For simplicity, only the Sanger quality format is supported,
+--   and only four lines per sequence (i.e. no line breaks in sequence or quality data).
+toFastQ :: BioSeqQual s => s -> LC.ByteString
+toFastQ s = LC.unlines [LC.cons '@' (unSL $ seqlabel s)
+                       , unSD (seqdata s)
+                       , LC.cons '+' (unSL $ seqlabel s)
+                       , L.map (+33) (unQD $ seqqual s)]
diff --git a/src/Bio/Core/Strand.hs b/src/Bio/Core/Strand.hs
new file mode 100644
--- /dev/null
+++ b/src/Bio/Core/Strand.hs
@@ -0,0 +1,6 @@
+{-| Define common data types for features of sequences -}
+
+module Bio.Core.Strand (Strand(..)) where
+
+-- | A 'Strand' is either plus (forward) or minus (reverse or reverse-complement)
+data Strand = Plus | Minus deriving (Eq,Ord,Read,Show)
