diff --git a/geomagio/processing/adjusted.py b/geomagio/processing/adjusted.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a1988896a806b7e0c6b410de802392b372eff90
--- /dev/null
+++ b/geomagio/processing/adjusted.py
@@ -0,0 +1,52 @@
+import json
+from obspy import UTCDateTime
+from typing import Optional
+import typer
+
+from ..adjusted.Affine import Affine
+from ..residual import SpreadsheetSummaryFactory, WebAbsolutesFactory
+
+
+def main():
+    typer.run(generate_matrix)
+
+
+def generate_matrix(
+    observatory: str,
+    starttime: UTCDateTime,
+    endtime: UTCDateTime,
+    readings_starttime: UTCDateTime,
+    readings_endtime: UTCDateTime,
+    output_file: str,
+    input_factory: str = "webabsolutes",
+    spreadsheet_directory: Optional[str] = None,
+    webabsolutes_url: Optional[
+        str
+    ] = "https://geomag.usgs.gov/baselines/observation.json.php",
+):
+    if input_factory == "spreadsheet":
+        readings = SpreadsheetSummaryFactory(
+            base_directory=spreadsheet_directory
+        ).get_readings(
+            observatory=observatory,
+            starttime=readings_starttime,
+            endtime=readings_endtime,
+        )
+    elif input_factory == "webabsolutes":
+        readings = WebAbsolutesFactory(url=webabsolutes_url).get_readings(
+            observatory=observatory,
+            starttime=readings_starttime,
+            endtime=readings_endtime,
+        )
+    else:
+        readings = []
+
+    result = Affine(
+        observatory=observatory,
+        starttime=starttime,
+        endtime=endtime,
+    ).calculate(readings=readings)[0]
+    result.matrix = result.matrix.tolist()
+
+    with open(output_file, "w") as file:
+        json.dump(result.dict(), file)
diff --git a/setup.py b/setup.py
index a92451cdf5762c924da69c7c343f1b73a92efab8..de1bec63c330ec0a053108278f5802cca37fac3e 100644
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,7 @@ setuptools.setup(
         "console_scripts": [
             "magproc-prepfiles=geomagio.processing.magproc:main",
             "filter-realtime=geomagio.processing.obsrio:main",
+            "generate-matrix:geomagio.processing.adjusted:main",
         ],
     },
 )