diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a4a57e9db..a671a72e6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,21 +1,21 @@
 repos:
   # Versioning: Commit messages & changelog
   - repo: https://github.com/commitizen-tools/commitizen
-    rev: 3.10.1
+    rev: 3.12.0
     hooks:
       - id: commitizen
         stages: [commit-msg]
 
   # Autoformat: Python code
   - repo: https://github.com/psf/black
-    rev: 23.9.1
+    rev: 23.10.1
     hooks:
       - id: black
 
   # Lint / autoformat: Python code
   - repo: https://github.com/astral-sh/ruff-pre-commit
     # Ruff version.
-    rev: "v0.0.292"
+    rev: "v0.1.4"
     hooks:
       - id: ruff
         args: [--exit-non-zero-on-fix]
diff --git a/mkdocs.yml b/mkdocs.yml
index 845c30aac..1625bb59e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -96,6 +96,7 @@ nav:
       - External Data: about/externaldata.md
       - Data conflation: about/conflation.md
       - The Config File: about/configuring.md
+      - XLSForm Design: about/xlsforms.md
   #  - odk2geojson: api/odk2geojson.md
   #  - odk2csv: api/odk2csv.md
   #  - odk2osm: api/odk2osm.md
diff --git a/osm_fieldwork/basemapper.py b/osm_fieldwork/basemapper.py
index 79063a40c..5e642582e 100755
--- a/osm_fieldwork/basemapper.py
+++ b/osm_fieldwork/basemapper.py
@@ -20,7 +20,7 @@
 
 import argparse
 import concurrent.futures
-import json
+import geojson
 import logging
 import queue
 import re
@@ -101,6 +101,7 @@ def dlthread(
             # Create the subdirectories as pySmartDL doesn't do it for us
             Path(dest).mkdir(parents=True, exist_ok=True)
 
+        dl = None
         try:
             if site["source"] == "topo":
                 filespec += "." + site["suffix"]
@@ -112,7 +113,10 @@ def dlthread(
                 log.debug("%s exists!" % (outfile))
         except Exception as e:
             log.error(e)
-            log.error("Couldn't download from %r: %s" % (filespec, dl.get_errors()))
+            if dl:
+                log.error(f"Couldn't download {filespec}: {dl.get_errors()}")
+            else:
+                log.error(f"Couldn't download {filespec}")
 
 
 class BaseMapper(object):
@@ -292,10 +296,10 @@ def makeBbox(
 
         log.debug(f"Reading geojson file: {boundary}")
         with open(boundary, "r") as f:
-            poly = json.load(f)
+            poly = geojson.load(f)
         if "features" in poly:
             geometry = shape(poly["features"][0]["geometry"])
-        if "geometry" in poly:
+        elif "geometry" in poly:
             geometry = shape(poly["geometry"])
         else:
             geometry = shape(poly)
diff --git a/osm_fieldwork/json2osm.py b/osm_fieldwork/json2osm.py
index bf645c70b..02183794a 100755
--- a/osm_fieldwork/json2osm.py
+++ b/osm_fieldwork/json2osm.py
@@ -267,7 +267,7 @@ def parse(
                 tags[key] = v
             total.append(tags)
 
-        log.debug(f"Finsished parsing JSON file {filespec}")
+        # log.debug(f"Finished parsing JSON file {filespec}")
         return total
 
     def createEntry(
@@ -417,10 +417,10 @@ def json2osm(input_file, yaml_file=None):
                     log.warning(f"Bad record! {feature}")
                     continue  # Skip bad records
 
-            log.debug("Writing final OSM XML file...")
             jsonin.writeOSM(feature)
+    # log.debug("Writing final OSM XML file...")
 
-    jsonin.finishOSM()
+    # jsonin.finishOSM()
     log.info(f"Wrote OSM XML file: {osmoutfile}")
 
     return osmoutfile
diff --git a/osm_fieldwork/osmfile.py b/osm_fieldwork/osmfile.py
index 3490a493e..b18356bab 100755
--- a/osm_fieldwork/osmfile.py
+++ b/osm_fieldwork/osmfile.py
@@ -200,6 +200,7 @@ def createWay(
         for ref in way["refs"]:
             osm += '\n    <nd ref="%s"/>' % ref
 
+        import epdb; epdb.st()
         if "tags" in way:
             for key, value in way["tags"].items():
                 if value is None:
@@ -208,8 +209,9 @@ def createWay(
                     continue
                 if key not in attrs:
                     newkey = escape(key)
-                    osm += "\n    <tag k='%s' v=%r/>" % (newkey, str(value))
-            if modified:
+                    newval = escape(str(value))
+                    osm += f"\n    <tag k='{newkey}' v='{newval}'/>"
+            if modified and key != 'note':
                 osm += '\n    <tag k="note" v="Do not upload this without validation!"/>'
             osm += "\n"
 
@@ -296,8 +298,10 @@ def createNode(
                 if not value:
                     continue
                 if key not in attrs:
-                    osm += "\n    <tag k='%s' v=%r/>" % (key, str(value))
-            if modified:
+                    newkey = escape(key)
+                    newval = escape(str(value))
+                    osm += f"\n    <tag k='{newkey}' v='{newval}'/>"
+            if modified and key != 'note':
                 osm += '\n    <tag k="note" v="Do not upload this without validation!"/>'
             osm += "\n  </node>\n"
         else:
diff --git a/tests/test_basemap.py b/tests/test_basemap.py
index 1e291f8da..55dc8cd3c 100755
--- a/tests/test_basemap.py
+++ b/tests/test_basemap.py
@@ -29,7 +29,7 @@
 log = logging.getLogger(__name__)
 
 rootdir = os.path.dirname(os.path.abspath(__file__))
-infile = f"{rootdir}/testdata/Rollinsville.geojson"
+boundary = f"{rootdir}/testdata/Rollinsville.geojson"
 outfile = f"{rootdir}/testdata/rollinsville.mbtiles"
 base = "./tiles"
 # boundary = open(infile, "r")
@@ -45,7 +45,7 @@
 def test_create():
     """See if the file got loaded."""
     hits = 0
-    basemap = BaseMapper(infile, base, "topo", False)
+    basemap = BaseMapper(boundary, base, "topo", False)
     tiles = list()
     for level in [8, 9, 10, 11, 12]:
         basemap.getTiles(level)
@@ -65,6 +65,5 @@ def test_create():
 
     assert hits == 2
 
-
 if __name__ == "__main__":
     test_create()