diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,23 @@
+0.0.6
+
+* Add BOM Graphical Area Forecast (GAF) endpoints
+  * `/gaf/<area>/current` and `/gaf/<area>/next` return the PNG image for
+    one of `WA-N`, `WA-S`, `NT`, `QLD-N`, `QLD-S`, `SA`, `NSW-W`, `NSW-E`,
+    `VIC`, `TAS`
+  * Area codes are parsed from `gaf.shtml`; product ids and the
+    current/next rotation come from `gaf-pub.js` (UTC-hour driven)
+* Add BOM Grid Point Wind & Temperature (GPWT) endpoint
+  * `/gpwt/<level>/<area>/<time>` returns the PNG for the requested
+    (level, area, time-slot) triple; `level` is `low`, `mid`, or `high`
+  * Product list is parsed from the BOM grid-point-forecasts HTML page
+  * Depends on `Data.Aviation.GPWT` from `metar-0.0.6`
+* GAF fetching moved into the `metar` library (`Data.Aviation.GAF` in
+  `metar-0.0.6`); this project now only handles HTTP routing
+* Require `metar >= 0.0.6`; drop direct deps on `tagsoup`, `wreq`,
+  `time`, `http-client` (now transitive through `metar`)
+* Remove stale `-XNoImplicitPrelude` from `.ghci` so `cabal repl` loads
+  the library cleanly
+
 0.0.5
 
 * Update to metar-0.0.5 library
diff --git a/metar-http.cabal b/metar-http.cabal
--- a/metar-http.cabal
+++ b/metar-http.cabal
@@ -1,5 +1,5 @@
 name:               metar-http
-version:            0.0.5
+version:            0.0.6
 license:            BSD3
 license-file:       LICENCE
 author:             Tony Morris <ʇǝu˙sıɹɹoɯʇ@sıɹɹoɯʇ>
@@ -24,9 +24,10 @@
 
   build-depends:
                     base >= 4.8 && < 5
+                    , bytestring >= 0.10 && < 0.13
                     , http-types >= 0.9 && < 1
                     , lens >= 4 && < 6
-                    , metar >= 0.0.5 && < 1.0
+                    , metar >= 0.0.6 && < 1
                     , network-uri >= 2.6 && < 3
                     , text >= 1.2 && < 3
                     , semigroups >= 0.9 && < 1
diff --git a/src/Data/Aviation/Metar/Http.hs b/src/Data/Aviation/Metar/Http.hs
--- a/src/Data/Aviation/Metar/Http.hs
+++ b/src/Data/Aviation/Metar/Http.hs
@@ -1,22 +1,38 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# OPTIONS_GHC -Wall #-}
 
--- | HTTP server exposing METAR observations. Australian aerodromes (ICAO codes
--- beginning with @Y@) are fetched from BOM; other codes fall back to NOAA.
+-- | HTTP server exposing METAR observations, BOM Graphical Area Forecast
+-- (GAF) images, and BOM Grid Point Wind and Temperature (GPWT) images.
+--
+-- @/metar/\<icao\>@ returns a METAR observation as text: Australian aerodromes
+-- (ICAO codes beginning with @Y@) are fetched from BOM; other codes fall back
+-- to NOAA.
+--
+-- @/gaf/\<area\>/current@ and @/gaf/\<area\>/next@ return the corresponding
+-- BOM GAF PNG image. Areas are @WA-N@, @WA-S@, @NT@, @QLD-N@, @QLD-S@, @SA@,
+-- @NSW-W@, @NSW-E@, @VIC@, @TAS@.
+--
+-- @/gpwt/\<level\>/\<area\>/\<time\>@ returns the corresponding BOM GPWT PNG.
+-- @level@ is @low@, @mid@ or @high@; @area@ is one of the codes advertised on
+-- the grid-point-forecasts page (e.g. @AUS@, @NSW@, @QLD-N@, @VIC-TAS@,
+-- @TIMS@); @time@ is a 3-hourly UTC slot like @00Z@, @03Z@ ... @21Z@.
 module Data.Aviation.Metar.Http (
   metarHTTP,
   metarHTTPapp,
 ) where
 
 import Control.Lens (folded, (^.), (^?), _Wrapped)
+import Data.Aviation.GAF (GAFError (GAFHttpError, GAFUnknownArea), GAFImage (GAFImage), GAFPeriod (GAFCurrent, GAFNext), getGAF, renderGAFError)
+import Data.Aviation.GPWT (GPWTError (GPWTHttpError, GPWTNoSuchProduct, GPWTUnknownLevel), GPWTImage (GPWTImage), getGPWT, parseLevel, renderGPWTError)
 import Data.Aviation.Metar (getMETAR)
 import Data.Aviation.Metar.METARResult (_METARResultValue)
+import qualified Data.ByteString.Char8 as BS
 import Data.ByteString.Lazy.UTF8 (fromString)
 import Data.List (intercalate)
-import Data.Text (toLower, unpack)
+import Data.Text (Text, toLower, unpack)
 import Network.HTTP.Types.Header (hContentType)
-import Network.HTTP.Types.Status (status200, status404)
-import Network.Wai (Application, pathInfo, responseLBS)
+import Network.HTTP.Types.Status (status200, status404, status502)
+import Network.Wai (Application, Response, pathInfo, responseLBS)
 import Network.Wai.Handler.Warp (defaultSettings, runSettings, setPort, setTimeout)
 import System.Environment (getArgs)
 
@@ -192,7 +208,7 @@
             Just l ->
               MaxLines l r'
 
--- | WAI 'Application' serving METAR observations.
+-- | WAI 'Application' serving METAR observations and BOM GAF images.
 metarHTTPapp ::
   Application
 metarHTTPapp req withResp =
@@ -209,6 +225,12 @@
               </> "metar for station <icao> all on one line truncated at <maxchars>"
               <//> "/metar/<icao>/*/<maxchars>/<appendstr>"
               </> "metar for station <icao> all on one line truncated at <maxchars> and if truncation occurs, append <appendstr>"
+              <//> "/gaf/<area>/current"
+              </> "current BOM Graphical Area Forecast (PNG) for <area> (WA-N, WA-S, NT, QLD-N, QLD-S, SA, NSW-W, NSW-E, VIC, TAS)"
+              <//> "/gaf/<area>/next"
+              </> "next BOM Graphical Area Forecast (PNG) for <area>"
+              <//> "/gpwt/<level>/<area>/<time>"
+              </> "BOM Grid Point Wind & Temperature forecast (PNG); <level> is low, mid or high; <area> e.g. AUS, NSW, QLD-N, VIC-TAS, TIMS; <time> is a 3-hourly UTC slot like 00Z, 03Z ... 21Z"
               <//> ""
       _404 =
         responseLBS
@@ -216,35 +238,37 @@
           []
           msg
    in case pathInfo req of
-        (rpt : xxxx : r) ->
-          let xxxx' =
-                unpack xxxx
-              modifyOutput ::
-                [String] ->
-                String
-              modifyOutput =
-                format (uriPathFormat (unpack <$> r))
-              mt =
-                case toLower rpt of
-                  "metar" ->
-                    Just ("METAR", getMETAR xxxx')
-                  "taf" ->
-                    Nothing
-                  _ ->
-                    Nothing
-           in case mt of
+        ["gaf", area, periodTxt]
+          | Just period <- gafPeriod (toLower periodTxt) ->
+              do
+                r <- getGAF (unpack area) period
+                withResp (gafResponse r)
+        ["gpwt", levelTxt, area, timeTxt] ->
+          let levelStr = unpack (toLower levelTxt)
+           in case parseLevel levelStr of
                 Nothing ->
-                  withResp _404
-                Just (mtt, mtf) ->
+                  withResp $
+                    responseLBS
+                      status404
+                      [(hContentType, "text/plain")]
+                      (fromString (renderGPWTError (GPWTUnknownLevel levelStr)))
+                Just lv ->
                   do
-                    t <- mtf ^. _Wrapped
+                    r <- getGPWT lv (unpack area) (unpack timeTxt)
+                    withResp (gpwtResponse r)
+        (rpt : xxxx : r)
+          | toLower rpt == "metar" ->
+              let xxxx' = unpack xxxx
+                  modifyOutput = format (uriPathFormat (unpack <$> r))
+               in do
+                    t <- getMETAR xxxx' ^. _Wrapped
                     withResp $
                       case t ^? _METARResultValue of
                         Nothing ->
                           responseLBS
                             status404
                             []
-                            ("no " <> mtt <> " found for " <> fromString xxxx')
+                            ("no METAR found for " <> fromString xxxx')
                         Just x ->
                           responseLBS
                             status200
@@ -258,6 +282,90 @@
               msg
         _ ->
           withResp _404
+
+-- | Parse the trailing path segment of a @/gaf/<area>/...@ request into a
+-- 'GAFPeriod'.
+--
+-- >>> gafPeriod "current"
+-- Just GAFCurrent
+--
+-- >>> gafPeriod "next"
+-- Just GAFNext
+--
+-- >>> gafPeriod "other"
+-- Nothing
+gafPeriod ::
+  Text ->
+  Maybe GAFPeriod
+gafPeriod t =
+  case t of
+    "current" -> Just GAFCurrent
+    "next" -> Just GAFNext
+    _ -> Nothing
+
+-- | Turn a GAF fetch outcome into a WAI response. Successful fetches serve
+-- the raw image bytes with the BOM-declared content type; errors map to
+-- @404@ (unknown area) or @502@ (upstream failure) with a plain-text body.
+gafResponse ::
+  Either GAFError GAFImage ->
+  Response
+gafResponse r =
+  case r of
+    Right (GAFImage ct bs) ->
+      responseLBS
+        status200
+        [(hContentType, BS.pack ct)]
+        bs
+    Left err@(GAFUnknownArea _ _) ->
+      responseLBS
+        status404
+        [(hContentType, "text/plain")]
+        (fromString (renderGAFError err))
+    Left err@(GAFHttpError _ _) ->
+      responseLBS
+        status502
+        [(hContentType, "text/plain")]
+        (fromString (renderGAFError err))
+    Left err ->
+      responseLBS
+        status502
+        [(hContentType, "text/plain")]
+        (fromString (renderGAFError err))
+
+-- | Turn a GPWT fetch outcome into a WAI response. Successful fetches serve
+-- the raw image bytes with the BOM-declared content type; errors map to
+-- @404@ (unknown level, or no product for the requested area/time) or @502@
+-- (upstream failure) with a plain-text body.
+gpwtResponse ::
+  Either GPWTError GPWTImage ->
+  Response
+gpwtResponse r =
+  case r of
+    Right (GPWTImage ct bs) ->
+      responseLBS
+        status200
+        [(hContentType, BS.pack ct)]
+        bs
+    Left err@(GPWTUnknownLevel _) ->
+      responseLBS
+        status404
+        [(hContentType, "text/plain")]
+        (fromString (renderGPWTError err))
+    Left err@(GPWTNoSuchProduct{}) ->
+      responseLBS
+        status404
+        [(hContentType, "text/plain")]
+        (fromString (renderGPWTError err))
+    Left err@(GPWTHttpError _ _) ->
+      responseLBS
+        status502
+        [(hContentType, "text/plain")]
+        (fromString (renderGPWTError err))
+    Left err ->
+      responseLBS
+        status502
+        [(hContentType, "text/plain")]
+        (fromString (renderGPWTError err))
 
 -- | Run 'metarHTTPapp' with Warp, optionally taking a port from the first
 -- command-line argument.
