Is there a native way across Jupyter Notebook, Jupyter Lab, and Jupyter Hub to programmatically store ipynb metadata?

Right now for a project I’m working on, I’m building a fairly complex GUI inside of Jupyter and want to abstract the configuration of some states related to a given notebook away from the user. They click an HTML button in an HTML widget, then behind the scenes I execute Python in the kernel (from JavaScript, using the expose_app_in_browser command line option + IPython.notebook.kernel.execute) to store the statefulness in a state.json file. This works. It’s just that now I have to explain to the user what this state.json file is and not to delete it.

There seems to be an opportunity to simplify this. Since ipynb files are just JSON themselves and there are numerous locations already within the format for metadata properties, I could easily be storing this data in the notebook. But just loading / modifying the JSON (or even using import nbformat as nbf) doesn’t suffice for a live notebook because Jupyter is tracking its own internal representation of that object state. I need to modify that object state internally, whether Jupyter is storing it server side or client side, I’m not sure. If I could just know where it is and how to modify it programmatically, I could really streamline my Jupyter application entirely within the existing ipynb format without hurting anything. In fact, I’ve tested doing so manually, and nbformat still views the file as valid.

I’m reluctant to use something platform specific like jupyterlab_commands (GitHub - timkpaine/jupyterlab_commands: Add arbitrary python commands to the jupyterlab command palette) for Jupyter Lab, because I want to focus on a solution that should work across Notebook, Lab, Hub, and potentially have a good chance of working within the various Jupyter front-end abstractions that support ipywidget widget rendering, like PyCharm, CoCalc, etc.