This isn’t strictly true. Inner functions have access to outer scope variables captured at the time of definition in their closures. In modern python. Legacy scoping is funky. That’s one of the reasons later.py is a script module – modern scoping applies no matter what calls into those functions.
I don’t remember which of those events use legacy scoping. If it isn’t a component event, I always place the actual event code in a project script module. Modern scoping is then applicable and closures work as expected.
You aren’t showing your code, but I’m going to guess that your project.hello.world() call is within another function you defined within the event. Legacy scoping basically prevents any function defined within the event from having system, shared, or project automatically present. They’ll only be present at the top level.
Make your event a one-liner, passing the event to a project script: