This page reflects my current perspectives on product development, informed by ongoing experience and learning. It will be periodically updated to incorporate new insights.

Building an AI game engine by simulating less

I started Lore in April 2026 after working on Sleeve and its Eidolon game. Lore was not a direct extraction from Sleeve. It was a separate game-engine project where I could apply what I had learned. I used ideas from LangGraph as an initial reference, then kept only the parts that fit the project.

The first design tried to simulate every nearby non-player character separately. Each character received its own context about what it knew and perceived. A model decided what each character wanted to do, and the engine combined those decisions into the next scene. A turn could take up to two minutes because it required several model calls. It was also expensive. Players do not want to wait that long for every action.

The current version uses freeform text instead of options. The player can enter anything. One model call interprets the message and turns it into a plausible character action using the possibilities supplied by the engine. Another writes the narration and dialogue using only the selected context. Dangerous or consequential actions can still move into a more detailed resolution process. The average turn now takes about 20 seconds.

Ruby owns the game state and rules. A player's message expresses intent, but it cannot declare an outcome or invent facts. Models interpret that intent and write prose without changing canonical state directly. Their output must match a structured contract before anything is committed. An invalid result can be retried or rejected without advancing the story. This prevents generated prose from silently becoming game state.

The harder problem has been the quality of the generated scenes. Early results repeated themselves, contradicted earlier events, hallucinated details, or gave weak responses. The engine also had trouble deciding whether a player's message described an action or something the character was saying. Getting the scene text and NPC behavior to a passable level required many rounds of changes to prompts, context, and validation. The balance between response speed and quality is still not right.

I built the Unleaving Inn as a constrained scenario for that work. The player finds themselves in a strange inn without their memory. The limited location and cast made it possible to test the engine's mechanics in a contained setting. I created the core concepts and characters. Language models helped fill in the details.

Coding agents wrote all the code. I directed the architecture and implementation, and I read most of the code before approving the pull requests. I used skills to guide the work, and review agents checked it throughout development. I started building reusable Ruby and Rails skills during Sleeve and refined them during Lore because agents kept making the same mistakes around application boundaries, validation, error handling, and tests.

The longer-term idea was a shared open world generated as play continued. A game master could author parts of it, but that would not be required. Work on that version has not really started. Lore remains a basis for future projects.

Trying WhatsApp as an interface for an AI helper

In February 2026, while I was experimenting with personal AI assistants, I started Helper Bot. I wanted to find out whether WhatsApp could make an AI assistant useful to non-technical family members. They already knew the interface and had it on their phones.

The main use case I had in mind was remote technical help. An older family member could photograph a dialog on a television or computer and ask what it meant. The bot could read the image and explain what to do in Finnish. This did not become a recurring real use case. It was the idea I wanted to test.

Helper Bot works through private chats. A person only needs to send a message to its WhatsApp contact. There is no new application to learn. Actual use has been light. The familiar interface removes some friction, but it does not create a reason to use an assistant.

The architecture was inspired by NanoClaw. The bot connects to WhatsApp through Baileys. The host accepts messages only from allowed chats and starts a fresh container for each agent run. Each chat has its own workspace, conversation history, and saved preferences. OpenRouter provides separate models for text, image understanding, and image generation.

Once the basic chat worked, I used the project to try other agent features. Helper Bot can inspect photos, generate and edit images, and remember user preferences. A user can ask it to schedule a reminder, including a recurring one, and the host sends the result back to the same WhatsApp chat. The bot can also create simple public web pages under a personal URL. Uploaded and generated images can be added to those pages.

Helper Bot was fully coded by agents. I decided what to build and tested the result by using it through WhatsApp. I have not read the code. In this kind of personal experiment, the implementation details do not matter to me as long as the behavior is correct and the security boundaries hold.

Learning by building my own AI assistant

I started using coding agents with Cursor in January 2025. A year later I wanted to build the tools, memory, and interface around the model myself. In January 2026 I started Sleeve, my first attempt to build an OpenClaw-style AI assistant. I also did not want to give somebody else's assistant broad access to my files, credentials, and messages. Discord was the interface.

The assistant was supposed to remember things, use tools, and act on its own. I first planned to use it for notes and project planning. The name came from the television series Altered Carbon. In the series, a sleeve is a body that a person's consciousness can inhabit. The joke was that the AI was the consciousness and I was its sleeve.

Sleeve ended up as three services. A standalone Discord bot received and sent messages. The Rails application routed them, stored the conversation history, and managed the knowledge base. Sleeve Mom embedded Pi's agent runtime and ran the assistant's tools. I authenticated Pi through its OpenAI Codex provider with my ChatGPT subscription. I configured Sleeve Mom to use one of the available GPT models.

I wanted the Rails application to be a hub for several projects. That was not only a plan for later. At least two projects sent messages through the same Discord bot, so keeping Discord separate was useful.

I used Pi to build Sleeve. I added brainstorming and plan-writing skills to Pi, then used them to break the work down. Coding agents wrote all the code. I made the architecture decisions and reviewed and tested the results.

Link collection was the first feature I used. I sent a URL in a direct message. Sleeve summarized it and saved the result as a Markdown note. I used this for a while, but I did not need a personal knowledge base enough to keep the habit. The knowledge base ended up being more useful for my AI game experiments.

For project planning, I got better results by opening Pi's terminal interface on the VPS and working there directly. Sleeve also supported image generation in the group chat. We used it a few times for fun, but it did not become a regular feature.

Eidolon soon took most of my attention. It was an experiment for game ideas I wanted to explore later. Eidolon was a fictional entity that remembered the real world incorrectly. It posted commentary about recent events with deliberate factual errors. My friends were supposed to notice an error and correct it with evidence. A correct answer would reveal part of a secret code.

The idea sounded easier than it was. A few friends tried the game. The first reaction was to trick the AI. After that, there was mostly confusion about what the players were expected to notice. The errors were not obvious enough and the puzzle was too difficult. It did not become engaging.

Repetition was the biggest technical problem. Eidolon kept returning to the same observations. Keeping the game state consistent came next. I separated the correct game state from Eidolon's distorted memories. I added scheduled research, player notes, rules for when it should speak, and checks for its responses. The code became more elaborate, but the game did not become clearer.

I worked on Sleeve for about two or three months. I paused Eidolon in April and later abandoned the project. It was not a product success, but I learned a lot about tools, memory, proactive agents, model output, and context management.

If I did this again, I would keep the assistant, coding interface, and games separate. Pi Web now gives me the coding interface I wanted. I might add an assistant later, but only when I have a real use for one. Games belong in their own project.

Building a shared YouTube queue for parties

A shared YouTube queue for a party sounds like a native feature, but the available options did not fit how I wanted to use it. Native playlists can cache changes, and "Add to queue" assumes that people share a device or local network. I wanted guests to use their own phones without joining my home Wi-Fi, while keeping playback in the native YouTube app already signed in to a Premium account on Android TV.

The approach became practical when I found that the Android TV app can be controlled through Android Debug Bridge. I built Show Manager as a small web app on a VPS. It sends commands over SSH to a Raspberry Pi in my home network, which then controls the TV through ADB. Guests scan a QR code from a display connected to the Pi and receive a 24-hour session. The system is unusual, but each part has a narrow responsibility. This lets me reuse devices and accounts I already have.

Search proved more difficult than playback. Search results do not reliably say whether a video is a proper music video or an audio track with a static image. Show Manager combines YouTube video results with YouTube Music song results. It also keeps a local collection of videos we have already screened and ranks matching items first. This does not try to infer quality from incomplete metadata. It uses previous choices as a practical feedback loop while still leaving wider search available.

The mobile interface now supports selecting several results, putting one item next, and controlling play, pause, and skip. Guest access is limited to search, playback, and the transient queue. The trusted view adds more disruptive controls, including clearing the queue and toggling TV power through the same ADB path, along with saved playlists and imports. Rather than add a separate admin account, the reverse proxy distinguishes public QR traffic from Tailnet traffic. That access model fits one household deployment, but I would choose differently for a service used by unrelated users.

I already had a YouTube playlist of music videos that we often played at parties. The YouTube app on Apple TV did not support shuffling it, but once Show Manager controlled the queue, randomization was easy to add. I imported the YouTube playlist as the initial collection, and Show Manager can now replace the party queue with those videos in random order. I have since stopped maintaining the YouTube playlist and add new video links directly to Show Manager.

Show Manager still handles its original job: editing a loop of images and videos for the always-on Raspberry Pi display and deploying it over SSH to mpv. I built the first version over a few days with coding agents, then kept changing it as real use exposed specific friction. It remains tied to my setup rather than becoming a general platform, but the source code is available on GitHub as a starting point for similar systems.

Shaping your own tools with agents

I had already been experimenting with web interfaces for Pi when I read a post by DODOREACH. People had asked for the Pi interface from an earlier post. Rather than release the finished app, DODOREACH shared a one-shot prompt for building your own. It gave me a good starting point for a new setup, which I then shaped around the way I work.

Pi Web gives me an interface where I can choose a project, start or resume a session, watch messages and tool calls as they happen, and keep several chats running. It works on my desktop and phone through Tailscale. Pi still handles models, login, tools, settings, and session files. I did not want the web app to become a second version of Pi that would always be catching up.

Most changes since then have been small adjustments to how I work. The phone layout is one example. Project and worker lists move into drawers, leaving the limited screen space for the conversation. I can check or continue the same sessions from my desktop without setting up a separate mobile workflow.

On a larger change, I keep requirements and architecture decisions in the supervisor session. A subagent can trace one issue or implement a bounded change in a separate context. It returns a structured handoff instead of adding its full transcript to the supervisor's context. I can inspect that transcript when I need it. Pi Web allows up to three subagents to work at the same time, but only one can edit. Parallel work helps with independent investigations. It is not the default.

Using Pi Web has made its boundary clearer. It should make Pi easier to reach and inspect, not become another development environment. Next, I want each project to define its deploy action and common scripts. A simple file browser could also be useful, but only if it supports the same narrow workflow.

Structuring teams and product development

My current view of product development comes from working as a developer, product manager, technical lead, and company founder. The details have changed between jobs, but the first question has stayed the same: what should we build? A team can write good software and still solve the wrong problem.

At Eebu, we built an ERP and other software for small and medium-sized businesses. I was the only developer on several products. We spent time on abstractions and premature optimization before we understood what customers needed. Being responsible for both the business and the code made that waste hard to ignore. I still prefer simple code that is easy to change while the problem is changing.

That experience also changed how I use feedback. Customers and domain experts know where their daily work is painful. Developers see the technical constraints. Product decisions need both views. Listening does not mean implementing every request. Feedback is evidence that the team weighs against its goals and what it has learned from other users.

At Woolman, I worked directly with customers on integration requirements and helped grow the development team to six people. As my role expanded, I spent more time on architecture, resourcing, and product work. That experience made the limits of a flat structure clear to me. Growth does not mean everyone needs every detail. Decisions need owners, and the people affected by them need a direct way to share information.

At Osgenic, my role combines technical leadership and product work. I guide technical and architectural decisions and work on backlog and roadmap priorities with customer and business value in mind. I also introduced regular one-to-one meetings with developers. An organization chart does not solve team communication. People need a direct way to raise concerns and understand why priorities change.

Technical choices also depend on the stage of the product. Before a product has found its use, I accept technical debt when it buys faster learning. The wrong solution will be discarded anyway. Once a system has real users and needs to keep working for years, the cost changes. Reliability and maintainability matter because failures create support work, manual corrections, and sometimes lost money.

My current preference is simple. Start with a close feedback loop and code that is easy to change. Give the team enough ownership to solve problems instead of only implementing tickets. As the product and organization grow, invest more in reliability and clear information flow. The process should change because the risks changed, not because a framework says so.