diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -257,6 +257,10 @@
 
 **Warning**: currently if you change your `[markdown]` settings any older files stored with different settings will not be readable.
 
+### Template
+
+You can edit the `template.md` config file to change what a new taskell file looks like.
+
 ### Controls
 
 You can edit keyboard bindings in the `bindings.ini` config file.
diff --git a/src/Taskell/Config.hs b/src/Taskell/Config.hs
--- a/src/Taskell/Config.hs
+++ b/src/Taskell/Config.hs
@@ -4,10 +4,19 @@
 
 import ClassyPrelude
 
-import Data.FileEmbed (embedFile)
+import           Data.FileEmbed             (embedFile)
+import           Data.Version               (showVersion)
+import           Language.Haskell.TH.Syntax (liftString)
+import qualified Paths_taskell              (version)
 
 version :: Text
-version = "1.9.3"
+version = $(liftString $ showVersion Paths_taskell.version)
+
+trelloUsage :: Text
+trelloUsage = decodeUtf8 $(embedFile "templates/trello-token.txt")
+
+githubUsage :: Text
+githubUsage = decodeUtf8 $(embedFile "templates/github-token.txt")
 
 usage :: Text
 usage = decodeUtf8 $(embedFile "templates/usage.txt")
diff --git a/src/Taskell/Data/List.hs b/src/Taskell/Data/List.hs
--- a/src/Taskell/Data/List.hs
+++ b/src/Taskell/Data/List.hs
@@ -1,28 +1,128 @@
-module Taskell.Data.List
-    ( List
-    , Update
-    , title
-    , tasks
-    , create
-    , empty
-    , due
-    , clearDue
-    , new
-    , count
-    , newAt
-    , duplicate
-    , append
-    , prepend
-    , extract
-    , updateFn
-    , update
-    , move
-    , deleteTask
-    , getTask
-    , searchFor
-    , nextTask
-    , prevTask
-    , nearest
-    ) where
+{-# LANGUAGE TemplateHaskell #-}
 
-import Taskell.Data.List.Internal
+module Taskell.Data.List where
+
+import ClassyPrelude
+
+import Control.Lens (element, makeLenses, (%%~), (%~), (&), (.~), (^.), (^?))
+
+import Data.Sequence as S (adjust', deleteAt, insertAt, update, (<|), (|>))
+
+import qualified Taskell.Data.Seq  as S
+import qualified Taskell.Data.Task as T (Task, Update, blank, clearDue, contains, due, duplicate)
+import           Taskell.Types     (TaskIndex (TaskIndex))
+
+data List = List
+    { _title :: Text
+    , _tasks :: Seq T.Task
+    } deriving (Show, Eq)
+
+type Update = List -> List
+
+-- create lenses
+$(makeLenses ''List)
+
+-- operations
+create :: Text -> Seq T.Task -> List
+create = List
+
+empty :: Text -> List
+empty text = List text ClassyPrelude.empty
+
+new :: Update
+new = append T.blank
+
+count :: List -> Int
+count = length . (^. tasks)
+
+due :: List -> Seq (TaskIndex, T.Task)
+due list = catMaybes (filt S.<#> (list ^. tasks))
+  where
+    filt int task = const (TaskIndex int, task) <$> task ^. T.due
+
+clearDue :: TaskIndex -> Update
+clearDue (TaskIndex int) = updateFn int T.clearDue
+
+newAt :: Int -> Update
+newAt idx = tasks %~ S.insertAt idx T.blank
+
+duplicate :: Int -> List -> Maybe List
+duplicate idx list = do
+    task <- T.duplicate <$> getTask idx list
+    pure $ list & tasks %~ S.insertAt idx task
+
+append :: T.Task -> Update
+append task = tasks %~ (S.|> task)
+
+prepend :: T.Task -> Update
+prepend task = tasks %~ (task S.<|)
+
+extract :: Int -> List -> Maybe (List, T.Task)
+extract idx list = do
+    (xs, x) <- S.extract idx (list ^. tasks)
+    pure (list & tasks .~ xs, x)
+
+updateFn :: Int -> T.Update -> Update
+updateFn idx fn = tasks %~ adjust' fn idx
+
+update :: Int -> T.Task -> Update
+update idx task = tasks %~ S.update idx task
+
+move :: Int -> Int -> Maybe Text -> List -> Maybe (List, Int)
+move current dir term list =
+    case term of
+        Nothing -> (, bound list (current + dir)) <$> (list & tasks %%~ S.shiftBy current dir)
+        Just _ -> do
+            idx <- changeTask dir current term list
+            (, idx) <$> (list & tasks %%~ S.shiftBy current (idx - current))
+
+deleteTask :: Int -> Update
+deleteTask idx = tasks %~ deleteAt idx
+
+getTask :: Int -> List -> Maybe T.Task
+getTask idx = (^? tasks . element idx)
+
+searchFor :: Text -> Update
+searchFor text = tasks %~ filter (T.contains text)
+
+changeTask :: Int -> Int -> Maybe Text -> List -> Maybe Int
+changeTask dir current term list = do
+    let next = current + dir
+    tsk <- getTask next list
+    case term of
+        Nothing -> Just next
+        Just trm ->
+            if T.contains trm tsk
+                then Just next
+                else changeTask dir next term list
+
+nextTask :: Int -> Maybe Text -> List -> Int
+nextTask idx text lst = fromMaybe idx $ changeTask 1 idx text lst
+
+prevTask :: Int -> Maybe Text -> List -> Int
+prevTask idx text lst = fromMaybe idx $ changeTask (-1) idx text lst
+
+closest :: Int -> Int -> Int -> Int
+closest current previous next =
+    if (next - current) < (current - previous)
+        then next
+        else previous
+
+bound :: List -> Int -> Int
+bound lst = S.bound (lst ^. tasks)
+
+nearest' :: Int -> Maybe Text -> List -> Maybe Int
+nearest' current term lst = do
+    let prev = changeTask (-1) current term lst
+    let nxt = changeTask 1 current term lst
+    let comp idx = Just $ maybe idx (closest current idx) nxt
+    maybe nxt comp prev
+
+nearest :: Int -> Maybe Text -> List -> Int
+nearest current term lst = idx
+  where
+    near = fromMaybe (-1) $ nearest' current term lst
+    idx =
+        case term of
+            Nothing  -> bound lst current
+            Just txt -> maybe near (bool near current . T.contains txt) $ getTask current lst
diff --git a/src/Taskell/Data/List/Internal.hs b/src/Taskell/Data/List/Internal.hs
deleted file mode 100644
--- a/src/Taskell/Data/List/Internal.hs
+++ /dev/null
@@ -1,128 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module Taskell.Data.List.Internal where
-
-import ClassyPrelude
-
-import Control.Lens (element, makeLenses, (%%~), (%~), (&), (.~), (^.), (^?))
-
-import Data.Sequence as S (adjust', deleteAt, insertAt, update, (<|), (|>))
-
-import qualified Taskell.Data.Seq  as S
-import qualified Taskell.Data.Task as T (Task, Update, blank, clearDue, contains, due, duplicate)
-import           Taskell.Types     (TaskIndex (TaskIndex))
-
-data List = List
-    { _title :: Text
-    , _tasks :: Seq T.Task
-    } deriving (Show, Eq)
-
-type Update = List -> List
-
--- create lenses
-$(makeLenses ''List)
-
--- operations
-create :: Text -> Seq T.Task -> List
-create = List
-
-empty :: Text -> List
-empty text = List text ClassyPrelude.empty
-
-new :: Update
-new = append T.blank
-
-count :: List -> Int
-count = length . (^. tasks)
-
-due :: List -> Seq (TaskIndex, T.Task)
-due list = catMaybes (filt S.<#> (list ^. tasks))
-  where
-    filt int task = const (TaskIndex int, task) <$> task ^. T.due
-
-clearDue :: TaskIndex -> Update
-clearDue (TaskIndex int) = updateFn int T.clearDue
-
-newAt :: Int -> Update
-newAt idx = tasks %~ S.insertAt idx T.blank
-
-duplicate :: Int -> List -> Maybe List
-duplicate idx list = do
-    task <- T.duplicate <$> getTask idx list
-    pure $ list & tasks %~ S.insertAt idx task
-
-append :: T.Task -> Update
-append task = tasks %~ (S.|> task)
-
-prepend :: T.Task -> Update
-prepend task = tasks %~ (task S.<|)
-
-extract :: Int -> List -> Maybe (List, T.Task)
-extract idx list = do
-    (xs, x) <- S.extract idx (list ^. tasks)
-    pure (list & tasks .~ xs, x)
-
-updateFn :: Int -> T.Update -> Update
-updateFn idx fn = tasks %~ adjust' fn idx
-
-update :: Int -> T.Task -> Update
-update idx task = tasks %~ S.update idx task
-
-move :: Int -> Int -> Maybe Text -> List -> Maybe (List, Int)
-move current dir term list =
-    case term of
-        Nothing -> (, bound list (current + dir)) <$> (list & tasks %%~ S.shiftBy current dir)
-        Just _ -> do
-            idx <- changeTask dir current term list
-            (, idx) <$> (list & tasks %%~ S.shiftBy current (idx - current))
-
-deleteTask :: Int -> Update
-deleteTask idx = tasks %~ deleteAt idx
-
-getTask :: Int -> List -> Maybe T.Task
-getTask idx = (^? tasks . element idx)
-
-searchFor :: Text -> Update
-searchFor text = tasks %~ filter (T.contains text)
-
-changeTask :: Int -> Int -> Maybe Text -> List -> Maybe Int
-changeTask dir current term list = do
-    let next = current + dir
-    tsk <- getTask next list
-    case term of
-        Nothing -> Just next
-        Just trm ->
-            if T.contains trm tsk
-                then Just next
-                else changeTask dir next term list
-
-nextTask :: Int -> Maybe Text -> List -> Int
-nextTask idx text lst = fromMaybe idx $ changeTask 1 idx text lst
-
-prevTask :: Int -> Maybe Text -> List -> Int
-prevTask idx text lst = fromMaybe idx $ changeTask (-1) idx text lst
-
-closest :: Int -> Int -> Int -> Int
-closest current previous next =
-    if (next - current) < (current - previous)
-        then next
-        else previous
-
-bound :: List -> Int -> Int
-bound lst = S.bound (lst ^. tasks)
-
-nearest' :: Int -> Maybe Text -> List -> Maybe Int
-nearest' current term lst = do
-    let prev = changeTask (-1) current term lst
-    let nxt = changeTask 1 current term lst
-    let comp idx = Just $ maybe idx (closest current idx) nxt
-    maybe nxt comp prev
-
-nearest :: Int -> Maybe Text -> List -> Int
-nearest current term lst = idx
-  where
-    near = fromMaybe (-1) $ nearest' current term lst
-    idx =
-        case term of
-            Nothing  -> bound lst current
-            Just txt -> maybe near (bool near current . T.contains txt) $ getTask current lst
diff --git a/src/Taskell/Data/Lists.hs b/src/Taskell/Data/Lists.hs
--- a/src/Taskell/Data/Lists.hs
+++ b/src/Taskell/Data/Lists.hs
@@ -1,20 +1,89 @@
-module Taskell.Data.Lists
-    ( Lists
-    , ListPosition(..)
-    , initial
-    , updateLists
-    , count
-    , due
-    , clearDue
-    , get
-    , changeList
-    , newList
-    , delete
-    , exists
-    , shiftBy
-    , search
-    , appendToLast
-    , analyse
-    ) where
+module Taskell.Data.Lists where
 
-import Taskell.Data.Lists.Internal
+import ClassyPrelude
+
+import Control.Lens  ((^.))
+import Data.Sequence as S (adjust', deleteAt, update, (!?), (|>))
+
+import qualified Taskell.Data.List as L (List, Update, append, clearDue, count, due, empty, extract,
+                                         prepend, searchFor)
+import qualified Taskell.Data.Seq  as S
+import qualified Taskell.Data.Task as T (Task, due)
+import           Taskell.Types     (ListIndex (ListIndex), Pointer, TaskIndex (TaskIndex))
+
+type Lists = Seq L.List
+
+type Update = Lists -> Lists
+
+data ListPosition
+    = Top
+    | Bottom
+
+initial :: Lists
+initial = fromList []
+
+updateLists :: Int -> L.List -> Update
+updateLists = S.update
+
+count :: Int -> Lists -> Int
+count idx tasks = maybe 0 L.count (tasks !? idx)
+
+due :: Lists -> Seq (Pointer, T.Task)
+due lists = sortOn ((^. T.due) . snd) dues
+  where
+    format x lst = (\(y, t) -> ((ListIndex x, y), t)) <$> L.due lst
+    dues = concat $ format S.<#> lists
+
+clearDue :: Pointer -> Update
+clearDue (idx, tsk) = updateFn idx (L.clearDue tsk)
+
+updateFn :: ListIndex -> L.Update -> Update
+updateFn (ListIndex idx) fn = adjust' fn idx
+
+get :: Lists -> Int -> Maybe L.List
+get = (!?)
+
+changeList :: ListPosition -> Pointer -> Lists -> Int -> Maybe Lists
+changeList pos (ListIndex list, TaskIndex idx) tasks dir = do
+    let next = list + dir
+    let fn =
+            case pos of
+                Top    -> L.prepend
+                Bottom -> L.append
+    (from, task) <- L.extract idx =<< tasks !? list -- extract current task
+    to <- fn task <$> tasks !? next -- get next list and append task
+    pure . updateLists next to $ updateLists list from tasks -- update lists
+
+newList :: Text -> Update
+newList title = (|> L.empty title)
+
+delete :: Int -> Update
+delete = deleteAt
+
+exists :: Int -> Lists -> Bool
+exists idx tasks = isJust $ tasks !? idx
+
+shiftBy :: Int -> Int -> Lists -> Maybe Lists
+shiftBy = S.shiftBy
+
+search :: Text -> Update
+search text = (L.searchFor text <$>)
+
+appendToLast :: T.Task -> Update
+appendToLast task lists =
+    fromMaybe lists $ do
+        let idx = length lists - 1
+        list <- L.append task <$> lists !? idx
+        pure $ updateLists idx list lists
+
+analyse :: Text -> Lists -> Text
+analyse filepath lists =
+    concat
+        [ filepath
+        , "\n"
+        , "Lists: "
+        , tshow $ length lists
+        , "\n"
+        , "Tasks: "
+        , tshow $ foldl' (+) 0 (L.count <$> lists)
+        ]
diff --git a/src/Taskell/Data/Lists/Internal.hs b/src/Taskell/Data/Lists/Internal.hs
deleted file mode 100644
--- a/src/Taskell/Data/Lists/Internal.hs
+++ /dev/null
@@ -1,89 +0,0 @@
-module Taskell.Data.Lists.Internal where
-
-import ClassyPrelude
-
-import Control.Lens  ((^.))
-import Data.Sequence as S (adjust', deleteAt, update, (!?), (|>))
-
-import qualified Taskell.Data.List as L (List, Update, append, clearDue, count, due, empty, extract,
-                                         prepend, searchFor)
-import qualified Taskell.Data.Seq  as S
-import qualified Taskell.Data.Task as T (Task, due)
-import           Taskell.Types     (ListIndex (ListIndex), Pointer, TaskIndex (TaskIndex))
-
-type Lists = Seq L.List
-
-type Update = Lists -> Lists
-
-data ListPosition
-    = Top
-    | Bottom
-
-initial :: Lists
-initial = fromList [L.empty "To Do", L.empty "Done"]
-
-updateLists :: Int -> L.List -> Update
-updateLists = S.update
-
-count :: Int -> Lists -> Int
-count idx tasks = maybe 0 L.count (tasks !? idx)
-
-due :: Lists -> Seq (Pointer, T.Task)
-due lists = sortOn ((^. T.due) . snd) dues
-  where
-    format x lst = (\(y, t) -> ((ListIndex x, y), t)) <$> L.due lst
-    dues = concat $ format S.<#> lists
-
-clearDue :: Pointer -> Update
-clearDue (idx, tsk) = updateFn idx (L.clearDue tsk)
-
-updateFn :: ListIndex -> L.Update -> Update
-updateFn (ListIndex idx) fn = adjust' fn idx
-
-get :: Lists -> Int -> Maybe L.List
-get = (!?)
-
-changeList :: ListPosition -> Pointer -> Lists -> Int -> Maybe Lists
-changeList pos (ListIndex list, TaskIndex idx) tasks dir = do
-    let next = list + dir
-    let fn =
-            case pos of
-                Top    -> L.prepend
-                Bottom -> L.append
-    (from, task) <- L.extract idx =<< tasks !? list -- extract current task
-    to <- fn task <$> tasks !? next -- get next list and append task
-    pure . updateLists next to $ updateLists list from tasks -- update lists
-
-newList :: Text -> Update
-newList title = (|> L.empty title)
-
-delete :: Int -> Update
-delete = deleteAt
-
-exists :: Int -> Lists -> Bool
-exists idx tasks = isJust $ tasks !? idx
-
-shiftBy :: Int -> Int -> Lists -> Maybe Lists
-shiftBy = S.shiftBy
-
-search :: Text -> Update
-search text = (L.searchFor text <$>)
-
-appendToLast :: T.Task -> Update
-appendToLast task lists =
-    fromMaybe lists $ do
-        let idx = length lists - 1
-        list <- L.append task <$> lists !? idx
-        pure $ updateLists idx list lists
-
-analyse :: Text -> Lists -> Text
-analyse filepath lists =
-    concat
-        [ filepath
-        , "\n"
-        , "Lists: "
-        , tshow $ length lists
-        , "\n"
-        , "Tasks: "
-        , tshow $ foldl' (+) 0 (L.count <$> lists)
-        ]
diff --git a/src/Taskell/Data/Subtask.hs b/src/Taskell/Data/Subtask.hs
--- a/src/Taskell/Data/Subtask.hs
+++ b/src/Taskell/Data/Subtask.hs
@@ -1,12 +1,29 @@
-module Taskell.Data.Subtask
-    ( Subtask
-    , Update
-    , new
-    , blank
-    , name
-    , complete
-    , toggle
-    , duplicate
-    ) where
+{-# LANGUAGE TemplateHaskell #-}
 
-import Taskell.Data.Subtask.Internal
+module Taskell.Data.Subtask where
+
+import ClassyPrelude
+import Control.Lens  (makeLenses, (%~))
+
+data Subtask = Subtask
+    { _name     :: Text
+    , _complete :: Bool
+    } deriving (Show, Eq)
+
+type Update = Subtask -> Subtask
+
+-- create lenses
+$(makeLenses ''Subtask)
+
+-- operations
+blank :: Subtask
+blank = Subtask "" False
+
+new :: Text -> Bool -> Subtask
+new = Subtask
+
+toggle :: Update
+toggle = complete %~ not
+
+duplicate :: Subtask -> Subtask
+duplicate (Subtask n c) = Subtask n c
diff --git a/src/Taskell/Data/Subtask/Internal.hs b/src/Taskell/Data/Subtask/Internal.hs
deleted file mode 100644
--- a/src/Taskell/Data/Subtask/Internal.hs
+++ /dev/null
@@ -1,29 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module Taskell.Data.Subtask.Internal where
-
-import ClassyPrelude
-import Control.Lens  (makeLenses, (%~))
-
-data Subtask = Subtask
-    { _name     :: Text
-    , _complete :: Bool
-    } deriving (Show, Eq)
-
-type Update = Subtask -> Subtask
-
--- create lenses
-$(makeLenses ''Subtask)
-
--- operations
-blank :: Subtask
-blank = Subtask "" False
-
-new :: Text -> Bool -> Subtask
-new = Subtask
-
-toggle :: Update
-toggle = complete %~ not
-
-duplicate :: Subtask -> Subtask
-duplicate (Subtask n c) = Subtask n c
diff --git a/src/Taskell/Data/Task.hs b/src/Taskell/Data/Task.hs
--- a/src/Taskell/Data/Task.hs
+++ b/src/Taskell/Data/Task.hs
@@ -1,27 +1,97 @@
-module Taskell.Data.Task
-    ( Task
-    , Update
-    , name
-    , description
-    , due
-    , subtasks
-    , blank
-    , new
-    , create
-    , duplicate
-    , setDescription
-    , appendDescription
-    , setDue
-    , clearDue
-    , getSubtask
-    , addSubtask
-    , hasSubtasks
-    , updateSubtask
-    , removeSubtask
-    , countSubtasks
-    , countCompleteSubtasks
-    , contains
-    , isBlank
-    ) where
+{-# LANGUAGE TemplateHaskell #-}
 
-import Taskell.Data.Task.Internal
+module Taskell.Data.Task where
+
+import ClassyPrelude
+
+import Control.Lens (ix, makeLenses, (%~), (&), (.~), (?~), (^.), (^?))
+
+import           Data.Sequence        as S (adjust', deleteAt, (|>))
+import           Data.Text            (strip)
+import           Data.Time.Zones      (TZ)
+import           Taskell.Data.Date    (Due (..), inputToTime)
+import qualified Taskell.Data.Subtask as ST (Subtask, Update, complete, duplicate, name)
+
+data Task = Task
+    { _name        :: Text
+    , _description :: Maybe Text
+    , _subtasks    :: Seq ST.Subtask
+    , _due         :: Maybe Due
+    } deriving (Show, Eq)
+
+type Update = Task -> Task
+
+-- create lenses
+$(makeLenses ''Task)
+
+-- operations
+create :: Text -> Maybe Due -> Maybe Text -> Seq ST.Subtask -> Task
+create name' due' description' subtasks' = Task name' description' subtasks' due'
+
+blank :: Task
+blank = Task "" Nothing empty Nothing
+
+new :: Text -> Task
+new text = blank & (name .~ text)
+
+setDescription :: Text -> Update
+setDescription text =
+    description .~
+    if null (strip text)
+        then Nothing
+        else Just text
+
+maybeAppend :: Text -> Maybe Text -> Maybe Text
+maybeAppend text (Just current) = Just (concat [current, "\n", text])
+maybeAppend text Nothing        = Just text
+
+appendDescription :: Text -> Update
+appendDescription text =
+    if null (strip text)
+        then id
+        else description %~ maybeAppend text
+
+setDue :: TZ -> UTCTime -> Text -> Task -> Maybe Task
+setDue tz now date task =
+    if null date
+        then Just (task & due .~ Nothing)
+        else (\d -> task & due ?~ d) <$> inputToTime tz now (strip date)
+
+clearDue :: Update
+clearDue task = task & due .~ Nothing
+
+getSubtask :: Int -> Task -> Maybe ST.Subtask
+getSubtask idx = (^? subtasks . ix idx)
+
+addSubtask :: ST.Subtask -> Update
+addSubtask subtask = subtasks %~ (|> subtask)
+
+hasSubtasks :: Task -> Bool
+hasSubtasks = not . null . (^. subtasks)
+
+updateSubtask :: Int -> ST.Update -> Update
+updateSubtask idx fn = subtasks %~ adjust' fn idx
+
+removeSubtask :: Int -> Update
+removeSubtask idx = subtasks %~ S.deleteAt idx
+
+countSubtasks :: Task -> Int
+countSubtasks = length . (^. subtasks)
+
+countCompleteSubtasks :: Task -> Int
+countCompleteSubtasks = length . filter (^. ST.complete) . (^. subtasks)
+
+contains :: Text -> Task -> Bool
+contains text task =
+    check (task ^. name) || maybe False check (task ^. description) || not (null sts)
+  where
+    check = isInfixOf (toLower text) . toLower
+    sts = filter check $ (^. ST.name) <$> (task ^. subtasks)
+
+isBlank :: Task -> Bool
+isBlank task =
+    null (task ^. name) &&
+    isNothing (task ^. description) && null (task ^. subtasks) && isNothing (task ^. due)
+
+duplicate :: Task -> Task
+duplicate (Task n d st du) = Task n d (ST.duplicate <$> st) du
diff --git a/src/Taskell/Data/Task/Internal.hs b/src/Taskell/Data/Task/Internal.hs
deleted file mode 100644
--- a/src/Taskell/Data/Task/Internal.hs
+++ /dev/null
@@ -1,97 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module Taskell.Data.Task.Internal where
-
-import ClassyPrelude
-
-import Control.Lens (ix, makeLenses, (%~), (&), (.~), (?~), (^.), (^?))
-
-import           Data.Sequence        as S (adjust', deleteAt, (|>))
-import           Data.Text            (strip)
-import           Data.Time.Zones      (TZ)
-import           Taskell.Data.Date    (Due (..), inputToTime)
-import qualified Taskell.Data.Subtask as ST (Subtask, Update, complete, duplicate, name)
-
-data Task = Task
-    { _name        :: Text
-    , _description :: Maybe Text
-    , _subtasks    :: Seq ST.Subtask
-    , _due         :: Maybe Due
-    } deriving (Show, Eq)
-
-type Update = Task -> Task
-
--- create lenses
-$(makeLenses ''Task)
-
--- operations
-create :: Text -> Maybe Due -> Maybe Text -> Seq ST.Subtask -> Task
-create name' due' description' subtasks' = Task name' description' subtasks' due'
-
-blank :: Task
-blank = Task "" Nothing empty Nothing
-
-new :: Text -> Task
-new text = blank & (name .~ text)
-
-setDescription :: Text -> Update
-setDescription text =
-    description .~
-    if null (strip text)
-        then Nothing
-        else Just text
-
-maybeAppend :: Text -> Maybe Text -> Maybe Text
-maybeAppend text (Just current) = Just (concat [current, "\n", text])
-maybeAppend text Nothing        = Just text
-
-appendDescription :: Text -> Update
-appendDescription text =
-    if null (strip text)
-        then id
-        else description %~ maybeAppend text
-
-setDue :: TZ -> UTCTime -> Text -> Task -> Maybe Task
-setDue tz now date task =
-    if null date
-        then Just (task & due .~ Nothing)
-        else (\d -> task & due ?~ d) <$> inputToTime tz now (strip date)
-
-clearDue :: Update
-clearDue task = task & due .~ Nothing
-
-getSubtask :: Int -> Task -> Maybe ST.Subtask
-getSubtask idx = (^? subtasks . ix idx)
-
-addSubtask :: ST.Subtask -> Update
-addSubtask subtask = subtasks %~ (|> subtask)
-
-hasSubtasks :: Task -> Bool
-hasSubtasks = not . null . (^. subtasks)
-
-updateSubtask :: Int -> ST.Update -> Update
-updateSubtask idx fn = subtasks %~ adjust' fn idx
-
-removeSubtask :: Int -> Update
-removeSubtask idx = subtasks %~ S.deleteAt idx
-
-countSubtasks :: Task -> Int
-countSubtasks = length . (^. subtasks)
-
-countCompleteSubtasks :: Task -> Int
-countCompleteSubtasks = length . filter (^. ST.complete) . (^. subtasks)
-
-contains :: Text -> Task -> Bool
-contains text task =
-    check (task ^. name) || maybe False check (task ^. description) || not (null sts)
-  where
-    check = isInfixOf (toLower text) . toLower
-    sts = filter check $ (^. ST.name) <$> (task ^. subtasks)
-
-isBlank :: Task -> Bool
-isBlank task =
-    null (task ^. name) &&
-    isNothing (task ^. description) && null (task ^. subtasks) && isNothing (task ^. due)
-
-duplicate :: Task -> Task
-duplicate (Task n d st du) = Task n d (ST.duplicate <$> st) du
diff --git a/src/Taskell/IO.hs b/src/Taskell/IO.hs
--- a/src/Taskell/IO.hs
+++ b/src/Taskell/IO.hs
@@ -1,20 +1,18 @@
-{-# LANGUAGE TemplateHaskell #-}
-
 module Taskell.IO where
 
 import ClassyPrelude
 
 import Control.Monad.Reader (runReader)
-import Data.FileEmbed       (embedFile)
 import Data.Text.Encoding   (decodeUtf8With)
 import System.Directory     (doesFileExist, getCurrentDirectory)
 
 import Data.Time.Zones (TZ)
 
-import Taskell.Config     (usage, version)
+import Taskell.Config     (githubUsage, trelloUsage, usage, version)
 import Taskell.Data.Lists (Lists, analyse, initial)
 
-import           Taskell.IO.Config         (Config, general, github, markdown, trello)
+import           Taskell.IO.Config         (Config, general, getDir, github, markdown, templatePath,
+                                            trello)
 import           Taskell.IO.Config.General (filename)
 import qualified Taskell.IO.Config.GitHub  as GitHub (token)
 import qualified Taskell.IO.Config.Trello  as Trello (token)
@@ -106,18 +104,10 @@
                     bool (pure Exit) (Load path ls <$ lift (writeData tz config ls path))
 
 createTrello :: Trello.TrelloBoardID -> FilePath -> ReaderConfig Next
-createTrello =
-    createRemote
-        (Trello.token . trello)
-        (decodeUtf8 $(embedFile "templates/trello-token.txt"))
-        Trello.getLists
+createTrello = createRemote (Trello.token . trello) trelloUsage Trello.getLists
 
 createGitHub :: GitHub.GitHubIdentifier -> FilePath -> ReaderConfig Next
-createGitHub =
-    createRemote
-        (GitHub.token . github)
-        (decodeUtf8 $(embedFile "templates/github-token.txt"))
-        GitHub.getLists
+createGitHub = createRemote (GitHub.token . github) githubUsage GitHub.getLists
 
 exists :: Text -> ReaderConfig (Maybe FilePath)
 exists filepath = do
@@ -140,7 +130,9 @@
 createPath path = do
     config <- asks ioConfig
     tz <- asks ioTZ
-    lift (writeData tz config initial path)
+    template <- readData =<< templatePath <$> lift getDir
+    let ls = either (const initial) id template
+    lift (writeData tz config ls path)
 
 -- writes Tasks to json file
 writeData :: TZ -> Config -> Lists -> FilePath -> IO ()
diff --git a/src/Taskell/IO/Config.hs b/src/Taskell/IO/Config.hs
--- a/src/Taskell/IO/Config.hs
+++ b/src/Taskell/IO/Config.hs
@@ -68,6 +68,9 @@
 configPath :: FilePath -> FilePath
 configPath = (</> "config.ini")
 
+templatePath :: FilePath -> FilePath
+templatePath = (</> "template.md")
+
 bindingsPath :: FilePath -> FilePath
 bindingsPath = (</> "bindings.ini")
 
@@ -80,6 +83,7 @@
     -- create config files
     create (configPath dir) $(embedFile "templates/config.ini")
     create (themePath dir) $(embedFile "templates/theme.ini")
+    create (templatePath dir) $(embedFile "templates/template.md")
     create (bindingsPath dir) $(embedFile "templates/bindings.ini")
     -- get config
     getConfig
diff --git a/src/Taskell/IO/Markdown/Parser.hs b/src/Taskell/IO/Markdown/Parser.hs
--- a/src/Taskell/IO/Markdown/Parser.hs
+++ b/src/Taskell/IO/Markdown/Parser.hs
@@ -57,7 +57,7 @@
 listP sym = L.create <$> listTitleP sym <*> (fromList <$> many' (taskP sym))
 
 markdownP :: Symbol -> Parser LS.Lists
-markdownP sym = fromList <$> many1 (listP sym) <* endOfInput
+markdownP sym = fromList <$> many1 (listP sym) <* skipSpace <* endOfInput
 
 -- parse
 parse :: Config -> Text -> Either Text LS.Lists
diff --git a/taskell.cabal b/taskell.cabal
--- a/taskell.cabal
+++ b/taskell.cabal
@@ -1,33 +1,36 @@
-cabal-version: 1.12
-name: taskell
-version: 1.9.3.0
-license: BSD3
-license-file: LICENSE
-copyright: 2019 Mark Wales
-maintainer: mark@smallhadroncollider.com
-author: Mark Wales
-homepage: https://github.com/smallhadroncollider/taskell#readme
-bug-reports: https://github.com/smallhadroncollider/taskell/issues
-synopsis: A command-line kanban board/task manager
+cabal-version:      1.12
+name:               taskell
+version:            1.10.0
+license:            BSD3
+license-file:       LICENSE
+copyright:          2019 Mark Wales
+maintainer:         mark@smallhadroncollider.com
+author:             Mark Wales
+homepage:           https://github.com/smallhadroncollider/taskell#readme
+bug-reports:        https://github.com/smallhadroncollider/taskell/issues
+synopsis:           A command-line kanban board/task manager
 description:
     Please see the README on GitHub at <https://github.com/smallhadroncollider/taskell#readme>
-category: Command Line Tools
-build-type: Simple
+
+category:           Command Line Tools
+build-type:         Simple
 extra-source-files:
     README.md
     templates/api-error.txt
     templates/bindings.ini
     templates/config.ini
     templates/github-token.txt
+    templates/template.md
     templates/theme.ini
     templates/trello-token.txt
     templates/usage.txt
     test/Taskell/IO/data/trello-checklists.json
     test/Taskell/IO/data/trello.json
+    test/Taskell/IO/data/roadmap.md
     test/Taskell/IO/Keyboard/data/bindings.ini
 
 source-repository head
-    type: git
+    type:     git
     location: https://github.com/smallhadroncollider/taskell
 
 library
@@ -39,14 +42,10 @@
         Taskell.Data.Date
         Taskell.Data.Date.RelativeParser
         Taskell.Data.List
-        Taskell.Data.List.Internal
         Taskell.Data.Lists
-        Taskell.Data.Lists.Internal
         Taskell.Data.Seq
         Taskell.Data.Subtask
-        Taskell.Data.Subtask.Internal
         Taskell.Data.Task
-        Taskell.Data.Task.Internal
         Taskell.Events.Actions.Types
         Taskell.Events.State.History
         Taskell.Events.State.Types
@@ -63,7 +62,8 @@
         Taskell.IO.Keyboard.Types
         Taskell.UI.Draw.Field
         Taskell.Types
-    hs-source-dirs: src
+
+    hs-source-dirs:     src
     other-modules:
         Taskell.Config
         Taskell.Data.Date.Types
@@ -109,22 +109,25 @@
         Taskell.UI.Types
         Taskell.Utility.Parser
         Paths_taskell
-    default-language: Haskell2010
-    default-extensions: OverloadedStrings NoImplicitPrelude
-                        TupleSections LambdaCase RankNTypes
+
+    default-language:   Haskell2010
+    default-extensions:
+        OverloadedStrings NoImplicitPrelude TupleSections LambdaCase
+        RankNTypes
+
     build-depends:
-        aeson >=1.4.6.0 && <1.5,
-        attoparsec >=0.13.2.3 && <0.14,
+        aeson >=1.4.7.1 && <1.5,
+        attoparsec >=0.13.2.4 && <0.14,
         base >=4.13.0.0 && <=5,
-        brick ==0.52.*,
+        brick >=0.52.1 && <0.53,
         bytestring >=0.10.10.0 && <0.11,
         classy-prelude >=1.5.0 && <1.6,
         config-ini >=0.2.4.0 && <0.3,
         containers >=0.6.2.1 && <0.7,
-        directory >=1.3.4.0 && <1.4,
-        file-embed >=0.0.11.1 && <0.1,
+        directory >=1.3.6.0 && <1.4,
+        file-embed >=0.0.11.2 && <0.1,
         fold-debounce >=0.2.0.9 && <0.3,
-        http-client >=0.6.4 && <0.7,
+        http-client >=0.6.4.1 && <0.7,
         http-conduit >=2.3.7.3 && <2.4,
         http-types >=0.12.3 && <0.13,
         lens >=4.18.1 && <4.19,
@@ -133,17 +136,18 @@
         text >=1.2.4.0 && <1.3,
         time >=1.9.3 && <1.10,
         tz >=0.1.3.3 && <0.2,
-        vty ==5.26.*
+        vty >=5.28.2 && <5.29
 
 executable taskell
-    main-is: Main.hs
-    hs-source-dirs: app
-    other-modules:
-        Paths_taskell
-    default-language: Haskell2010
-    default-extensions: OverloadedStrings NoImplicitPrelude
-                        TupleSections LambdaCase RankNTypes
-    ghc-options: -threaded -rtsopts -with-rtsopts=-N
+    main-is:            Main.hs
+    hs-source-dirs:     app
+    other-modules:      Paths_taskell
+    default-language:   Haskell2010
+    default-extensions:
+        OverloadedStrings NoImplicitPrelude TupleSections LambdaCase
+        RankNTypes
+
+    ghc-options:        -threaded -rtsopts -with-rtsopts=-N
     build-depends:
         base >=4.13.0.0 && <4.14,
         classy-prelude >=1.5.0 && <1.6,
@@ -151,9 +155,9 @@
         tz >=0.1.3.3 && <0.2
 
 test-suite taskell-test
-    type: exitcode-stdio-1.0
-    main-is: Spec.hs
-    hs-source-dirs: test
+    type:               exitcode-stdio-1.0
+    main-is:            Spec.hs
+    hs-source-dirs:     test
     other-modules:
         Taskell.Data.Date.RelativeParserTest
         Taskell.Data.DateTest
@@ -175,16 +179,19 @@
         Taskell.IO.TrelloTest
         Taskell.UI.FieldTest
         Paths_taskell
-    default-language: Haskell2010
-    default-extensions: OverloadedStrings NoImplicitPrelude
-                        TupleSections LambdaCase RankNTypes
-    ghc-options: -threaded -rtsopts -with-rtsopts=-N
+
+    default-language:   Haskell2010
+    default-extensions:
+        OverloadedStrings NoImplicitPrelude TupleSections LambdaCase
+        RankNTypes
+
+    ghc-options:        -threaded -rtsopts -with-rtsopts=-N
     build-depends:
-        aeson >=1.4.6.0 && <1.5,
+        aeson >=1.4.7.1 && <1.5,
         base >=4.13.0.0 && <4.14,
         classy-prelude >=1.5.0 && <1.6,
         containers >=0.6.2.1 && <0.7,
-        file-embed >=0.0.11.1 && <0.1,
+        file-embed >=0.0.11.2 && <0.1,
         lens >=4.18.1 && <4.19,
         mtl >=2.2.2 && <2.3,
         raw-strings-qq ==1.1.*,
@@ -196,4 +203,4 @@
         text >=1.2.4.0 && <1.3,
         time >=1.9.3 && <1.10,
         tz >=0.1.3.3 && <0.2,
-        vty ==5.26.*
+        vty >=5.28.2 && <5.29
diff --git a/templates/template.md b/templates/template.md
new file mode 100644
--- /dev/null
+++ b/templates/template.md
@@ -0,0 +1,8 @@
+## To Do
+
+
+## Doing
+
+
+## Done
+
diff --git a/test/Taskell/Data/ListNavigationTest.hs b/test/Taskell/Data/ListNavigationTest.hs
--- a/test/Taskell/Data/ListNavigationTest.hs
+++ b/test/Taskell/Data/ListNavigationTest.hs
@@ -7,8 +7,8 @@
 import Test.Tasty
 import Test.Tasty.HUnit
 
-import           Taskell.Data.List.Internal as L
-import qualified Taskell.Data.Task          as T (Task, new)
+import           Taskell.Data.List as L
+import qualified Taskell.Data.Task as T (Task, new)
 
 taskSeq :: Seq T.Task
 taskSeq =
diff --git a/test/Taskell/Data/ListTest.hs b/test/Taskell/Data/ListTest.hs
--- a/test/Taskell/Data/ListTest.hs
+++ b/test/Taskell/Data/ListTest.hs
@@ -9,8 +9,8 @@
 import Test.Tasty
 import Test.Tasty.HUnit
 
-import           Taskell.Data.List.Internal as L
-import qualified Taskell.Data.Task          as T (Task, blank, name, new)
+import           Taskell.Data.List as L
+import qualified Taskell.Data.Task as T (Task, blank, name, new)
 
 emptyList :: List
 emptyList = L.empty "Test"
diff --git a/test/Taskell/Data/ListsTest.hs b/test/Taskell/Data/ListsTest.hs
--- a/test/Taskell/Data/ListsTest.hs
+++ b/test/Taskell/Data/ListsTest.hs
@@ -9,11 +9,11 @@
 
 import Control.Lens ((.~))
 
-import           Taskell.Data.Date           (textToTime)
-import qualified Taskell.Data.List           as L
-import           Taskell.Data.Lists.Internal
-import qualified Taskell.Data.Task           as T
-import           Taskell.Types               (ListIndex (ListIndex), TaskIndex (TaskIndex))
+import           Taskell.Data.Date  (textToTime)
+import qualified Taskell.Data.List  as L
+import           Taskell.Data.Lists
+import qualified Taskell.Data.Task  as T
+import           Taskell.Types      (ListIndex (ListIndex), TaskIndex (TaskIndex))
 
 -- test data
 list1, list2, list3 :: L.List
@@ -43,12 +43,7 @@
 test_lists =
     testGroup
         "Data.Taskell.Lists"
-        [ testCase
-              "initial"
-              (assertEqual
-                   "Returns To Do and Done lists"
-                   (fromList [L.empty "To Do", L.empty "Done"])
-                   initial)
+        [ testCase "initial" (assertEqual "Returns empty" (fromList []) initial)
         , testCase
               "updateLists"
               (assertEqual
diff --git a/test/Taskell/Data/SubtaskTest.hs b/test/Taskell/Data/SubtaskTest.hs
--- a/test/Taskell/Data/SubtaskTest.hs
+++ b/test/Taskell/Data/SubtaskTest.hs
@@ -7,7 +7,7 @@
 import Test.Tasty
 import Test.Tasty.HUnit
 
-import Taskell.Data.Subtask.Internal
+import Taskell.Data.Subtask
 
 -- tests
 test_subtask :: TestTree
diff --git a/test/Taskell/Data/TaskTest.hs b/test/Taskell/Data/TaskTest.hs
--- a/test/Taskell/Data/TaskTest.hs
+++ b/test/Taskell/Data/TaskTest.hs
@@ -11,9 +11,9 @@
 
 import Data.Time.Calendar (fromGregorianValid)
 
-import           Taskell.Data.Date          (Due (DueDate))
-import qualified Taskell.Data.Subtask       as ST (name, new)
-import           Taskell.Data.Task.Internal
+import           Taskell.Data.Date    (Due (DueDate))
+import qualified Taskell.Data.Subtask as ST (name, new)
+import           Taskell.Data.Task
 
 desc :: Maybe Text
 desc = Just "A very boring description"
diff --git a/test/Taskell/IO/KeyboardTest.hs b/test/Taskell/IO/KeyboardTest.hs
--- a/test/Taskell/IO/KeyboardTest.hs
+++ b/test/Taskell/IO/KeyboardTest.hs
@@ -15,7 +15,7 @@
 import Data.Time.Zones (utcTZ)
 
 import Graphics.Vty.Input.Events       (Event (..), Key (..))
-import Taskell.Data.Lists.Internal     (initial)
+import Taskell.Data.Lists              (initial)
 import Taskell.Events.Actions.Types    as A
 import Taskell.Events.State            (create, quit)
 import Taskell.Events.State.Types      (State, Stateful, mode)
diff --git a/test/Taskell/IO/Markdown/ParserTest.hs b/test/Taskell/IO/Markdown/ParserTest.hs
--- a/test/Taskell/IO/Markdown/ParserTest.hs
+++ b/test/Taskell/IO/Markdown/ParserTest.hs
@@ -134,6 +134,12 @@
                          "List item with Sub-Task"
                          (Right (makeSubTask "Blah" True))
                          (parse defaultConfig "## Test\n\n- Test Item\n    * [x] Blah"))
+              , testCase
+                    "Line break at end"
+                    (assertEqual
+                         "List item"
+                         (Right listWithItem)
+                         (parse defaultConfig "## Test\n\n- Test Item\n\n"))
               ]
         , testGroup
               "Alternative Format"
diff --git a/test/Taskell/IO/data/roadmap.md b/test/Taskell/IO/data/roadmap.md
new file mode 100644
--- /dev/null
+++ b/test/Taskell/IO/data/roadmap.md
@@ -0,0 +1,361 @@
+## Misc.
+
+- Add more information to taskell.app
+    > Update taskell.app to have more than just README.md contents. Use cases, more images, examples, etc.
+    * [ ] Use case example: checklist
+    * [ ] Use case example: Git controlled tasks
+    * [ ] Blog posts for updates
+- Add to Flatpack
+    > https://opensource.com/article/19/10/how-build-flatpak-packaging
+
+## Refactoring
+
+- 乤乭 乤亍 乤乭乫 乤乭亍乫 乤乭 乤乭亍
+- Refactor Task `Update` to be `Task -> Maybe Task`?
+- Use Attoparsec for parsing
+- Add tests for Taskell.IO.GitHub
+- Break up State module
+    * [ ] More of logic should go into Task, List, and Lists
+- Parse checkItems Trello JSON using Aeson FromJSON rather than needing extra record type
+- Remove duplication of config - currently using ini and hard-coded defaults
+- Use Shake instead of bash script
+
+## Bugs
+
+- Empty subtasks create "---" task
+    > Feel like I added this for some reason, can't think why...
+- Pressing Esc while editing a task should go back to previous version?
+- Selected item can still get a bit lost in SEARCH mode when going between lists
+    > Sometimes defaults to 0, when there is something to be found
+- Very long words should get hyphenated
+    > The cursor gets lost if a word is longer than the line - URLs in particular can cause issues
+- Help modal needs to wrap and scroll
+- Limit modal height based on content
+- Multiple spaces in a line don't show up as more than one, but are saved as more than one
+- Task description should be visible by default in task detail
+    > Visibility should be on the description by default?
+- No obvious way to know if there are more items in a list off-screen
+    > Lowest item should be "..." if more items
+- Blank trello token should show info about setting it up rather than auth error
+    > Auth error should show setup info too?
+- A single issue with config.ini reverts to defaultConfig?
+
+## Features
+
+- Add Cabal test to build process
+    > Use `stack sdist .` to generate cabal file
+- Define key binding info in one place
+    > Currently all over the place
+    * [ ] Bindings
+    * [ ] Default key
+    * [ ] Description
+    * [ ] Generate bindings.ini from it
+- Somehow merge `event` and `events` in Actions that use bindings
+    > Can one event trigger multiple separate state changes?
+- Some way to just see tasks with due dates
+    * [x] Sort by date
+    * [x] Scrollable
+    * [x] Pressing Enter on one takes you to it
+    * [x] Use renderTask from Draw
+    * [ ] Filter by: overdue, this week, later
+    * [ ] Number of due items in status bar?
+    * [x] Descriptions need to wrap
+    * [ ] Search should filter
+    * [ ] Show list each task belongs to?
+    * [x] Backspace (customisable) removes date
+- Configuration options
+    > See #54
+    * [ ] Padding
+    * [ ] Move to top of list - different key binding?
+    * [ ] Show toggle bar
+- Edit task text in DETAIL mode
+    > Need to be able to select different parts of the DETAIL modal. Probably need to rethink Mode constructors.
+- Pressing Undo in DUE mode should undo without leaving view
+    > Fallthrough to NORMAL events more generally? Might require rethinking modes to separate behaviour and things being tracked?
+- Add a List widget for common actions between tasks and sub-tasks
+    > Or use a typeclass... somehow?
+    * [ ] Moving around
+    * [ ] Re-ordering subtasks
+    * [ ] New items above/below
+    * [ ] Duplicating
+    * [ ] Marking complete
+    * [ ] Deleting
+- Add custom key support
+    * [x] Create bindings.ini
+    * [x] Update events to use Map from bindings.ini
+    * [ ] Check for key conflicts: include keys not explicitly mapped (e.g. 1-9, Esc, Enter)
+    * [x] Check for bits of functionality missing a mapping
+    * [x] Update Help dialogue with key mappings
+    * [x] Needs to support merging with default options so that it's easy to add new default keys in the future
+    * [ ] Add keys to Help which aren't in bindings
+    * [ ] More detailed error messages for missing/invalid mappings
+- Add tags/labels with `t`
+    * [ ] Way to filter by tag
+    * [ ] Hide/show tags with key press
+- Performance with large files
+    > Becomes unusable with large files
+    * [x] Initially use debouncing to avoid writing too often
+    * [ ] Cache formatting results
+    * [ ] Invalidate layout cache less frequently
+    * [ ] Benchmarking tests
+    * [ ] Allow cancelling write to avoid trying to write the same file at the same time
+- Should be able to have new-lines in task descriptions
+    * [x] Trello import
+    * [ ] Regular input (Shift + Enter for new line?)
+    * [x] Markdown parsing
+    * [ ] Text line breaks go a bit funny with multi-line descriptions
+- Always show list title
+    > Floating list titles - so you can always see what list you're in
+- Make token UX better
+    * [ ] Open link automatically?
+    * [ ] Ask for token and save to ini file automatically
+- URL field - plus config to run specific command when selected (e.g. `open -a Chrome.app #{url}`)
+- Import Issues from GitHub using  labels
+- Readline support?
+    > Using Haskline: https://rootmos.github.io/main/2017/08/31/combining-brick-and-haskeline.html
+- Editable title?
+    > Use a `# Title` at top of file and display title somewhere in taskell
+- Keep undo between sessions?
+- Ability to load a taskell file with custom config.ini settings
+    > Either command line arguments for settings or just a `-c other.ini` command
+- Inifinite task depth?
+    > No reason, other than UX, that sub-tasks can't have sub-tasks.
+- Add Trello syncing
+
+## In Progress
+
+- Relative dates days and weeks shouldn't include time?
+- Show remaining time on near dates
+
+## Done
+
+- `a` to add
+- `e` to edit
+- `Space` to mark complete
+- `j`/`k`/`up`/`down` to move up/down list
+- `h`/`l`/`Left`/`Right` to move between lists
+- `q` to quit
+- Create taskell.json if doesn't exist
+- Move tasks up/down
+- Delete with `D`
+- No padding on lists
+- Order of lists is wrong
+- Can't switch lists
+- Add doesn't go to bottom of list
+- foldr1 in UI/Main will break if no lists
+- Cursor support
+- Move tasks between lists with `H`/`K`
+- Move to next list with `Space`
+- Create new list with `N`
+- Delete lists with `X`
+- Enter while in add mode creates new/Esc leaves add mode
+- Rename Tasks to List
+- Rename AllTasks to Lists
+- Horizontal scrolling
+- Scrolling long lists
+- If no lists crashes on up/down - using index in AllTasks
+- State should return Maybe?
+- Select lists with `1-9`
+- Run with any correctly formatted json file
+- Wrap lines
+- UI modules need refactoring
+- Horizontal scrolling stops working if a word longer than the column width is entered
+- Cursor no longer in the right place
+- Space in edit/add mode doesn't move cursor along - bit disconcerting
+- If no items in current list, returns a Nothing, so everything dissappears
+- CreateList mode doesn't display anything
+- Cursor doesn't show on CreateList mode
+- Reordering lists with `>` and `<`
+- `o` to add on line below
+- `O` to add on line above
+- `G` take to bottom of file
+- Undo with `u`
+- Should only save after adding a new item or finished editing an item - should save when pressing Enter while adding new items
+- `C` to change task - i.e. deletes text and goes into edit mode
+- Space moves to next and stays in list / H & L move but keep current
+- Cursor position assumes single line list title
+- `E` edits list title
+- Pressing enter on Edit creates new task
+- Reordering leftmost list left takes you to last list
+- Linux binary
+- Homebrew support
+- Tabs in tasks throw off cursor and wrapping
+- Cursor vertical offset is wrong when adding a new list
+- Search using `/`
+- Change foldl to foldl`
+- Debian package
+- Empty tasks aren't obviously selectable
+- Pressing `e` on a blank list breaks things
+- Add support for Markdown
+- Fixed Unicode support
+- Scrolling
+- New list outside view doesn't scroll
+- New item outside view doesn't scroll
+- Vertical scrolling falls behind
+- Use concurrency for IO
+- Search UI
+- Vertical scrolling hides list titles
+- Use Brick for UI
+- `C` doesn't work properly
+- Custom colours
+- `.taskell` config file in home directory
+- Rename Persistence to Taskell.IO
+- List titles sometimes go missing
+- Use Template Haskell to import in config file templates
+- On `?` show keyboard commands
+- Remove size from state
+- Sub-lists
+    * [x] Scrolling in sub-tasks
+    * [x] Press Enter to create next
+    * [x] Word wrapping
+    * [x] Searching
+    * [x] Delete items
+- No cursor in sub-task view
+    * [x] Single line
+    * [x] Multi-line
+- Customisable Markdown format
+    * [x] Change top level headers
+    * [x] Change top level list item: e.g. to H3 instead of li
+    * [x] Change sub-list: e.g. from "    *" to "-"
+- Feels sluggish in sub-task view - cache main view?
+- Leaving search only refreshes current list
+- Display a warning if any line of the file could not be parsed - otherwise could lead to data loss
+- One bad config line stops all config from working - needs to merge with defaultConfig
+- Split up Draw/Modal code into more logical chunks
+- Move between lists with `m` - shows possible lists
+- Caching issue when using `m` to move lists - doesn't update previous list
+- Copy and paste?
+- Pressing Enter on empty list shows an subtasks box with an error
+- Cursor goes missing on the left hand side at the end of a line - needs to wrap
+- Sub-task count not visible on last item in a list longer than the vertical height
+- Vertical spacing doesn't work if the current item is blank
+- Empty tasks - i.e. just a space - don't show up
+- Editing list title doesn't always have visibility
+- Left/Right arrow keys in insert mode
+- Share code between tasks and sub-tasks lists?
+    * [x] Move wrap into Field widget
+    * [x] Use Field for search
+    * [x] Use Field for sub-tasks
+    * [x] Use Field for titles
+    * [x] Use Field for tasks
+    * [x] Make sure `C` works
+- Copy and paste
+    * [x] List titles
+    * [x] Search
+- Multiple spaces at the beginning of a line can break cursor positioning
+- Task body - e.g. as well as sub lists, have a longer description
+- Indicator for when a task has a description
+    > Use ≡?
+- Pressing `Esc` when entering task description shouldn't reset it
+- Better Trello import errors - e.g. auth vs. parsing issues
+    * [x] Error on parse issues
+    * [x] Error on Auth issues
+- Add due dates to tasks with `@`
+    * [x] Render due dates
+    * [x] Editable due dates
+- Trello dates need to take current timezone into account
+    > Trello gives dates in UTC, but need to display them in the current timezone. Deadlines should also take timezones into account if necessary.
+- Move to column only works for columns before the one you're in
+- Add Trello import
+    * [x] Basic trello import
+    * [x] Add due date support
+    * [x] Add sub-tasks support
+    * [x] Add card summary support
+- Improve Trello checklist import
+    * [x] Take checklist fetch errors into account
+    * [x] Refactor code
+    * [x] Use Reader to pass around trello token?
+- Should change list numbering to letters when in move list mode
+- GitHub checklist support - []/[x]
+- Caching doesn't clear properly when using `o` and `O`
+- Add description status indicator option to config.ini
+    > Part of the themeing should allow changing to different icon - might not work in all fonts
+- Add Twitter links
+    * [x] Website
+    * [x] Github
+- Move image to taskell.app
+    > The demo image should live on the taskell.app server, rather than being on an orphan branch on GitHub
+    * [x] Move image
+    * [x] Update site
+    * [x] Update GitHub README.md
+    * [x] Remove img branch
+- Sort out Homebrew forumula
+    > Make the necessary changes so that taskell can be put on the homebrew-core repository
+    * [x] Find someone to submit it
+    * [x] Use `install_cabal_package`
+    * [x] Use `depends_on "cabal-install" => :build`
+- Update Task field naming
+    * [x] Task: description -> name/title
+    * [x] Task: summary -> description
+    * [x] Taskell.UI.Modal.SubTasks -> Taskell.UI.Modal.Detail
+- The isBlank check on tasks could potentially delete a task with no description but which does have sub-tasks
+- Blank task names should appear as something
+- Use lenses for nested data
+- Add more tests
+    * [x] Trello response parsing
+- Add GitHub Project support
+- Refactor Taskell.IO
+    > Avoid repeating basically the same code for Trello and GitHub fetching
+- Add ability to list GitHub projects
+    > Give an organisation or username and repo, list the possible projects to fetch - avoid having to look up the project ID manually first
+- GitHub import should take pagination into account
+- Use XDG spec for storing config files
+- Automate website publishing when doing a new build
+    > Should automatically update the `_config.yml` file, build the website, then deploy it
+- Can't remove a description
+- Title bar for extra info
+    * [x] File path
+    * [x] Current position
+- Search should be case insensitive
+- Add Mode to status bar
+- Modals interfere with status bar
+- Showing a specific task in search mode shows wrong task
+    > Based on the index in the full list, rather than the filtered one. So will show the task from the full list if the indexes don't happen to match.
+- Can't remove dates
+- Tidy up load functions in Taskell.IO
+- Getting stuck in INSERT mode when blank item
+- If an item isn't created, then selection gets lost
+- Search navigation issues
+    > Issues with navigation when in NORMAL + SEARCH mode
+    * [x] Navigating up and down
+    * [x] Navigating between lists
+    * [x] Moving task up and down
+    * [x] Often nothing is selected when first entering search mode
+- Duplicate task with `+`
+- Use Reader throughout Draw/Modal modules
+- Simplify DrawState
+    * [x] Bindings
+    * [x] Today
+    * [x] Normalised State
+    * [x] Layout
+- Add a debug option
+    * [x] Shows full Mode print out
+- Add a "complete" action
+    > Moves to last column and removes date. Space bar by default.
+- Remove `~` style sub-task complete parsing
+- MoveTo shouldn't show if nothing selected
+- Deleting a list can screw up current position
+- Remove date
+    * [x] NORMAL mode
+    * [x] DETAIL mode
+    * [x] DUE mode
+- Update screenshot
+- Date should update if taskell is left open
+- Use proper error codes
+- Redo functionality
+- Modifier keys?
+- Use relative times for due dates
+    > e.g. 1w, 2d, 1w 2d (see `man sleep` options for ideas)
+    * [x] Markdown input
+    * [x] Markdown output
+    * [x] Markdown needs to use actual timezone
+    * [x] Need to use parser
+    * [x] Trello time parsing
+- Use ReaderConfig in Taskell.IO.Markdown.Internal stringify functions
+- Add test for subtask linebreaks to MarkdownTest
+- Config option to always use UTC for markdown output
+- Check times work no matter what timezone
+- Show time on short dates
+- Date validation
+- Check order of due items
+- Trim spaces for date input
