diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2015, Bryan St. Amour
+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 weather nor the names of its
+  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 HOLDER 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.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+# weather
+Haskell library for working with the Weather Underground JSON API.
+
+Currently only supports querying for conditions for US-based cities.
+
+Example usage:
+
+```haskell
+{-# LANGUAGE RecordWildCards #-}
+
+module Main where
+
+import Web.Weather
+
+mykey :: APIKey
+mykey   = "top-secret"
+
+mycity, mystate :: String
+mycity  = "Detroit"
+mystate = "MI"
+
+main :: IO ()
+main = do
+  resp <- getConditions mykey mycity mystate
+  case resp of
+   Nothing -> putStrLn "No data for that city/state"
+   Just (Observation{..}) -> do
+     putStrLn $ "Observation time: " ++ obsTime
+     putStrLn $ "Weather conditions: " ++ obsWeather
+     putStrLn $ "Temp: " ++ show obsTemp
+     putStrLn $ "Rel humidity: " ++ show obsRelHumidity
+     putStrLn $ "Wind: " ++ obsWind
+     putStrLn $ "Feels like: " ++ obsFeelsLike
+```
+
+Output:
+
+```
+Observation time: Last Updated on April 10, 2:09 PM EDT
+Weather conditions: Partly Cloudy
+Temp: 52.9
+Rel humidity: "60%"
+Wind: From the West at 4.7 MPH
+Feels like: 52.9 F (11.6 C)
+```
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/Weather.cabal b/Weather.cabal
new file mode 100644
--- /dev/null
+++ b/Weather.cabal
@@ -0,0 +1,30 @@
+-- Initial weather.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                Weather
+version:             0.1.0.0
+synopsis:            Library for interacting with the Weather Underground JSON API.
+description: Weather is a simple library for interacting with the Weather Underground JSON API. It is not complete, but it may be useful still.
+homepage:            http://bryanstamour.com
+license:             BSD3
+license-file:        LICENSE
+author:              Bryan St. Amour
+maintainer:          bryan@bryanstamour.com
+-- copyright:
+category:            Web
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Web.Weather
+  -- other-modules:
+  -- other-extensions:
+  build-depends: base >= 4.7.0.2 && < 5
+               , HTTP >= 4000.2.12
+               , text >= 1.1.0.1
+               , unordered-containers >= 0.2.5.1
+               , aeson >= 0.8.0.2
+               , bytestring >= 0.10.4.0
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/Weather.cabal~ b/Weather.cabal~
new file mode 100644
--- /dev/null
+++ b/Weather.cabal~
@@ -0,0 +1,31 @@
+-- Initial weather.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                Weather
+version:             0.1.0.0
+synopsis:            Library for interacting with the Weather Underground JSON API.
+description: Weather is a simple library for interacting with the Weather Underground \
+JSON API. It is not complete, but it may be useful still.
+homepage:            http://bryanstamour.com
+license:             BSD3
+license-file:        LICENSE
+author:              Bryan St. Amour
+maintainer:          bryan@bryanstamour.com
+-- copyright:
+category:            Web
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Web.Weather
+  -- other-modules:
+  -- other-extensions:
+  build-depends: base >= 4.7.0.2 && < 5
+               , HTTP >= 4000.2.12
+               , text >= 1.1.0.1
+               , unordered-containers >= 0.2.5.1
+               , aeson >= 0.8.0.2
+               , bytestring >= 0.10.4.0
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/Web/Weather.hs b/src/Web/Weather.hs
new file mode 100644
--- /dev/null
+++ b/src/Web/Weather.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Web.Weather
+       ( Observation(..)
+       , APIKey
+       , getConditions
+       ) where
+
+import Control.Monad
+import Control.Applicative
+
+import Data.Text (Text)
+import Data.Aeson
+import Data.ByteString.Lazy.Char8 (pack)
+import Network.HTTP (getResponseBody, simpleHTTP, getRequest)
+
+import qualified Data.HashMap.Strict as H
+
+-- | Observation data.
+data Observation =
+  Observation { obsTime        :: String  -- ^ The time the observation was taken.
+              , obsWeather     :: String  -- ^ Description of the weather.
+              , obsTemp        :: Float   -- ^ Temperature (F).
+              , obsRelHumidity :: String  -- ^ Relative humidity (%).
+              , obsWind        :: String  -- ^ Wind condition.
+              , obsFeelsLike   :: String  -- ^ What it feels like.
+              } deriving (Show)
+
+instance FromJSON Observation where
+  parseJSON (Object v) = Observation
+                         <$> v .: "observation_time"
+                         <*> v .: "weather"
+                         <*> v .: "temp_f"
+                         <*> v .: "relative_humidity"
+                         <*> v .: "wind_string"
+                         <*> v .: "feelslike_string"
+  parseJSON _          = mzero
+
+-- | API key. Obtain yours at http://wunderground.com.
+type APIKey = String
+
+-- | Get the current weather conditions of a city.
+getConditions :: APIKey -> String -> String -> IO (Maybe Observation)
+getConditions key city state = do
+  obj <- evalJSONRequest $ conditionsQuery key city state
+  return $ obj >>= getProperty "current_observation"
+
+-- Fetch a property from a JSON object.
+getProperty :: FromJSON a => Text -> Value -> Maybe a
+getProperty property (Object v) = do
+  val <- H.lookup property v
+  case fromJSON val of
+   Error _   -> Nothing
+   Success x -> Just x
+getProperty _ _                 = Nothing
+
+-- Evaluate a JSON request and return the parsed object.
+evalJSONRequest :: FromJSON a => String -> IO (Maybe a)
+evalJSONRequest request = do
+  body <- getResponseBody <=< simpleHTTP $ getRequest request
+  return . decode $ pack body
+
+-- The query used to get weather conditions.
+conditionsQuery :: String -> String -> String -> String
+conditionsQuery key city state =
+  "http://api.wunderground.com/api/" ++ key
+  ++ "/conditions/q/" ++ state
+  ++ "/" ++ city ++ ".json"
