I think very few PG extension use cases need new storage engines. Looking at
https://age.incubator.apache.org/overview/ it says it's using the normal PG storage.
Regarding indexes - (1) you can implement most custom indexe scenarios based on supplied expressions involving custom functions: https://www.postgresql.org/docs/current/indexes-expressional... (2) I suspect for the graph use case you could leverage json indexes: https://www.postgresql.org/docs/current/datatype-json.html#J...
This is not to claim with any high degree of certainty that this could be implemented in PG/Lua, just from my armchair there doesn't seem anything immediately obvious that would prevent it.
For example the querying in AGE is syntactically implemented in the function cypher() that is used in the examples to receiving custom syntax as strings with the "dollar quoting"[1] syntax:
SELECT *
FROM cypher('graph_name', $$
MATCH (n)
WHERE exists(n.surname)
RETURN n.first_name, n.last_name $$) as (first_name agtype, last_name agtype);
[1]
https://www.postgresql.org/docs/current/sql-syntax-lexical.h...