diff --git a/projects/public_dns/src/python/arrdem/updater/__main__.py b/projects/public_dns/src/python/arrdem/updater/__main__.py
index 984e26c..4631bd7 100644
--- a/projects/public_dns/src/python/arrdem/updater/__main__.py
+++ b/projects/public_dns/src/python/arrdem/updater/__main__.py
@@ -18,7 +18,8 @@ RECORD_LINE_PATTERN = re.compile(
     r"(?P<rrset_ttl>\S+)\s+"
     r"IN\s+"
     r"(?P<rrset_type>\S+)\s+"
-    r"(?P<rrset_values>.+)$"
+    r"(?P<rrset_values>[^\s#]+)"
+    r"(?P<comment>\s*#.*?)$"
 )
 
 
diff --git a/projects/public_dns/src/resources/zonefiles/tirefireind.us.j2 b/projects/public_dns/src/resources/zonefiles/tirefireind.us.j2
index 87484b5..8bf9300 100644
--- a/projects/public_dns/src/resources/zonefiles/tirefireind.us.j2
+++ b/projects/public_dns/src/resources/zonefiles/tirefireind.us.j2
@@ -22,15 +22,13 @@ relay       {{ ttl }} IN A {{ link }}
 pxe         {{ ttl }} IN A {{ link }}
 {% endfor %}
 
+# Secrets service
+ssvc                       {{ ttl }} IN A 10.0.0.22
+
 # Host records
 ## The hand-rolled hosts
 feed.host.dia0.site        {{ ttl }} IN A 10.0.0.5
 sucker.host.dia0.site      {{ ttl }} IN A 10.0.0.16
 chisel.host.dia0.site      {{ ttl }} IN A 10.0.0.20
 heiroglyph.host.dia0.site  {{ ttl }} IN A 10.0.0.22
-## The modes
-fuhok-migir.host.dia0.site {{ ttl }} IN A 10.0.0.24
-kadib-mifin.host.dia0.site {{ ttl }} IN A 10.0.0.25
-banat-kukol.host.dia0.site {{ ttl }} IN A 10.0.0.26
-## The old blue laptop
-gamis-nakag.host.dia0.site {{ ttl }} IN A 10.0.0.27
+gamis-nikag.host.dia0.site {{ ttl }} IN A 10.0.0.27
diff --git a/projects/smith/BUILD b/projects/smith/BUILD
new file mode 100644
index 0000000..f69a080
--- /dev/null
+++ b/projects/smith/BUILD
@@ -0,0 +1,11 @@
+py_project(
+    name = "smith",
+    lib_deps = [
+        py_requirement("ibis"),
+        py_requirement("toml"),
+    ],
+    main_deps = [
+        py_requirement("click"),
+    ],
+    main = "src/python/smith/__main__.py",
+)
diff --git a/projects/smith/README.md b/projects/smith/README.md
new file mode 100644
index 0000000..0a94f29
--- /dev/null
+++ b/projects/smith/README.md
@@ -0,0 +1,18 @@
+# Smith
+> An agent
+![Mr. Smith](./smith.jpeg)
+
+
+Smith is, in many ways, a clean sheet implementation of [cram](https://git.arrdem.com/arrdem/cram).
+
+Cram as a tool has been quite successful at implementing an agentless (get it) masterless configuration.
+Clone a git repo and apply the config.
+
+The miss of Cram is that it's really only designed to install static files, and really only to a homedir.
+Installing packages is frankly a dirty hack.
+
+In contrast to Cram's static configurations and mostly static actions, Smith has much more in common with Ansible, Puppet or Saltstack.
+
+Like these full up configuration management systems, Smith features an inventory system, a package manager abstraction, templating features and - unlike these other systems - a core action model and changelog.
+
+Also like those other systems, Smith uses a "real" configuration language for defining "modules".
diff --git a/projects/smith/smith.jpeg b/projects/smith/smith.jpeg
new file mode 100644
index 0000000..0e89045
Binary files /dev/null and b/projects/smith/smith.jpeg differ
diff --git a/projects/smith/src/python/smith/__main__.py b/projects/smith/src/python/smith/__main__.py
new file mode 100644
index 0000000..d5b61e9
--- /dev/null
+++ b/projects/smith/src/python/smith/__main__.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+
+import click
+
+
+@click.group
+def cli():
+    pass
+
+
+@cli.group("inventory")
+def inventory():
+    pass
+
+
+@inventory.command("config")
+def inventory_config():
+    """Show the configured inventory plugins."""
+    pass
+
+
+@inventory.command("show")
+def inventory_show():
+    """Evaluate host inventory data & display that configuration."""
+    pass
+
+
+@cli.group("config")
+def config():
+    pass
+
+
+@config.command("state")
+def config_state():
+    """Show the current configuration state from the last apply."""
+
+
+@config.command("diff")
+def config_diff():
+    """Show changes from applying the new configuration."""
+
+
+@config.command("apply")
+def config_apply():
+    """Apply changes from the new configuration."""
+
+
+if __name__ == "__main__":
+    cli()
diff --git a/tools/python/pythonshim b/tools/python/pythonshim
index a3a0a7e..3c96de3 100755
--- a/tools/python/pythonshim
+++ b/tools/python/pythonshim
@@ -4,7 +4,7 @@
 # But ... that's exactly what we want to do.
 # So this script exists to find a 'compliant' Python install and use that.
 
-PYTHONREV="3.10"
+PYTHONREV="3.11"
 CMD="python${PYTHONREV}"
 
 if [ -x "$(command -v "$CMD")" ]; then
diff --git a/tools/python/requirements.in b/tools/python/requirements.in
index 12aad51..da7413a 100644
--- a/tools/python/requirements.in
+++ b/tools/python/requirements.in
@@ -1,3 +1,4 @@
+ExifRead
 aiohttp
 aiohttp_basicauth
 async_lru
@@ -7,10 +8,10 @@ black
 cachetools
 click
 colored
-ExifRead
 flake8
 flask
 hypothesis
+ibis
 icmplib
 isort
 jinja2
@@ -42,3 +43,4 @@ sphinxcontrib-programoutput
 unify
 yamllint
 yaspin
+toml
diff --git a/tools/python/requirements.txt b/tools/python/requirements.txt
index be5b261..e51fccd 100644
--- a/tools/python/requirements.txt
+++ b/tools/python/requirements.txt
@@ -1,128 +1,92 @@
 aiohttp==3.8.4
 aiohttp-basicauth==1.0.0
-aiosignal==1.2.0
-alabaster==0.7.12
-async-lru==1.0.3
+aiosignal==1.3.1
+alabaster==0.7.13
+async-lru==2.0.2
 async-timeout==4.0.2
-attrs==22.1.0
-autoflake==2.0.1
-Babel==2.11.0
-bases==0.2.1
-beautifulsoup4==4.11.2
+attrs==22.2.0
+autoflake==2.0.2
+Babel==2.12.1
+beautifulsoup4==4.12.0
 black==23.1.0
-blake3==0.3.1
-bleach==4.1.0
-borg==2012.4.1
 cachetools==5.3.0
-cbor2==5.4.3
-certifi==2022.9.24
-chardet==4.0.0
-charset-normalizer==2.1.1
+certifi==2022.12.7
+charset-normalizer==3.1.0
 click==8.1.3
 colored==1.4.4
 commonmark==0.9.1
-coverage==6.2
-Cython==0.29.30
-dataclasses==0.6
+coverage==7.2.2
 decorator==5.1.1
 deepmerge==1.1.0
-Deprecated==1.2.13
 docutils==0.19
-exceptiongroup==1.1.0
+exceptiongroup==1.1.1
 ExifRead==3.0.0
 flake8==6.0.0
 Flask==2.2.3
 frozenlist==1.3.3
-graphviz==0.19.1
-hypothesis==6.68.1
+hypothesis==6.70.0
+ibis==3.2.0
 icmplib==3.0.3
 idna==3.4
 imagesize==1.4.1
-importlib-metadata==4.10.0
-iniconfig==1.1.1
-isodate==0.6.1
+iniconfig==2.0.0
 isort==5.12.0
-itsdangerous==2.0.1
-jedi==0.18.1
+itsdangerous==2.1.2
 Jinja2==3.1.2
-jsonschema==4.3.3
-jsonschema-spec==0.1.3
+jsonschema==4.17.3
+jsonschema-spec==0.1.4
 lark==1.1.5
 lazy-object-proxy==1.9.0
 livereload==2.6.3
 lxml==4.9.2
-m2r==0.2.1
-Markdown==3.4.1
-MarkupSafe==2.1.1
+Markdown==3.4.3
+MarkupSafe==2.1.2
 mccabe==0.7.0
-meraki==1.27.0
-mirakuru==2.4.1
-mistune==2.0.1
-mmh3==3.0.0
-multidict==6.0.2
-multiformats==0.1.4.post3
-mypy-extensions==0.4.3
-numpy==1.23.5
+meraki==1.30.0
+mirakuru==2.5.1
+mistune==2.0.5
+multidict==6.0.4
+mypy-extensions==1.0.0
 octorest==0.4
-openapi-schema-validator==0.4.3
-openapi-spec-validator==0.5.5
+openapi-schema-validator==0.4.4
+openapi-spec-validator==0.5.6
 packaging==23.0
-parso==0.8.3
 pathable==0.4.3
-pathspec==0.9.0
-pep517==0.13.0
+pathspec==0.11.1
 picobox==2.2.0
-pip==22.3.1
-pip-tools==6.4.0
-plac==1.3.5
-platformdirs==2.4.1
+platformdirs==3.2.0
 pluggy==1.0.0
-port-for==0.6.1
-prompt-toolkit==3.0.36
+port-for==0.6.3
+prompt-toolkit==3.0.38
 proquint==0.2.1
 psutil==5.9.4
 psycopg2==2.9.5
-pudb==2022.1
-pur==5.4.2
 py==1.11.0
 pycodestyle==2.10.0
 pycryptodome==3.17
-pycryptodomex==3.15.0
 pyflakes==3.0.1
-Pygments==2.13.0
-pyparsing==3.0.9
+Pygments==2.14.0
 pyrsistent==0.19.3
-pysha3==1.0.2
-pyskein==1.0
-pytest==6.2.5
+pytest==7.2.2
 pytest-cov==4.0.0
 pytest-postgresql==4.1.1
-pytest-pudb==0.7.0
-pytest-timeout==2.1.0
-pytz==2022.6
 PyYAML==6.0
-readme-renderer==32.0
 recommonmark==0.7.1
-redis==4.5.1
-regex==2021.11.10
+redis==4.5.3
 requests==2.28.2
-requests-toolbelt==0.9.1
-requirements-parser==0.3.1
 retry==0.9.2
 rfc3339-validator==0.1.4
-scipy==1.8.1
-setuptools==60.5.0
 six==1.16.0
 smbus2==0.4.2
 snowballstemmer==2.2.0
 sortedcontainers==2.4.0
-soupsieve==2.3.1
+soupsieve==2.4
 Sphinx==6.1.3
 sphinx_mdinclude==0.5.3
-sphinxcontrib-applehelp==1.0.2
+sphinxcontrib-applehelp==1.0.4
 sphinxcontrib-devhelp==1.0.2
-sphinxcontrib-htmlhelp==2.0.0
-sphinxcontrib-httpdomain==1.8.0
+sphinxcontrib-htmlhelp==2.0.1
+sphinxcontrib-httpdomain==1.8.1
 sphinxcontrib-jsmath==1.0.1
 sphinxcontrib-openapi==0.8.1
 sphinxcontrib-programoutput==0.17
@@ -131,25 +95,14 @@ sphinxcontrib-serializinghtml==1.1.5
 termcolor==2.2.0
 toml==0.10.2
 tomli==2.0.1
-toposort==1.7
-tornado==6.1
-typed-ast==1.5.1
-types-setuptools==57.4.7
-typing-validation==0.0.1.post7
-typing_extensions==4.4.0
+tornado==6.2
+typing_extensions==4.5.0
 unify==0.5
 untokenize==0.1.1
-urllib3==1.26.13
-urwid==2.1.2
-urwid-readline==0.13
-wasm==1.2
-wcwidth==0.2.5
-webencodings==0.5.1
-websocket-client==1.2.3
+urllib3==1.26.15
+wcwidth==0.2.6
+websocket-client==1.5.1
 Werkzeug==2.2.3
-wheel==0.37.1
-wrapt==1.13.3
-yamllint==1.29.0
-yarl==1.8.1
+yamllint==1.30.0
+yarl==1.8.2
 yaspin==2.3.0
-zipp==3.7.0