Fathom Works mark FATHOMWORKS
Fathom Works · AI infrastructure

Custom AI infrastructure.

Self-hosted, composable, production-ready.

[ about ]

Most “AI agent consultants” can write a good prompt. Fewer have run a fleet of coordinating agents against real infrastructure — real failure modes, at 2am — and fixed it. That's the work I do.

I design and run production infrastructure for AI agent systems: custom MCP servers, multi-agent coordination, and the deployment pipelines that keep it all running. Everything here is live, self-hosted, and actively used — not a tutorial project.

With 20+ years running mission-critical systems — when something broke, my team and I were the ones who had to get our hands dirty and fix it fast. Same reliability mindset, applied to everything I build now.

Bachelor of Science, Information Technology Business Management · Associate of Applied Science, Computer Systems Information Technology, Wide Area Networking

[ what we build ]
Multi-agent systems MCP servers Trading intelligence dashboards Document pipelines Real estate tools

The full stack, containerized, running on your hardware.

If it involves AI talking to your systems — or your systems talking to each other — we build it.

[ projects ]
mcp-switchboard— a message bus for AI agents

mcp-switchboard is a centralized, self-hosted MCP server that acts as a message bus between AI agents — Claude Code, Hermes, Ollama, and others — so they can hand work off to each other directly. It replaces the “human as relay” pattern where someone sits in the middle manually copying output from one agent's terminal into another's.

It runs as a single container behind one URL, with no broker, no Redis, no external dependencies — state lives in SQLite (WAL mode, 5-second busy timeout, monotonic message IDs used as cursors) and survives restarts. Delivery is real-time via an in-process EventEmitter plus long-polling (wait_for_message, up to 25s, AbortSignal-cancelled on client disconnect so listeners don't leak), and a /sync endpoint atomically publishes an agent's status and drains its inbox in the same round trip, so two sessions sharing a mailbox can't both grab the same message. A self-cleaning roster reaps agents that have gone dark for 24+ hours, both lazily on every lookup and on an hourly backstop sweep.

The more interesting decision is in the headless responder daemon, which lets an agent answer messages via claude --print with no interactive session open: it's fail-closed by default, dropping every message unless an explicit sender allowlist is configured — because it's feeding untrusted bus content straight into an LLM, and a prompt injection buried in a message shouldn't be able to run shell commands or read local secrets. The README is just as upfront about what the simplicity costs: single-replica only, and one shared bearer token across all agents — fine for a home network, not something you'd run multi-tenant.

Code on GitHub →

TradingAgents— multi-agent LLM trading intelligence, streamed live

TradingAgents runs a stack of specialized LLM agents — four analysts, bull/bear researchers, a trader, a risk team, and a portfolio manager — through the same sequence a real trading desk would use, then streams that internal debate to the browser over WebSocket instead of handing back one opaque verdict. You can ask follow-up questions against a finished analysis without re-running the pipeline, and watch the handoffs between agents happen live rather than waiting on a spinner.

It's a six-container Docker stack behind an nginx reverse proxy, split into a WebSocket API service for single-ticker analysis and a separate portfolio service so multi-holding scans don't block ad-hoc requests. A scheduler daemon triggers nightly runs (10 PM ET weekdays) that maintain a $100k S&P 500 paper portfolio and a 7:30 AM daily options paper trader with risk guardrails; state lives in SQLite with WAL mode, and the LLM layer is swappable across 14+ providers, defaulting to Ollama Cloud.

The more interesting piece is the live “Agent Bus” feed showing inter-agent debate in real time: it runs through an optional switchboard container over its own MCP client, with a bounded queue and a circuit breaker explicitly built to never raise into the analysis — if that observability layer breaks, you lose the live feed, not the trade decision underneath it. The rest of the security posture follows the same instinct: internal service calls are checked with hmac.compare_digest against a shared token, and stored API keys and OAuth tokens are Fernet-encrypted at rest rather than left in plaintext by default.

Code on GitHub →

schwab-mcp— direct MCP access to your Schwab brokerage account

An MCP server that gives Claude direct access to a live Schwab brokerage account — quotes, positions, option chains, order placement, transaction history — through plain-language requests instead of tabbing over to Schwab's site or app. It's a fork of sudowealth/schwab-mcp; the core tool definitions and Schwab API integration are inherited, but everything needed to run it as an actual always-on service — Docker packaging, a persistent on-disk token store, background token refresh, a stateless HTTP transport — was built on top of that base.

15 tools across five categories (accounts, quotes/market data, options, orders, transactions), packaged as a containerized HTTP MCP server where each request spins up and tears down its own server instance, so no session state lives in memory between calls. It self-throttles to Schwab's API limit — 100 requests per 60-second window, with 3 retries on exponential backoff — and refreshes its access token every 10 minutes in the background so a call never fails mid-session on expiry.

The real constraint here came from Schwab's OAuth design, not the code. Access tokens last roughly 30 minutes and refresh silently, but the refresh token itself expires after 7 days with no API path to renew it — only a browser-based re-auth. Rather than let that fail silently, the server exposes a /health endpoint reporting authenticated true/false, so the one unavoidable manual step (log back in once a week) is a visible, deliberate checkpoint instead of a surprise outage.

Code on GitHub →

RAG— multi-user document Q&A, self-hosted

Self-hosted, multi-user document Q&A: upload PDFs, text files, or URLs into named, isolated libraries, then chat with an AI that answers only from what's actually been ingested, with clickable source citations and one-click document download. Libraries don't cross-contaminate — each is its own Qdrant collection — so unrelated document sets can live in the same instance without ever mixing in a retrieval query.

FastAPI with async Gunicorn workers, Qdrant for per-library vector storage, PostgreSQL/SQLAlchemy for auth, and Redis+RQ running ingestion as background jobs so uploads don't block the request thread. Embeddings run through BAAI/bge-large-en-v1.5 via sentence-transformers; the LLM backend is switchable from the admin UI between a bundled Ollama container and OpenAI, Anthropic, or any OpenAI-compatible endpoint.

The interesting call is the MCP companion: instead of building MCP support into the Docker image, it's a standalone client (mcp_server.py) that authenticates to the already-running API over plain HTTP, with its own separate requirements-mcp.txt so the mcp/httpx dependencies never touch the production container. The same instinct shows up in the network layout — only the FastAPI container publishes a port to the host; Postgres, Qdrant, Redis, and Ollama are reachable only inside the Docker network.

Code on GitHub →

gsd-browser-mcp— headless Chrome over MCP

gsd-browser-mcp gives Claude and other MCP-speaking agents actual hands on a web page — navigation, clicking, form-filling, JavaScript execution, and screenshots — instead of leaving them stuck parsing static HTML or waiting on a human to drive the browser. It runs a real headless Chromium instance in Docker, so an agent can work through logins, dynamic content, and multi-step flows the same way a person would.

The whole surface is one MCP tool, gsd_browser_run, served over HTTP behind a bearer-token check; the caller passes it a subcommand — navigate, snapshot, screenshot, click-ref, fill-ref, eval — and each call spawns a gsd-browser child process that streams its result back, with screenshots returned as base64 PNG. It runs as a non-root container user, deployed as one service in a larger shared MCP stack alongside a companion cloud gateway for remote connections.

The interesting design call is how element targeting works: snapshot returns a map of stable refs for the page's interactive elements, and click-ref/fill-ref act on those refs directly instead of CSS selectors — so an agent's actions survive DOM churn that would break a selector-based approach. The other deliberate tradeoff is Chromium running with --no-sandbox to work inside Docker at all, with the non-root container user standing in as the compensating control instead of the browser's own process sandbox.

Code on GitHub →

Property Search— automated MLS listing discovery

Real estate agents managing multiple clients end up manually re-checking Redfin, Zillow, and Realtor.com against each client's criteria, then emailing out anything new by hand. Property Search automates that loop: it runs each client's saved search on a schedule, filters against a wide set of criteria (price, beds/baths, square footage, property type, radius, listing age, days on market, HOA fees), and emails only the listings that are new since the last run.

Backend is Python 3.11 + Flask, with APScheduler driving the background search jobs and the HomeHarvest library (pinned to a fixed version) pulling listings across all three sources in one pass. Each client gets an independent filter set and alert schedule via config JSON files, with Nominatim geocoding and OpenStreetMap handling the map view. It ships as a Docker Compose stack with no database — state is a CSV listing log, a JSON “seen” tracker, and an app log file.

The dedup logic is the real engineering constraint here: none of Redfin, Zillow, or Realtor.com expose a public listings API, so the scraper library is doing the work, and that means listing identifiers and page structure can shift without warning. Pinning the scraper dependency to an exact version and tracking “seen” state locally in JSON — rather than trusting the source sites to give stable IDs — is the deliberate hedge against that fragility.

Code on GitHub →

dibbs-needle— federal RFQ screener, built and concludedConcluded

Built a scanner to find profitable DoD parts-resale opportunities in DLA's DIBBS system. Two weeks in, the data said no — DLA already sells most items below retail, and the technical-data-package locks turn most of what's left into a sole-source trap. So we killed it.

The tool itself worked fine: a daily federal feed ingest, a 6.57-million-row historical award corpus across 46 agencies, local-LLM triage, and an adversarial review pass that caught a 13x data error before it ever shipped.

The real finding wasn't about parts — it's that this kind of scanner only works where a government actually publishes award history. That's what ruled state and local procurement out entirely, cleanly, before a dollar got spent chasing it.

This is the actual service: turning “should we even do this” into a real, data-backed answer in weeks. If you've got a question like that, reach out.

Code on GitHub →

[ where this comes from ]

Before any of this, I spent two decades in the Gulf of Mexico offshore industry — starting as an unlicensed engineer doing scheduled maintenance and troubleshooting on heavy-use marine equipment, working up through the ranks to Master, commanding vessels from 90 to 310 feet. Same instinct either way: understand the system well enough to fix it under pressure, then earn the authority to run the whole thing.

As captain, that meant running dynamic-positioning station-keeping across multiple DP systems, mooring tankers to single-point systems, coordinating with ROV and dive teams on subsea work, and delivering vessels internationally. Every day involved direct client interaction, not just running the boat — the same operational-plus-people mix that shows up in how I run infrastructure now.

I earned a B.S. in Information Technology Business Management while off watch and at home between hitches, not a career break. Build the actual capability first, credential it after — that's the same pattern behind everything on this site.

[ work with fathom works ]

Available for contracts and consulting. If you're building with MCP, running agent pipelines, or need a system that doesn't rely on a SaaS subscription — reach out.

No newsletter, no noise — this goes straight to Fathom Works.