Software Engineer • IT Support Technician • Computer Science Student
I'm a Computer Science student at the University of KwaZulu-Natal and an aspiring software engineer with hands-on project experience in C++, Java, Python, and C#, with a growing focus on the architecture and design of agentic AI systems.
My biggest project so far is Confident Agent, where I led a team of five in designing an agentic AI system that catches hallucinated REST API calls in LLM-generated code before they reach the user. I shaped the architecture, from how the model, the verification tool and the release decision fit together, to the benchmark and independent evaluator that tested it. The idea that guided it: a trustworthy agent isn't one that is always right, but one that knows when it shouldn't be trusted.
Beyond that, my projects range from building a multi-threaded C++ inventory system for a simulated logistics network, to fine-tuning a BERT model on 60,000 Steam reviews, to working with a team of five on CoreBuster, a sci-fi first-person shooter in Unity 6 with 18 custom shaders, NavMesh enemy AI and a ray-traced ambient occlusion pass, to writing a music player that analyses audio itself rather than trusting metadata. I like projects that force me to actually understand how something works under the hood.
Alongside my studies, I've spent over five years in IT support and client-facing sales at RM Graphic Solutions, diagnosing hardware faults, building and configuring custom PCs, and managing client accounts from enquiry through to delivery. That combination means I approach software with both a builder's curiosity and a support technician's instinct for what actually breaks in the real world.
Come take a look around. I'm always keen to talk about a new project or opportunity.
A high-performance C++ system built for a fictional client, Nexus Logistics, to centralise inventory and order processing across 5 warehouses that had previously each run their own inconsistent management system. The design follows a producer-consumer model: five warehouse threads load orders into a shared queue, then a user-selected number of worker threads (1-32) drain and fulfil them concurrently against a central inventory.
I led the project and was responsible for the high-level system design: the overall producer-consumer architecture and how the OrderPool, InventorySystem and thread pipeline fit together. I then built the entire CLI: the full 9-option menu, every product/search/sort sub-menu, and the input-validation layer (safe int/double readers that recover cleanly from bad input instead of leaving cin in a broken state). Together these cover all the user-facing flow that sits on top of the class hierarchy the rest of the team designed.
I also took the AnalyticsManager through a full overhaul, from a handful of basic totals into a proper reporting engine: 18 metrics across global and per-warehouse scope (revenue, lost revenue, best-selling item, and category/type breakdowns of revenue, quantity, failure rate and average price), each exportable to its own CSV for Excel/Power BI, all runnable from a dedicated Analytics sub-menu I added to the CLI.
Product base class with Taxable, Discounted and Standard subclasses, using virtual functions so pricing logic resolves correctly through a shared_ptr<Product> at runtime.std::atomic<int> for lock-free order-ID generation.Processing 1,300 orders across a 999-product, 11-category catalogue scaled from ~20,000 ms on a single thread down to ~650 ms at 32 threads (a ~30× speedup) before plateauing as inventory-mutex contention became the bottleneck.
A full-stack database application modelling the day-to-day operations of a travelling amusement park (customer admissions and loyalty cards, employee rostering, ride/show/stall management, maintenance logging and financial transactions), all served through a role-based Java Swing front end over MySQL.
I planned the business scenario that the whole database was modelled from: working out how a travelling carnival's customer admissions, loyalty smart cards, employee roles, attractions and financial transactions actually relate to one another, before any table existed. That scenario became the spec the EERD and schema were built against.
I then built the entire Java Swing front end and its visual design. Login is a custom-painted screen I wrote directly on Graphics2D: a drifting starfield of 180 twinkling stars, 18 looping carnival “sparks”, and a slowly shifting dual-tone gradient behind a rounded glass card, all hand-animated on a Swing Timer, no game engine or extra library involved. On top of that I built the generic EntityConfig-driven CRUD engine that every other screen is built from, the role-based routing between the four account types, the four-step Sales pipeline, and the Reports screen.
EntityCrudPanel builds the form, grid and SQL for all 21 entities: adding a new entity is a metadata entry, not a new screen.All queries are parameterised throughout, and MySQL's own per-role privileges provide a second line of defence: even a bug in the Swing client can't issue a statement the account isn't allowed to run.
A head-to-head comparison of three generations of NLP text classifiers (a traditional statistical model, a recurrent deep-learning model, and a pre-trained transformer) on the same binary sentiment task: predicting whether a Steam game review is Recommended or Not Recommended.
I led the project and, in addition to training our BERT model, built the entire data pipeline that fed all three models (extraction, cleaning, balancing and splitting) as a standalone notebook the rest of the team's model notebooks all pointed at, so every model trained and tested on identical data.
Extraction: Steam's API caps each request at 100 reviews and paginates with a cursor rather than an offset, so I wrote a loop that walks that cursor per game across 100 selected App IDs, targeting 500 positive and 500 negative reviews each. I collected by class as I went, not after the fact, because some games skew heavily positive and pulling reviews blind would have starved the negative class. Requests are rate-limited with time.sleep() to avoid throttling, and every write checks Steam's own review ID before saving, so re-running the script after a timeout or crash never reintroduces a duplicate.
Cleaning: the raw pull (~94,900 reviews) needed several passes before it was trustworthy training data: stripping reviews mangled by Steam's profanity filter (which replaces swearing with a symbol that corrupts the surrounding text on read), removing links and spam patterns that carry no sentiment signal, running langdetect per review because Steam's own language tag reflects the client's UI language rather than the review text (this alone cut 21,950 reviews), stripping emojis the tokenisers can't meaningfully use, and de-duplicating by exact text (~18,000 reviews) so the same review couldn't land in both the train and test split and inflate accuracy.
Balancing & splitting: the cleaned data was balanced to an even 60,000 reviews (30k positive / 30k negative) and split 70:30 with stratification, so class balance held in both the training and test sets.
For my own model, I fine-tuned BERT (bert-base-uncased) with AdamW, a linear warmup schedule and gradient clipping on a 6GB GTX 1060, and restored the best-validation-loss checkpoint to counter overfitting after epoch 1.
A local player for FLAC libraries, inspired by the old Samsung TouchWiz Music Square, except instead of relying on genre tags or an online lookup, it plots every track by actually analysing the audio itself. Everything runs locally: no files, tags or audio ever leave the machine.
For each track, librosa extracts tempo, loudness (RMS), onset rate, spectral centroid, and a tonality “mode score” from a chroma vector compared against major/minor key profiles. These five raw features are then z-scored across the whole library (so “loud” or “bright” is always relative to your own collection) and combined into two weighted axes: arousal (tempo-led) for the x-position and valence (tonality-led) for the y-position, each compressed to -1..+1 with a tanh squash.
The analyzer is resumable and parallelised: it samples ~60 seconds per track from ~30% in, skips already-scored files on re-runs, and falls back to a slower crash-isolated mode if a corrupt file would otherwise take down the whole batch.
Break the armour. Take the core. Choose the ship's fate. CoreBuster is a science-fiction first-person shooter developed in Unity 6 for COMP307 Computer Graphics. The player awakens aboard a malfunctioning spaceship overrun by hostile robots, fights through interconnected industrial chambers, and ultimately decides between escaping the ship or confronting its unstable reactor core.
At the centre of the combat system is Core Bust, a first-person execution mechanic. Armoured enemies contain unstable energy cores. Once their armour has been destroyed, the player can approach and execute them, physically extracting the exposed core through a synchronised animation. A successful execution restores health, but leaves behind a toxic gas cloud that creates a new environmental hazard.
The mechanic is implemented through coordinated gameplay state machines involving ArmouredEnemy, CoreExecutionTarget, CoreExecutioner and UnstableCore. Armour destruction extracts geometry from the animated mesh and converts it into physical debris rather than simply hiding the armour.
The game features four main enemy classes across nine variants, including armoured Cyber Soldiers and Elites, standard ground robots, and airborne HoverBots. Enemies use NavMesh navigation, room-aware pathfinding, line-of-sight detection, telegraphed attacks and procedural attack animation.
Enemy behaviour reacts to armour damage, electrical status effects, the player's position and the ship's security doors. Reinforcements arrive through warp-in effects during lockdown encounters.
The spaceship is designed as a continuous level with five connected zones, including a tutorial wing, workshop, reactor chamber, turbine hall and final Boss Hall. Security doors and keycards govern progression between areas, while terminals initiate lockdowns and waves of enemies.
The game offers two endings. The player can survive a timed escape sequence or enter the final chamber and dismantle the giant reactor core through a multi-stage encounter involving three consoles and destructible armour layers.
Gameplay systems are organised into separate assemblies for shared infrastructure, gameplay, artificial intelligence, user interfaces and rendering.
A custom ZoneStreamer system reduces rendering overhead by suppressing renderers in rooms that are not currently visible, while preserving physics and AI simulation. The project also includes configurable graphics quality profiles and rendering optimisations for constrained hardware.
Developed by Cosmic Studios as a five-person COMP307 group project at the University of KwaZulu-Natal. CoreBuster combines real-time computer graphics, interactive gameplay, procedural content creation, game AI and software engineering in a single playable project.
My biggest project to date. Language models write plausible code that calls web APIs which do not exist, at versions that have been retired, with parameters the provider never documented. I led a team of five to test whether an agent can stop those REST API hallucinations from reaching the user, guided by one idea: a Confident Agent is not one that is always correct, but one that knows when it should not be trusted.
I led the group and shaped the project end to end:
A local model (Qwen3.5-9B) is paired with a deterministic validation tool that parses the generated Python without running it and checks every API claim across six layers (imports, identifiers, access point, input contract, output contract and security context) against frozen, hashed OpenAPI specifications. The evidence is summarised in an Evidence-Weighted Confidence Score, and a decision policy then delivers, flags, corrects once, or withholds the code. Hard verification constraints, not the score, decide whether anything is released.
The site you're looking at right now. A single-page Jekyll portfolio with sliding panels for About Me, Projects and a full Detailed CV, all themed and colour-matched to my actual CV rather than a generic template look.
Rather than starting from a blank page, I built this on top of two open-source Jekyll templates and reworked both substantially: