AI for banking, built inside the fence.
7+ years building enterprise software for industries where failure isn't an option: banking, payments, fintech. The current focus is applied AI in regulated environments — LLM capability without sending a byte to the public cloud. Client and employer names withheld; happy to walk through any of it under NDA.
integrated
data egress
conversion lift
regulated systems
Two hireable stories, both in production.
Currently building: a high-throughput access-control system in Rust — gRPC services over MongoDB and Redis. Plus ongoing monolith → .NET microservices migrations in banking environments.
AI tools, run against a daemon I control.
Personal builds sitting on a local Ollama daemon. Embeddings come from mxbai-embed-large,
chat from whichever model fits the task. No API keys checked into anything, no provider lock-in — the cloud bridge
is opt-in via the :cloud suffix when a model is too heavy to host.
Document OCR & extraction pipeline
Ingests document scans, runs OCR, then hands the raw text to a local LLM that classifies the document type and pulls out the fields that actually matter — dates, parties, totals, identifiers. Output drops into a searchable store, not a wall of unstructured text.
Retrieval-augmented chat, end to end
The unglamorous one. Embed a corpus, store the vectors, do a kNN lookup at query time, stitch the top chunks into the prompt, send it to the model. Built to wire the moving parts together myself instead of trusting a framework — chunking, recall thresholds, and prompt budget all picked deliberately.
Terminal coding assistant, in Go
A single Go binary that talks to the local Ollama daemon and answers from inside the shell. Streams tokens as they arrive, keeps a session buffer, and stays out of the way — no browser tab, no auth dance, no leaving the terminal to ask a small question.
The Council — multi-agent deliberation
Four Claude personas — Philosopher, Contrarian, Romanticist, Analyst — argue a question in parallel. An Arbiter persona reads the four outputs and synthesizes a single answer. Dark grimoire UI, hand-drawn SVG avatars. Built to see if forcing disagreement produces better answers than asking one model twice.
Wire the pieces by hand.
// cli/chat.go — stream chat tokens straight to stdout func stream(ctx context.Context, prompt string) error { body, _ := json.Marshal(map[string]any{ "model": cfg.Model, "prompt": prompt, "stream": true, }) req, _ := http.NewRequestWithContext(ctx, "POST", cfg.Host+"/api/generate", bytes.NewReader(body)) res, err := http.DefaultClient.Do(req) if err != nil { return err } defer res.Body.Close() dec := json.NewDecoder(res.Body) for { var chunk struct{ Response string; Done bool } if err := dec.Decode(&chunk); err != nil { return err } fmt.Print(chunk.Response) if chunk.Done { return nil } } }