# Engineering Approach

## File prompt.txt
This gonna be renamed to AGENTS.md

The repository contains a global prompt.txt file, as well as separate subprojects that have their own prompt.txt files. I use Claude Code for development. It first reads the main prompt.txt file and then, when necessary, explores the relevant subprojects or modules and reads their local prompt.txt files.

This gives the LLM additional context and allows it to make changes to the code in a more “informed” or context-aware way.

## Running (run.sh + venv)
Every subproject is self-contained and launched through its own `run.sh`. The script creates the subproject's own `.venv`, installs its `requirements.txt`, and execs the entrypoint. Never use the system `python` or a shared venv — each subproject's dependencies live in its own `.venv`.

The `run.sh` convention (identical across subprojects):

```bash
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"          # cwd-safe: works from anywhere
if [ ! -d ".venv" ]; then python3 -m venv .venv; fi
.venv/bin/pip install -r requirements.txt -q
exec .venv/bin/python <entrypoint>.py
```

The `cd "$(dirname "$0")"` line is mandatory — without it the venv and paths break when the script is run from another directory.

## Tests
Within the subprojects, I place module tests in dedicated tests directories.

During the initial, highly experimental phase, I did not examine the contents of these tests very closely. I assumed that the LLM understood the requirements written in natural language and that the generated tests reflected those requirements accurately.

However, this is not an approach that should characterize a well-managed software project. Over time, I therefore began designing the tests much more deliberately. A good test can be treated as a requirement expressed in a formal language rather than in natural language.

This test, for example, simply checks whether an event received from a relay is stored in the database.

![Test](diagrams/test.png)

The tests do not contain explanatory comments written in natural language. Instead, they are structured so that they can be read and understood directly from the code.

In this particular case, I create a new event and publish it to a mock relay. I then instruct the system under test to subscribe to a specific public key. The expected outcome is that the new event is stored in the database, which is verified using DbHelper.expect_row.

Tests of this kind ensure that the system continues to behave according to the creator’s requirements and that the AI does not silently break critical functionality, such as storing a newly received event in the database.

I consider these tests extremely important. The same applies to tests that randomly modify individual characters and verify that the system does not fail, as well as tests that check for memory leaks and similar problems.

All of this matters because, based on my own experience, it is possible to write code that appears excellent at first glance, only to discover many bugs once it is subjected to thorough testing.

## Errors
No silent errors — I need to **see** when something goes wrong and react accordingly. So my approach is basically to store all the exceptions, crashes and other stuff. Any thrown errors should go as a log.

## Logs
I like remote, structured logs so something like "what happenss" and "with what data" and you know what - I should use Nostr Kind 78 for logs. Yeah, why not? haha, Cool, because then I could use Just Onboarding to navigate them!

# Basic Order of Operations
1. Question
2. Remove
3. Simplify
4. Speed up
5. Automate

# Motto
Make everything as simple as possible, but no simpler.

