Só uns detalhes sobre o código:

Em vez de verificar se o arquivo existe, simplesmente tente abri-lo e capture as exceções. Essa ideia de verificar e só depois abrir gera uma condição de corrida (race condition): em resumo, entre a verificação e a abertura, o estado do arquivo pode ter mudado e dar erro do mesmo jeito (mais detalhes aqui).

O withgarante que o arquivo será fechado ao final, então não precisa chamar close().

Para verificar a extensão do arquivo e demais manipulações, dê uma olhada no módulo pathlib - disponível desde o Python 3.4 e considerada uma alternativa mais moderna à os.path (veja aqui um comparativo).

Por fim, se a ideia é que o arquivo JSON seja apenas para "organização" interna e não necessariamente para ser lido por humanos, considere alternativas como os módulos pickle ou shelve.

Muito obrigado pelas dicas. Vou atualizar o repositorio com essas sugestões.