How I work
I build software that solves real business problems. I work close to the people who own the process, learn their domain first, and own the solution end to end: build it, ship it, run it in production, and hand it over so the team can own it.
My work spans full-stack systems with AI, AI process automation, platform integration, cloud infrastructure and DevOps.
Software engineering
On the engineering side, I build React and TypeScript front ends, backend services, microservices and data pipelines. I apply Domain-Driven Design (DDD) and work with API contracts, databases, authentication, CI/CD and production reliability. I care about clear boundaries, useful documentation and measurable behaviour.
AI engineering
As an AI engineer, I build agents and workflows on language models, train models myself, and put them into products. I focus on the system around the model, not just the model. That means structured outputs, Pydantic validation, LLM tool use, narrow permissions, prompt-injection safeguards, retries and fallbacks, evaluation, and human review for decisions that matter. I have a Master's in Data Science and Artificial Intelligence. My thesis on text-to-image generation with GANs and contrastive learning outperformed the state-of-the-art models of that time.
Communication
What sets me apart is communication. I explain technical trade-offs in business terms and keep non-technical stakeholders aligned on decisions. I have a background in leading a team and building a company subsidiary from the ground up, growing it from 6 to around 20 people.
Forward-deployed by default
Full-stack software engineering
My work spans full-stack systems with AI, AI process automation, platform integration, cloud infrastructure and DevOps: microservices and data pipelines with Domain-Driven Design, API contracts, databases, authentication, CI/CD and the React front ends on top, owned from the first conversation to on-call.
For me, forward-deployed isn't a separate job. It's how I do software engineering: start where the work actually happens, and stay until it runs.
Out of respect for client and company confidentiality, I share only a high-level view of this work
Process
- 01
Listen where the work happens
I sit with the operators and leads who run the process, because they know where it really breaks.
- 02
Write the scope down
What we're solving, how we'll know it worked, and what we're leaving out for now.
- 03
Build the smallest slice that works
One real flow through every layer, end to end, before anything gets polished.
- 04
Prove it
Tests, acceptance criteria agreed with the people who'll use it, and load tests where traffic matters.
- 05
Ship and run it
CI/CD to Kubernetes, dashboards and alerts from day one, and I'm on call for what I ship.
- 06
Hand over and feed back
Docs and runbooks so others can run it. Anything reusable goes back into the platform instead of staying a one-off.
Four kinds of work
Number Verification API
A Java and Spring Boot API that verifies phone numbers against external sources. Each kind of data has its own caching rule, and a circuit breaker with graceful degradation keeps a slow source from blocking the whole flow. The API is contract-first, and outside systems are stubbed in tests, so nothing depends on a live service.
Routing configuration
A React and TypeScript tool, backed by a Kotlin and Spring Boot service, that lets operators manage routing rules and priorities over HTTP and ENUM without asking an engineer. Rules are stored as data, apart from the logic that applies them. Priority conflicts show in the UI and are checked again on the backend. Every change is audited, and the previous state can always be restored.
Review before commit
A tool that replaced a manual data process. Validation lives in the backend and returns field-level errors. Operators review exactly what will be written before anything is saved, and every action is audited. I shadowed the people doing the work and ran the tool alongside the manual process until the results matched.
ENUM lookup API over DNS
A Java and Spring Boot microservice that finds and contacts external clients through DNS, with ENUM number-to-service lookups. It needs no proprietary SDK or special firewall rules. Caching follows the records' own TTLs. Failures are classified: a missing record is a hard failure, and timeouts retry with exponential backoff. Tests run against a local DNS server in a container, never live DNS.
See it inMeridian
In production
AI-assisted engineering
At tyntec I use GitHub Copilot and Claude every day, as approved tools within the company's rules. They make me faster at the parts of the job that were never the hard part.
I own every line I merge, whoever drafted it. So my process is built around checking the output, not trusting it: I read every line, run the tests and review the diff as if a colleague wrote it.
Where I use it
- Exploring unfamiliar code
- Boilerplate
- Test drafts
- Documentation
- Mechanical refactors
Where I don't lean on it
- Architecture and trade-off decisions
- Auth and security-critical code
- Anything I can't verify
Boundaries
- Approved tools only, within the company's rules.
- No secrets, customer data or personal data in prompts.
- Nothing merges without passing tests and a human review.
In my own projects
AI engineering
I build agents and workflows on language models, and I focus on the system around the model: validated outputs, narrow permissions, a guard that checks every answer, a person who approves what matters, and an eval against what the AI replaces.
Where hand-written rules reach their limits, I bring in AI workflow automation and measure it against those rules. It is held to the same reliability bar as the production systems I run.
Process
- 01
Map the workflow first
Who does what today, where it goes wrong, and what a mistake would cost.
- 02
Pick the simplest shape
If a rule or a fixed pipeline can do it, I don't use an agent.
- 03
Few tools, narrow permissions
Each agent gets only the tools it needs, enforced in code, not in the prompt.
- 04
Validate everything that comes back
Structured outputs are checked against a schema before anything acts on them.
- 05
A person approves what matters
Agents read, analyse and propose. Anything that writes, sends or spends waits for approval, and text from documents or users can't trigger an action on its own.
- 06
Trace, test, prune
Every step is logged so a decision can be replayed. Failures become test cases, and a tool or agent that doesn't earn its place is removed.
What that looks like
Inputs screened
Inputs are checked for prompt injection before any model call.
Failures handled, not patched
A malformed answer is rejected and retried, then falls back or goes to a person.
Models chosen deliberately
By capability, latency, cost, context and privacy, and swapped when a better fit ships.
Built for human oversight
Data minimisation, access control and a traceable record of every automated decision.
LLM toolkit
See it inMeridian
From model to product
AI product engineering
I take a model from idea to a feature people use: choose or train the model, build it into the product, and measure whether it actually helps.
In my master's research I trained a text-to-image GAN with contrastive learning in PyTorch. In Meridian, a local language model reads courier contracts inside the product, and an eval decides whether it stays.
Process
- 01
Start from the user problem
What should the product do better, for whom, and how will we know it does?
- 02
Choose or train the model
An existing model when it is good enough; training my own when the task and the data call for it, as in my thesis.
- 03
Data and metric first
A labelled set and a metric before anything ships: FID and R-precision in my thesis, precision and recall in Meridian.
- 04
Build it into the product
An API with a fixed output format, a fallback when the model is slow or wrong, and a UI that shows what the model did.
- 05
Measure it in use
Compared with the product without the model. It stays only if it measurably helps.
- 06
Keep it changeable
Versioned models and prompts, cost and latency tracked, and a clear path to swap the model when a better one ships.
See it inMeridian Master's thesis
Software · AI-assisted · AI · AI product
Underneath all of it
The same engineering rules hold whether the code runs a Kafka pipeline, comes from an assistant or acts as an agent. Each card shows which parts it applies to.
Platforms and integrations
Pick the transport per integration
Kafka where producers and consumers must stay decoupled or replay events; plain REST where the caller needs an answer now.
- Software
- AI
Make failure boring
Idempotent consumers, retries with backoff and a dead-letter topic, so a bad message is parked instead of lost.
- Software
- AI
Contract first
The OpenAPI contract is agreed before the code, including the public API specifications integrators build against.
- Software
- AI-assisted
- AI
Identity in one place
Keycloak with OAuth2 and OpenID Connect, not auth logic scattered through services.
- Software
- AI
If it isn't on a dashboard, it isn't running
Request, error and duration metrics, dashboards and alerts with an owner, from the first deploy.
- Software
- AI
Software architecture
Boundaries follow the domain
Service splits come from Domain-Driven Design, so each service owns its data and can change on its own.
- Software
- AI
Validate everything that comes back
A Kafka event, a partner response or an LLM answer: nothing is trusted until it has been checked.
- Software
- AI-assisted
- AI
Write the decision down
Options, trade-offs and the reason, in a short record the team can find later.
- Software
- AI-assisted
- AI
Boring until proven otherwise
Well-understood tools and patterns unless there's a measured reason to choose something new.
- Software
- AI-assisted
- AI
Wrap before you replace
Legacy gets a seam and tests first, then a gradual swap, one small change at a time.
- Software
- AI-assisted
See it in the work
Every project page shows these steps on a real build, with an honest status.