tylersowards.com all systems nominal self-hosted · Fort Worth, TX

● Tyler Sowards · full-stack developer · internal tools, automation, AI workflows

I build systems.

Self-taught, field-tested. Ten years ago I was on a survey field crew. I designed and built the platform my old department still uses, and today I am a software developer on the firm's Business Innovation team. Below is that platform, plus everything I build on my own time.

01 service monitor · seventeen systems

● RESTRICTED · INTERNAL · UP SINCE 2026

Geomatics ERP

An ERP for a working geomatics department.

FastAPIPostgreSQL / PostGISRedis NginxDocker

I designed, built, and deployed it with help from AI coding tools, and supported it until I changed teams: a 26-container microservice platform on a spatial PostGIS core. Eighteen bounded services behind one gateway: project tracking, field operations, AI document extraction, client delivery. It replaced Asana for project and task management, and the department runs its field and office work on it. The map below is the real topology. A few were built and never put into daily use: the compliance gate, the analytics layer, and the field-to-office pipeline. Click around.

geomatics_erp_modules · service map, click to inspectauto-tour
nginx gateway jwt · rbac · routing 18 FastAPI services · one bounded context each PostGIS source of truth Redis rate · session event ledger telemetry backup nightly
01 / 18

eighteen services · click a box, filter by layer, or let the tour drive · arrow keys work

geomatics_erp_ui · select a service abovesanitized preview
Sanitized preview
in progress
a hand-built, generic mock of this service lands here. the tasks board is the first one live. no real Geomatics ERP UI is ever served.

click a service above to see its sanitized UI here · every preview is a generic mock, never the real thing

● CORE LOOP PLAYABLE · PERSONAL LAB · UNITY 6 + .NET · 1,500+ TESTS PASSING

Land Survey Simulator

A land survey simulator: the arithmetic is automated, the judgment is modeled.

A first-person land survey game. A card headed CHIEF, NOTE reads: Did you pick up general ground at a density that describes the lot's roughness? Nothing in the list for it yet, and I would rather ask than find out in the office. Below it in italics: If you got it, say so and I will shut up. Nothing here is a mark against you, I am reading the same brief you are.
the crew chief reviews your work. He only sees the shots you took, never the actual ground, so when something looks missing he asks about it instead of telling you you got it wrong
A wide first person view across a Texas Cross Timbers lot. Tall dry grass fills the right foreground. A wrought iron fence runs diagonally into the middle distance, separating the creek bank from the parcel, with scattered oaks and elms across the middle and standing water at the lower left.
the back of the lot. Past the fence the ground drops off toward a creek, which is why your surface is only graded inside the property line
First person view across a pale concrete cul-de-sac. A blue pickup truck is parked at the right edge of frame. Beyond a band of tall grass stand scattered trees, and a single storey house with a dark roof sits in the middle distance.
the street out front, where you park and start the day. Two of the lot's eight property corners sit right at the edge of the pavement

Nobody teaches surveying to someone who has never held a prism pole, so I am building the thing that does. The brain is a plain .NET class library with no engine reference of any kind: survey mathematics, the error model, boundary rules, grading. It builds for net8.0 and netstandard2.1, has no package references at all, and the same assembly runs under dotnet test and inside Unity. More than 1,500 tests run in seconds, which is what makes it safe to keep changing the math. Coordinates are the part I got strict about early. Everything is stored as doubles in meters and radians in a projected CRS and converted only for display, and survey data never round-trips through a 32-bit float: at Texas state plane northings a float resolves to roughly half a foot, which is worse than the instrument being simulated. The engine transform is a rendering against a floating origin that re-bases as the player walks. Every surface the player sees is in US survey feet, which is exactly 1200/3937 meters and not the international foot. Two parts per million sounds like nothing until you are seven million feet north, where it is about fourteen feet. The fixture the whole suite is built on is a five station loop with analytically known geometry, enclosing 22,500 m² exactly. I computed every expected value independently before writing the library, because matching a published traverse proves you copied it correctly and proves nothing else.

The rule that constrains everything is that the player is never shown ground truth. Every observation is truth plus modeled error, and estimating an unknown from imperfect evidence is the whole game. The crew chief who reviews your work reasons only about the record you produced, never about the terrain, and a reflection test asserts that no truth-bearing type can reach his view of the job. That firewall is what keeps the feedback honest: he is allowed to say that you coded a top of bank and there is no toe anywhere in the job, and he is not allowed to say you missed the bank. Grading is measured rather than asserted. P95 deviation is the headline, not RMSE, because a missed breakline is a large error over a small area and RMSE averages it into invisibility. On the reference bank, leaving a three meter grade break unshot reads as 0.53 m RMSE against 1.38 m P95, and shooting top and toe takes both to zero.

The part I got wrong was the chief himself. Played on a correctly worked lot he produced nine remarks, most of them technically true and useless. A false positive costs more than a miss, because once you learn to dismiss him every real finding goes with the false ones. I narrowed the finders against the actual ground and measured his remarks back down from nine to two. Underneath the one job there is a career, written as a tested model rather than as shipped content: rodman, gun, party chief, licensed, your own firm, on the rule that a rung has to hand you a new way to work and never better numbers.

C# / .NET 8Unity 6 URPRTK / GNSS error model Delaunay TINEPSG:2276 ftUS lidar / GDAL pipelineMonte Carlo validation metes and bounds

● PRE-LAUNCH · TWO BRANDS, ONE BACKEND · 114 TESTS, REAL FEDERAL DATA · contoursplease.com

Contours

Draw a boundary, get the site record.

FastAPIrasterio · shapely · pyprojscikit-image ezdxfThree.jsPostgreSQL StripeLeaflet

A SaaS in the making: draw or upload a site boundary and one pass returns real USGS contour lines, a stamped CAD file in six export formats (DXF, KMZ, GeoJSON, Shapefile, SVG, PNG), a nine-section due-diligence report, and a first-person 3D walk of the actual terrain, aerial imagery draped over the lidar surface. Everything is computed from public federal data, never mocked: 3DEP elevation down to the one-meter lidar tier, FEMA flood hazard, SSURGO soils, NLCD canopy, TIGER roads, NHD hydrology. The algorithms are the point: marching-squares contour extraction, D8 drainage flow accumulation with ponding detection, a buildable-pad finder that hunts the flattest contiguous square under combined slope, water, and flood masks, a driveway grade profiler along any drawn line, and per-boundary NAD83 UTM zone selection by formula, correct anywhere in the continental US. The 114 backend tests run mostly against the real DEM, flood, and soils rasters, and the backend container is hardened: read-only rootfs, all capabilities dropped, non-root, tmpfs scratch. Two brands, one consumer and one professional, are served by a single backend and routed purely by nginx server name. Deliverables are planning-grade by design and say so on every page.

contours_tool · boundary in, contours outdemo

demo data · a boundary is traced, then the terrain under it is contoured live, marching squares over a real height function · index contours are heavier, just like the DXF

site_report · assembled in one passidle

demo data · each section is a separate spatial query against the drawn polygon · the real report adds severe weather history, towers, EPA facilities, and the 3D walk

walk_this_site · Grapevine Dam, TXopen ↗

click in and walk it · Walk This Site, built off the back of the engineering from Land Survey Simulator, my other project: same public-lidar approach, ported to plain Three.js · real ground near Grapevine Dam, TX, about 38 acres, USGS 3DEP one meter lidar and NAIP aerial imagery, contours drawn live at two feet

● RUNNING · PERSONAL LAB · C# / .NET · 227,060,311 PTS MAPPED

The Living Shard

A game world that plays itself.

C# / .NETPostGISWebGL Geminipathfinding graphLLM cost governance

Autonomous characters living inside a real game server: traveling between towns, mining, crafting, trading on a persistent market ledger, buying houses, and holding LLM-backed conversations when spoken to. The map below shows agents routing themselves across a waypoint graph of the world, with their activity streaming beside it. And beneath the map: the same world as a 227-million-point reconstruction, rebuilt from the game's own data files and explorable in 3D (188M continent points shown).

shard_watch · agent trackerconnecting…
event feedSIM

drag to pan · scroll or pinch to zoom · double-click to reset

pointcloud_viewer · the continent · real export data 187,876,094 pts source
loading points…

drag to rotate · scroll or pinch to zoom · shift-drag or right-drag to pan · double-click to reset

● RUNNING · HOMELAB · 70+ CONTAINERS · 3M+ LOGS A WEEK

Telemetry

A cockpit for everything else on the rack.

FastAPIWebSocketsaiodocker vanilla JSHome Assistant

Real-time observability for every container on my home server: live log streams, health, uptime timelines, pattern alerts. The log hot-path is memory-only, a single background task batch-writes to SQLite each second, so bursts never stall the stream. Alerts fan out to dashboard, bell, and phone from one code path.

telemetry_feeddemo

a slice of the real container-health grid · the restart and stop buttons work, try one

bare_metal · hostdemo
CPU0.0%
24 logical cores55°C
Memory38.0 / 62.5 GB
60.7% used
Disk · Host1.3 GB / 31.0 GB
4% used
NETWORK RX ↓ 0.01 Mbps
NETWORK TX ↑ 0.01 Mbps
HOST UPTIME5D 0H 52M

demo data in the real panel's layout · the real one reads cpu, memory, disk, and network straight from /host/proc

● RUNNING · HOMELAB · 4 DEPENDENCIES · NO BUILD STEP

ezUnraid

The rack's own workbench.

One click from any browser into a real terminal inside any container or appdata folder on the server: actual PTYs bridged over WebSockets, resize ioctl included, rendered by a vendored xterm.js so nothing loads from a CDN at runtime. It walks the appdata share to auto-discover compose projects and pairs them to live containers through compose labels, correcting for Unraid's FUSE versus cache-pool path aliasing on the way. Favorite folders pin as one-click shells, a single env list cross-links every instance on the LAN, and the rebuild button works on everything on the box including itself: the self-rebuild case is detected and handed to a detached helper container, so the update survives killing its own host mid-deploy. A + new CLI button scaffolds a fresh sandboxed Claude Code workspace (compose file, bootstrap script, config volume, seeded app folder) that the discovery walk picks up on its own. Four pip dependencies, and frontend edits go live on refresh off a bind mount.

FastAPIWebSockets · ptyxterm.js Docker APIzero CDN
ezunraid · workbenchdemo

demo data · click a tab or any discovered project · the real thing is a live PTY per tab, resize and all, into whichever container or folder you clicked

● LIVE ON THE LAN · HOMELAB · 4 DEPENDENCIES

Switchboard

The relay the agents behind every other card on this page use to talk to each other.

Every project here has its own Claude Code agent working it, and until this existed none of them could see how another one had already solved something. Switchboard is one FastAPI container, four dependencies total (fastapi, uvicorn, aiosqlite, and Pillow for avatar thumbnails), with two faces: a WebSocket hub that pushes every message to every connected browser in real time, and a plain-curl REST API built specifically for CLI agents, no SDK, no auth handshake. The constraint that shaped the first design is that a CLI agent cannot hold a socket open the way a browser can, so every read supports an after_id delta and an optional server-side wait, up to 120 seconds, that blocks until a newer message actually exists: one curl call waits on a reply instead of a model turn spent per check. A sliding-window rate limit exists for one reason: an agent that starts looping gets told, in plain language, to consolidate its thoughts into fewer messages, not silently dropped. I watch every channel live from the same browser UI the agents use. The Walk This Site viewer on the Contours card above was ported over a live exchange between two agents, in this exact tool, the night it shipped.

FastAPIWebSocketsaiosqlite REST for agentslong-poll delta readsrate-limited by design
switchboard · #generaldemo

type a message, switch channels, or send four fast and you will trip a scaled-down copy of the rate limit the real API enforces · invented agents, invented replies, the mechanics are real

● RUNNING · HOMELAB · 2.5 GBPS MIRROR · 1.6M PPS TESTED

Aegis

The whole network on one graph.

GoAF_PACKET · TPACKET_V3nDPI FastAPISQLite (WAL)WebSockets

My ntopng replacement. A managed switch mirrors every packet in the house into a Go capture agent: AF_PACKET fanout workers, nDPI deep packet inspection, and device identity sniffed from DHCP, mDNS, DNS, and ARP. Flows pre-aggregate in the agent, stream over a unix socket (with a disk spool for backend downtime), and land in a single-writer SQLite pipeline behind the graph ntopng never gave me: every device and protocol at once, zoomable from live seconds to months. Replay benchmarks clear 1.6 million packets per second, four times the worst case a saturated mirror can produce.

aegis_graph · all devices, one timelinedemo

demo data · click a device to hide or show its series

aegis_flows · deep packet inspection0 pps
dropped frames: 0spool: empty

demo of the live flow table · nDPI names the app, not just the port

● PRE-LAUNCH · SAAS · 3 STAGES · 4 LENSES · MAJOR FINDINGS VERIFIED · plotcheck.app

PlotCheck

A continuity audit for whole novels, with receipts.

Authors upload a manuscript and get back contradictions, timeline errors, name drift, and pacing problems. Continuity, name, and timeline findings are re-verified against the source text before they are allowed into the report: a second model pass re-reads the evidence, and a finding that no longer holds does not ship. The pipeline is three async stages: per-chapter extraction fanned out concurrently, four parallel analysis lenses with a trope tagger running alongside, then a bounded verification pass that re-reads the cited chapter instead of the whole book. Every Gemini call returns structured output against a typed schema, so manuscript text is inert data and output is never trusted as prose. Manuscripts are never written to disk, auth is built from scratch with refresh-token family revocation on reuse, and credit billing reconciles Stripe outbound-only, no inbound webhooks required.

FastAPIGemini · structured outputSSE StripeArgon2 · JWTSQLite
plotcheck_run · 22 chapters, 3 stagesqueued

demo data, a fictional manuscript · the evidence is the product: a finding that does not hold up on a second read is discarded in stage C

● LIVE · 4 PUBLIC SITES · 160 AESTHETICS · ONE ENGINE

WebAesthetics

Thirty years of web design, each era rendered in itself.

A reference catalog of 38 digital design aesthetics, GeoCities chaos to aurora-gradient AI minimalism, each documented with its history, defining traits, copyable color palettes, typography pairings, and a live UI sandbox rendered in that aesthetic. The theming is the engineering problem: every era ships as its own scoped stylesheet, lazy-loaded on demand, so one vanilla JS shell re-skins into 38 different pages with no framework and no build step. Search runs on SQLite FTS5 across the whole corpus, filters slice by decade and mood, and the SPA cheats where crawlers care: detail pages live at real paths with a server-rendered SEO head, so every aesthetic is indexable with its own title and canonical. Then the engine turned out to be a franchise: the same FastAPI app now serves four public catalogs, digital design, fashion, interior, and game visuals, each on its own domain with its own SQLite database, seed corpus, and FTS index, routed purely by Host header. All four ride one Cloudflare Tunnel, no published ports on the rack.

FastAPISQLite FTS5vanilla JS scoped CSS themingCloudflare Tunnel
webaesthetics_sandbox · one layout, 38 skins
Sunset Coffee Co.
small-batch roasts, shipped weekly
“The best cup on the block.” · The Local Paper
same markup every time · only the stylesheet changes

six of the 38, recreated in miniature · the real site does this with a full component sandbox per aesthetic, palette and type specimens included

● PRE-LAUNCH · HOUSEHOLD · ~29,000 LINES · NO FRAMEWORK

WENAB

Envelope budgeting for two, on our own hardware.

A YNAB-style envelope budget that we own outright. It is one SQLite file on the rack, with bank sync only if we opt in, through a read-only SimpleFIN token that anchors the balance at link time instead of importing years of history. The engine does monthly rollover math, goal pacing, and multiple auto-assign strategies, and money is integer cents end to end, written down as a hard contract so a float never rounds a budget. Security is layered where it belongs: every page and API route authenticates at the proxy through nginx auth_request, and the JWT carries a token-version claim checked against the database on every request, an instant log-out-everywhere kill switch with no blocklist to maintain. Deletes are soft, into a recycle bin with cascade-aware restore across categories, transactions, and split children. Receipts resize in the browser before upload and optionally itemize through Gemini vision, reports are hand-rolled inline SVG, a forecast view projects 12 or 24 months ahead with what-if assumptions laid against a baseline, and admin is CLI-only by design: there is no signup surface to attack.

FastAPISQLAlchemy asyncSQLite nginx auth_requestGemini visionSimpleFIN (opt-in)vanilla JS
wenab_plan · this month
every dollar gets a job

demo data · hit auto-assign and watch the strategy pour what is left to assign into the underfunded envelopes, goals first · the real app does two-level nesting, drag to reorder, and undo

● RUNNING · SELF-HOSTED · 14 GENERATION MODES · 20+ EXPORT FORMATS · palettetown.cc

Palette Town

A color tool with no account, no paywall, no limits.

The palette generator I wanted kept features behind a subscription, so I built my own. The first version took an afternoon. Spacebar generates, locks keep what you like, and 14 generation modes run the harmony theory from monochromatic to tetradic. Two to ten colors, shade ramps, drag to reorder, undo history, and more than twenty export formats: CSS, SCSS, and Tailwind through Swift, Android XML, Adobe .ase, and Procreate swatches. Saved palettes land in a server-side SQLite library shared by every device in the house, with a localStorage fallback that migrates itself when the server returns. The stack is a static frontend and a dependency-free Node server: no npm install, no build step.

Node (zero deps)SQLitevanilla JS color theoryDocker
palette_town · working demohover it and hit space
click a swatch to copy its hex

a real slice of the app · lock what you like, regenerate the rest · the full version does 2 to 10 colors, shades, and a shared library

the rack keeps growing. the smaller residents:

● RUNNING · HOMELAB

Tallyman

Feels like a budgeting app. Keeps books a CPA can work from.

Money tracking for a one-person LLC. The everyday screen is a simple transaction list, but every entry silently posts as a balanced double-entry journal entry underneath, so the trial balance always proves out and year-end is a one-click ZIP to the accountant. Five containers on a schema-per-service Postgres: core ledger, CSV bank reconciliation, and Stripe webhook ingestion with an idempotency log each own a schema, plus a nightly Fernet-encrypted pg_dump to S3 and the frontend. The ledger knows Section 174 R&D amortization, home-office proration, and net-worth reporting, and an envelope-style budget tab plus an IP and asset registry (copyrights, trademarks, codebases, domains, optionally tied to a capitalized GL account) sit on the same books.

FastAPIPostgres 16Stripe webhooksdouble-entry

● LAN TOOL · HOMELAB · 4 DEPENDENCIES

Softater

Point it at an app, pin the notes to the app.

Visual review for self-hosted web apps. Give it a host and port, or a web address, and the target loads inside the studio through a same-origin reverse proxy: frame-blocking headers are stripped, the app's own URLs are rewritten, and a small shim patches fetch, XHR, history, and WebSocket so single-page apps keep working through the hop. Because the frame is same-origin, the studio can read its DOM. Shift-click an element or drag a region and the note stores a generated CSS selector with the bounding box as a fallback, so pins follow the element through layout shifts and turn dotted when the selector stops resolving. Notes export as Markdown, JSON, or CSV.

FastAPIhttpx reverse proxyDOM inspectorSQLite

● LAN ONLY · HOUSEHOLD · 144 INGREDIENTS · 85 SOURCES

Salsa Slot Machine

A toy, held to a citation standard.

Spin the reels, lock what you like, respin the rest, then ask for the actual recipe with measured amounts and a method. The dice are the fun part; the data is the work. The first draft of the catalog and its 113 compatibility rules came out of an AI, and none of it shipped on trust: every rule was audited against published recipes and extension-service guidance. None survived as a hard ban, six narrowed into conditional cautions, sixty-five were cut as preference or contradicted by a real recipe, and forty-two needed context the board cannot know. Pairings are labeled published or inferred, and when no clean board exists the spin engine returns an honest 409 instead of a conflicting fallback. 75 tests, real Chromium included.

FastAPIconstraint searchsource auditPlaywright

● LIVE · PUBLIC · 12 GENRES · 18,249 REEL LINES · tropemachine.app

Trope Machine

A slot machine for story seeds, running in public.

A free brainstorming tool for fiction writers and a sister tool to PlotCheck, live at tropemachine.app and served from the rack. Pick a genre, spin setting, protagonist, incident, antagonist, trope, tone, theme, and a genre-specific reel, lock what sparks, and re-roll the rest. A hand-edited line locks itself so a spin never throws it away, and Chaos mode pools all twelve genres at once. Every shared board gets its own server-rendered 1200×630 share card with per-request meta tags, and user text embedded in the page is escaped against script breakout. Abuse defense is hand-rolled on three dependencies: each request is classified human, bot, or junk, and ten 404s in five minutes earns a 24-hour ban. The 18,249 lines were generated, judged by a second pass, then scrubbed against a style guide of AI writing tells.

FastAPIPillow share cardsbot classificationvanilla JS

● LAN ONLY · HOUSEHOLD · 9 AGENTS · 40 TESTS

Life App

The memory and message bus for a staff of AI agents.

The back office for a household run with help from nine persistent Claude Code agents, each responsible for their part of running their house. The app never calls a model itself. It is the only place the agents get their context: each turn, a budgeted context builder assembles one Markdown document from live SQL (undelivered messages, pending proposals, open questions, upcoming events, pinned facts, full-text search hits), trims from the bottom when it runs past 12,000 characters, and records exactly which messages were delivered so nothing is lost or repeated. Agent bearer tokens are scoped so no agent can touch another's data, a cron scheduler fires their routines, and everything exports as a Markdown mirror. The humans get an isometric office, AI-generated sprites on a Canvas 2D renderer, where presence, poses, and ?/! markers are a pure function of server state.

FastAPISQLite FTS5context budgetingCanvas 2D
02 console · talk to the page
tyler@homelab: ~try `help`
03 uptime history · one firm, ten years
Sep 2026 → nowSoftware Developer I, Business InnovationJoined the Business Innovation team as a software developer, building internal applications for the rest of the firm.
Dec 2025 → Sep 2026Assistant Project Manager, GeomaticsLed development and support of the department platform, shipping tools between site walks.
Jan 2025 → Dec 2025Survey Technician IIBridging field and office: QA/QC, Leica Infinity, exhibits, and crew logistics across the metroplex. Kept hitting the same bottlenecks, so I started building the software to remove them.
Sep 2021 → Jan 2025Survey Crew Chief IIDrafting between field days from 2021. From September 2023 I was in the office 90 to 100 percent of the time: drafting, data processing, QA/QC, and coordinating other crews. The title took until 2025 to catch up.
Jan 2020 → Sep 2021Survey Crew ChiefConstruction staking, boundary and topo.
Oct 2016 → Jan 2020Instrument OperatorHired onto a field crew in October 2016. Field collection, and the domain knowledge everything above is built on. Ran a crew as acting crew chief from January 2019.
04 installed packages

backend + data

  • Python · FastAPI
  • C# / .NET · Unity
  • Go · packet capture · cgo
  • REST · WebSockets · SSE
  • PostgreSQL / PostGIS
  • Redis · SQLite (WAL)
  • geospatial ETL · JWT / RBAC
  • Stripe billing · webhooks

AI + frontend

  • agentic LLM tool-calling
  • schema-constrained output · Claude · Gemini
  • vanilla JS (ES6+)
  • SVG / canvas dataviz
  • Three.js / WebGL

devops + host

  • Docker · Compose · Nginx
  • Linux · Git
  • Cloudflare Tunnel
  • Unraid homelab
  • self-hosted

The basement.

You typed the thing. These do not go on the resume.

isekai-engine A slot machine that gambles with Gemini and pays out absurd light-novel plotlines. Built for laughs.
ultra-downloader A concurrent download manager with process-group signaling and atomic file claims. Over-engineered on purpose.