January 2025 – June 2026 (~18 months)
CircularAI
Senior Software Developer — de facto technical lead
- .NET / ASP.NET Core
- Entity Framework Core
- SQL
- React
- TypeScript
- SignalR
- WebSockets
- Elasticsearch
- JWT auth
- AI API integration
An AI-powered platform helping cities and public bodies turn circular-economy strategies into structured missions, projects, and measurable actions — spanning missions, procurement, an AI assistant, and more.
Team
- 1 CEO / project manager
- 2 senior backend-oriented developers, including myself
- 2 React developers
- 1 full-stack developer
- 1 tester
- Close collaboration with a separate AI team on the AI integration
Challenge
CircularAI was developed in a highly constrained environment. The initial phase was particularly intense — roughly a month and a half to deliver a significant amount of functionality, while requirements were still evolving and several team members were unfamiliar with parts of the stack.
Specifications were sometimes delivered incrementally: we'd build functionality, then receive new requirements that invalidated a substantial part of the previous implementation. The AI integration itself was new to most of the team.
During the initial month I worked approximately 2.3x my contracted hours, based on our time tracking, and took compensatory time off afterward. The larger challenge was maintaining a coherent system while requirements, implementation, and team capacity were all changing at once — without letting the codebase become a collection of disconnected solutions.
Solution
Building a dedicated AI communication layer
Each developer integrating an AI feature was effectively re-implementing the communication protocol themselves, creating duplication and inconsistent implementations. AI communication was clearly going to be a core capability, not a one-off integration.
I designed and built a dedicated service, internally called Cai, as the common communication layer between the application and the AI system — handling the AI API connection, WebSocket communication, response streaming, background execution, error handling, persistence, response adaptation, and delivery to users via SignalR.
Features could define the request they needed and rely on the shared service for everything else. By the end of the project this was the standard mechanism for AI communication, used across roughly 25–50 integration points.
Designing for long-running AI operations
Some operations sent large files (around 10 MB) to the AI system for analysis, taking several minutes to return a structured JSON result — unsuitable for normal request/response handling.
I designed a background-task mechanism: the application creates a persistent task record, starts the AI operation independently, and gives the AI system a callback endpoint to notify the API when processing completes. This decoupled the user's request lifetime from the AI computation's lifetime and gave the app a consistent way to represent long-running operations generally.
Making real-time communication easier to use
For the React frontend consuming SignalR events, I designed a provider/context-based subscription pattern where a component subscribes to a named message with an action to run when it arrives, automatically unsubscribing on unmount.
Frontend developers implemented it from my architectural design and examples. Since my own React/TypeScript experience was still developing at the time, I used AI tooling to iterate through implementations and communicate the architecture precisely.
Taking ownership across the platform
I personally implemented major areas including Missions, Projects, Procurement, authentication and authorization (JWT access/refresh tokens), backend APIs, data modelling, Elasticsearch functionality, and parts of the workflow and background-processing systems, and took over an existing workflow implementation from another developer.
Being involved across so many areas meant I could usually see the impact of a change across the system, and became the person who found solutions to difficult problems and took responsibility for new subsystems like Elasticsearch.
Making implementation easier for other developers
A recurring principle was to remove ambiguity from the people who'd use the systems I built — developers shouldn't need to understand the difficult architectural decisions behind a system to use it correctly.
The same principle applied to specifying work: I used structured templates and AI-assisted drafting to turn informal requirements into clear technical specs, reducing the ambiguity developers had to resolve themselves. The underlying idea: resolve the problem and the ambiguity once, so the next developer doesn't have to.
Result
CircularAI reached production and was deployed before I left Swappsi in June 2026, used by roughly a dozen customers or municipalities (exact count not verified). The Cai AI communication architecture remained in production as the standard integration mechanism for AI functionality.
More broadly, the project marked a transition in my role — I entered as a senior engineer and became, in practice, one of the central technical decision-makers for the product: writing production code, designing architecture, solving hard technical problems, mentoring developers, specifying work, and maintaining a system-wide understanding of the platform.
It reinforced something now central to how I think about engineering: good architecture isn't primarily about elegant abstractions — it's about reducing complexity for the people who have to build and maintain the system. The best abstraction is often the one that makes the right thing obvious.
A reference from Swappsi's CEO (May 2026) independently describes this work as demonstrating strong senior-level technical ability, structured problem solving, sound architectural and implementation decisions, clean and maintainable code, effective use of AI tooling, knowledge sharing, and proactive contribution to the wider team.
