Review of the engine by Claude Code yielded 11 bug-fixes. The good, the bad about the experience, how you can do this in your own codebase, Docker SBX and more

Posted on

PLY point cloud. with proper colors and opacity
PLY point cloud. with proper colors and opacity
PLY point cloud. with proper colors and opacity

I gave Claude a long-running task: Review every file of Castle Game Engine.

The process found 11 “real” bugs (something was indeed a bug in the engine, and it could be a bug in real-life applications using the engine) which we promptly fixed. So I’m happy:) See the “Detailed Stats” section at the end for all the numbers.

I will describe the process below, to give some pointers how to do it on your own codebases. In short: fine-tune the instructions to get quality reviews, watch for agent trying to avoid doing real reviews, use Docker SBX to run securely unattended.

Note: If you want to know my general thoughts/experience about using AI with Castle Game Engine, see AI guidelines for Castle Game Engine. A short version: let’s work to gain understanding / be smarter thanks to AI, and not to lose understanding / be dumber. AI can do impressive stuff, but can also be terribly unreliable — in fact the post below is another good example of both of those facts being true at the same time.

For some independent AI opinion that I agree with, see links at the bottom of our guidelines, and also I recently read from a creator of open-source AI harness Pi “Thoughts on slowing the fuck down”.

Motivation: AI reviews (subset of them) are useful

  1. AI reviews of commits/PRs by Claude are useful in my experience. Using commands like review staged, review unstaged, review unmerged is consistently giving me useful suggestions how to improve the code before I push it.

    I have to emphasize that by useful I mean that they contain useful bits. Of course they are also filled with nonsense — AI misunderstanding what the application/engine around it does, misunderstanding differences between FPC/Delphi or particular platforms, suggesting bad approaches (always with confidence), suggesting “defensive” coding techniques that would actually hide problems instead of keeping the flow validated…

    But if you’re prepared + capable of filtering out the nonsense, you’re left with useful observations how to improve the code. AI reviews do sometimes note a real improvement or even real bug-fix that my own eyes didn’t catch — that’s why I use it. It’s a special case of “many eyeballs make all the bugs shallow” rule, here AI is another set of eyeballs.

    ( This of course also deserves a disclaimer: Don’t write bad quality code just because you can rely that “AI review” will smooth it out. It will not, it will not capture all the wrong edge-cases if your design is flawed, it will not do the thinking for you. Use AI as a helper, not as replacement for your own thinking/understanding. )

  2. So, why am I using AI reviews only for new code that I commit? Let’s review all the past code!

  3. A bonus note about security, especially if you develop an application where security is a concern (you consume untrusted input, from network or game MODs — see how this applies to games / game engines too): this approach could be focused to perform a “security audit”.

    You don’t need Mythos to do it:) And, to be serious, the bad actors will do such review of your code, esp. if you’re open-source and your code is just public. So you better do the audit yourself, and fix the issues before they are exploited.

How I did this: on tuning the reviews quality/verbosity and Docker sbx

The details how I set this up (so that you can consider doing this for your own codebase too):

  1. Initial prompt. At the start, I asked to review the engine, file by file, starting from src/ and provide a review for each file.

    Note: Our engine already includes CLAUDE.md to help Claude follow our rules better. If you don’t have such file, I would recommend to create and maintain it — it really helps to “steer” Claude in a good direction. To make it available to non-Claude agents, use AGENTS.md and point to it from CLAUDE.md.

  2. Fine-tune to get useful reviews. It took some fine-tuning to make the initial prompt really useful.

    At the beginning, it tended to produce overly-verbose and useless reviews — often discussing with itself (like “Bug! X does Y. Oh, no wait, it is actually OK. Not a bug”.) or pointing to not important details (to give it credit, it sometimes flagged such notes as nit-picking indeed).

    Instructing it to give more concise reports… resulted in getting simple review “No definite bugs found.” for all engine files:) Well that’s also useless, of course.

    In the end, we found a middle ground, although effectively I cannot share with you “just a single prompt to do this”, because the end result is a conversation and pointing into examples what to do / what not to do. For some files, I got “No bugs.”, for some others I got txt files with 1-2 issues to correct.

    The point is: you need to look at initial reviews, and consider if they are too verbose/succinct, and give feedback to steer it in the useful direction. Otherwise browsing a 4000 sloppy reviews will be a huge pointless job for you.

  3. It was worth it! The issues detected (after the fine-tuning above) are genuinely useful reports. Real, meaty bugs that I missed over the years. E.g.

  4. Fixing them manually or not? Initially I considered letting Claude also fix the issues by itself.

    • But in the end, I fixed most of them manually (i.e. I’m still using AI code completion through GitHub Copilot, but not AI agent) since the AI agent “fixes” mostly required fixes on top of them. It didn’t add automated tests, it didn’t make code clean (centralizing logic). Reviewing + fixing agent work was taking me longer than “just doing” them in the way I want from start.

    • And some reviews were plain wrong. E.g. it wanted to break TCastleTouchControl by limiting speed, because it wanted to adapt visual clamping to speed clamping — without understanding that the current version is actually what we want, more functional to use.

  5. Place reviews in .ai-review subdirs. I started by instructing Claude to show me the review, and only continue once I acknowledge. This was of course not good in the long-run, it needlessly blocked the work, so I switched to “put each review in a txt file alongside the source, and don’t wait for my confirmation to move on”.

    In the end I switched to “put each review in a .ai-review subdirectory, e.g. review for src/foo.pas goes to src/.ai-review/foo.txt“.

    This allowed me to easily ignore these reviews in version control, by adding .ai-review/ to GIT exclusions (e.g. in .git/info/exclude, so the exclusions themselves remain private to me).

  6. Exclude auto-generated and 3rd party stuff. I fine-tuned which files to include / exclude. I did want to go through entire engine (sources, examples, tools etc.). But I excluded auto-generated files (like LPK, DPROJ, auto-generated per-node includes in src/scene/x3d/auto_generated_node_helpers/) and 3rd-party units code (like Vampyre Imaging).

  7. Watch it, as it tries to abort / avoid doing the work! I needed to push Claude to actually do all the reviews, unattended. I used /goal to enforce it, and it worked… only to some extent.

    Claude started to avoid work by doing “shallow” reviews of most files — and happily reported “No bugs found” for ~1000 files while admitting it only scanned them. (grepped for potential issues, not read). I instructed to use “deep review”, and again enforced it using /goal.

    Then Claude lied to me that it “finished the work” while it turned out it only processed 3 sub-directories in src and the rest was quickly scanned. Not surprisingly, the “scanned sub-directories” did not contain any issues according to the review. This is hilariously unreliable:) I just kept looking what it’s doing and asking for the “deep review” when I saw it tries to mass-qualify a bunch of files as “No bugs found”.

  8. This used multiple 4h sessions. This was a very long-running task. Multiple times I exhausted my “tokens in 4h window” limit from Claude Code. I was ready and OK for this, I just waited, and later/next day said “continue”.

  9. Docker SBX rocks for unattended agent usage. I wanted it to run without interaction, since otherwise I’m a human bottleneck and I mostly just accept the commands executed. (some of the commands could not be auto-accepted by a useful pattern.)

    So I wanted to run with --dangerously-skip-permissions, but that’s something you should never do without being in a secure container. ( Really, don’t ignore this warning. Esp. for longer-running tasks where you don’t observe everything the AI is doing. Letting it run with --dangerously-skip-permissions will lead to a disaster!, weird things will happen at least in your repo (and maybe beyond) and you will not even know what/why happened. )

    Solution: I run the session of Claude inside Docker’s sbx which is a fantastic tool to run AI agents in a sandbox. Docker containers are obvious solution for isolation of agents, and sbx makes using them for this specific purpose a breeze. It creates containers with read-write mount on your disk, so you can inspect the work (and even commit+push) comfortably on your host system, while AI runs in a really isolated environment.

    I highly recommend this approach for any longer-running AI tasks. It’s really a relief to just run inside sbx with --dangerously-skip-permissions, so you’re no longer a dummy clicking “yes I allow” (and constantly break your work to look at Claude state) and you can just let it run. You don’t specifically need sbx for this, since any virtualization Docker-like solution could achieve this — but I found sbx to just fit me right out-of-the-box, and I already use Docker for other stuff so this felt “I’m at home” for me.

  10. Moving conversations from outside to inside SBX. As I didn’t start with the sbx approach, I started with a normal session outside sbx -> so then resumed work in a session inside sbx. I wondered about copying around ~/.claude to make this resume smooth, but in the end it was enough to carry the “current review state” in a collection of Markdown files, and just point the new session to them, and also copy a bunch of “memory files”.

All in all, I do recommend this process, I guess, to everyone if you have some “tokens to spare”. As pointed above — the process had flaws, you need to fine-tune the verbosity/quality of the reviews, you need to make sure it’s really doing it (and not lying to you). But it also had real gains — real, user-affecting bugs have been found and fixed in the engine thanks to this.

Detailed stats

If you’re curious, detailed stats and links to what was fixed:

And that’s it 🙂 Thank you for reading.

If you like what we’re doing, please support the engine development. Thank you!

Comments on the forum ➤

AI usage guidelines and thoughts updated, and… test of vibe-coding with Castle Game Engine

Posted on

Castle Vibes screenshot - castle
Castle Vibes screenshot - NPC
Castle Vibes screenshot - NPC talk
Castle Vibes screenshot - trophy

As most of us, I spend lately considerable amount of time researching and talking about AI implications (for coding and beyond).

It’s a big subject. The technology offers us various applications, and various new ways for misuse too.

I think the following statement manages to summarize my hopes + concerns best: When working to solve the problem, we should be gaining understanding, not losing it. So use AI to get smarter / faster, not to loose understanding / decrease code maintainability.

  1. I have updated our AI usage guidelines with this and many other statements — both positive usage of AI (e.g. “review my uncommitted changes”) and warning about negative (trusting the AI designs, which may go in unmaintainable direction without supervision).
    • I think we can use these tools carefully (understanding AI proposals, and correcting / filtering out bad ideas) to our benefit, and I was experimenting with doing it on many projects now (including our engine).

    • Being careful is certainly warranted. Committing code that “looks good on the surface”, but fails to scale, fails to be maintainable, or is not understood -> that’s a road to being unable to develop the software in the future (both with AI and with your own brain).

  2. Additional reading material:

    You all likely have read a ton of AI things on the Internet lately 🙂 There is a lot of noise, over-hype (no, AI is not a replacement for human developers, and I don’t think it will ever be, though our role may change; remember there is no “production” app vibe-coded as of now) and hate too. And some hate I agree with (AI companies made a huge copyright theft on unprecedented scale; they suck) but it doesn’t mean that AI is useless as a tool.

    Some of the references I agree with:

  3. I have committed CLAUDE.md into the engine repository — it contains a number of instructions to steer Claude Code into following our practices.

  4. Finally, something you’ve been waiting for:) I have tested “vibe coding” an application using Castle Game Engine. Even if I explicitly don’t think it’s a good way to make a game, it was a fun thing to try!

    • Head on to https://github.com/michaliskambi/castle-vibes/ for the complete code and data, screenshots, and a long README with observations.

    • Builds (Linux, Windows, web) are available.

    • It is maybe the worst game I ever made/played, but it is playable, which is impressive in itself. You can walk around a winter scenery with a 3D castle, fog, falling snow, some forest, minimap. You can get a quest to slain 6 goblins, and do it, and at the end you get the reward – trophy appears.

    • Observe many things that AI did correctly, but also many done wrong. Various bugs, generating UI using Pascal code, generating models using Python, unoptimal (but still looking cool for this demo!) snowflakes.

    • It’s not a game I designed or control. It’s a random game. Features, look, details (placement, quests) of everything -> is an outcome of a random process, as you can only specify so much in ~15 paragraphs in English. We can speculate how much the quality will improve “out of the box” with better AI agents in upcoming months/years, but ultimately if I want to control over the game -> I will need to put much more work into spec/prompting or “get my hands dirty” and just edit the code/data myself. At some points, “just edit the code/data myself” will be more efficient, at the end we’ve made the engine to be easy to use. Pascal code is the most precise “spec” 🙂 So I don’t see the future as “just vibe code me this app”. The real applications will be a result of iteration on the solution with both AI and manual work.

    • Oh it’s such a mixture of good and bad feelings 🙂 Please read the full README with observations.

Have fun using our engine and please support the humans behind the engine 🙂.

Comments on the forum (5) ➤

November improvements: huge animation upgrade, guidelines about AI usage, Codeberg mirror, various fixes

Posted on

Displaying a crowd of characters animated using skinning in glTF
Skinned animation of an alien
Skinned animation of a fox

We have a few things to report from November. Enjoy 🙂

  1. We have merged a big branch with numerous improvements to our animation handling (skinned animation and other). The important new functionality is documented here. This merge features:
    • Skinned animation loaded from glTF is now performed on GPU (mesh is deformed using shaders). This allows such animations to be loaded much faster, take much less memory, and be more efficient at the same time. You can animate a big crowd of characters using this technique.

    • The same efficient skinned animation can be defined in X3D using new Skin node.

    • animate_bones_by_code example was updated to showcase this, including skinned animation and huge crowd test.

    • We have fixed loading/saving of matrix values from X3D.

      Testcases:

    • The OptimizeExtensiveTransformations flag is deprecated and does nothing now, because the related optimization is now done always, unconditionally, and for all animations (including Skin, H-Anim, and regular animation of transformations without the skin). The optimization has been reworked to be “always a gain”, by updating a set of sub-trees.

    • The InternalFastTransformUpdate flag does not exist anymore. This optimization is also now done always, unconditionally, for all animations, and it benefits all animations of transformations (with or without skinned animation).

    • I have a longer version of this news… but I also want to extend this work even more, in particular to pass joints information using a texture. Current implementation limits number of joints that can be handled by a shader: when the joints count is > 128 it falls back to CPU animation. We can make it better and handle almost ~any number of joints by passing their information in a different way.

  2. We have published guidelines for AI usage in Castle Game Engine.

    They are primarily for people who contribute to the engine, but the guidelines should also serve you well if you use AI in your own projects. To give a summary of my view: AI can be useful, but don’t trust it as it can also be wrong (and confuse you much). Don’t use AI to generate big unreviewed pieces of code or documentation, as they will likely have numerous problems. Start by using AI to generate smaller pieces that you understand + review + improve before committing, like for “code completion”.

    Go ahead and read the article, I go there into more details 🙂

  3. We maintain now a mirror of our repositories at Codeberg. GitHub is not your only choice 🙂 We intend to explore it more, including their CI/CD as alternative to GitHub Actions.

  4. Improved reading “extra” glTF data into X3D metadata, to put JSON contents into X3D metadata when we don’t have a better option.

  5. glTF reading is also a bit faster, as we use bounding box from glTF “accessor” (no need to calculate it on our side in some cases).

  6. Fixed and improved “Edit -> Visualize H-Anim Joints”, “Edit -> Visualize Skin Joints” in Castle Model Viewer.

  7. Workarounded Delphi 13 crashing when building our engine in release mode.

  8. Important fix for processing textures from data URI (caching was way too agreessive resulting in wrong textures used).

Comments on the forum (2) ➤

Example talking with OpenAI (ChatGPT) assistant using Castle Game Engine (from desktop or Android)

Posted on

Castle Game Engine - Talking with OpenAI assistant

I was playing with OpenAI “assistants” lately. Assistant acts like a ChatGPT with which you can talk, but adjusted personally to you — you can instruct the assistant to answer your questions using your guidelines, possibly using a database of your uploaded files and other information. For example, I can instruct assistant to “Call the person asking the question “Gary” and add a cat joke to every answer.”. I can also upload Castle Game Engine documentation in AsciiDoctor format.

Naturally, I thought “How hard it is to actually use the OpenAI API to do this? Can I do this from Castle Game Engine application?”. Turns out it was super-trivial 🙂 Took me 1.5h to have a basic version working. Later I extended it to support mobile and have better UX.

Here’s the result: https://github.com/castle-engine/castle-openai. Use this code as you please. As an example of talking with OpenAI, or just as an example of using TCastleDownload to communicate with any HTTP REST service. See the screenshot to get inspired 🙂

In related news, I have merged a pull request to support custom HTTP headers and request body on Android by Vlad (phomm). This extends the capabilities of our TCastleDownload on Android — which was critical to also make this example run smoothly on Android. Thank you!

Note that I don’t provide binaries for this application. You have to follow the README — get your own API key, create your own assistant, fill their ids as shown in the README. Then compile your own version of this application. Note that using OpenAI API this way is a paid feature — you will need to put some credits, and each query will use it.

Have fun! Like it? Please support us on Patreon!

Comments on the forum ➤