Jonathan, I took a look at your package, and the code, it's a really nice exploration of the solutions.

I did find having to include the o() call in the sdaprano version quite distracting (I realise it's needed to get it to work in current cpython without silly tricks in the interpreter)...

...But I'm not afraid of doing horribly evil things to python for the purposes of proof-of-concepts.

The code in this gist:
https://gist.github.com/stestagg/4962d4e86fb586b14138f19af4ae4a02

Implements a very ugly codec hack to make python 'understand' keywords in index constructs, and I use it to show how the approach proposed by Steven D'Aprano (Please correct me if I'm mis-representing anything!) should work in my mind.
If you want to run this code yourselves, you can do by downloading the 2 files into a directory, and running `run.py` (with an appropriate PYTHONPATH set)

The bit of the gist that is most relevant is this:

class ObjWithGetitem(Helper):

    def __getitem__(self, key=None, foo=None, bar=None):
        print(f'{key=}  {foo=}')


def main():
    obj = ObjWithGetitem()
   
    obj[1]
    # key=1  foo=None

    obj[foo=1]
    # key=None  foo=1
    
    obj[1, foo=2]
    # key=1  foo=2
    
    obj[1, 2]
    # key=(1, 2)  foo=None
    
    obj[1, 2, foo=3]
    # key=(1, 2)  foo=3

    obj[(1, 2), foo=3]
    # key=(1, 2)  foo=3

    obj[(1, 2), 3, foo=4]
    # key=((1, 2), 3)  foo=4

    obj[**{'foo': 9}]
    # key=None  foo=9

    obj[1, 2, foo=3, xxx=5]
    # TypeError: __getitem__() got an unexpected keyword argument 'xxx'

Which I like for its simplicity

I'm not sure about supporting '*args' syntax in indexes at all, unless doing so could be shown to be trivially implementable without any nasty corner-cases.

Steve