Skip to content

Conversation

@nakulj
Copy link

@nakulj nakulj commented Jan 28, 2026

fixes #3320

@nakulj nakulj changed the title Add support for jsonnet (fixes #3320) Add support for jsonnet Jan 28, 2026
@nakulj nakulj marked this pull request as ready for review January 28, 2026 06:20
@nakulj
Copy link
Author

nakulj commented Jan 28, 2026

I decided to take a shot at adding jsonnet support directly. Let me know if this is the right approach.

@tekezo
Copy link
Member

tekezo commented Jan 28, 2026

Thank you for PR!

With this approach, changes written back to the JSON from the settings window or the menu aren't reflected.
I assume you're already aware of that, but I'm a bit hesitant to introduce this as a general-purpose feature.

At the moment, I think the best approach is to manually convert karabiner.jsonnet to karabiner.json when you make changes.

Separately from that, I understand how painful it is to write JSON directly.
We already have the JavaScript engine duktape integrated into the project, although it's not enabled anywhere except karabiner_cli.
Using that, I think it would be nice if we could write something like an "eval" inside karabiner.json, as shown below.

    "profiles": [
        {
            "complex_modifications": {
                "rules": [
                    {
                        "description": "local",
                        "manipulators": {"eval": "external.js"}
                    }
                ]
            }
        }
    ]

@nakulj
Copy link
Author

nakulj commented Jan 30, 2026

That makes sense. Personally I do not like the settings window changing my karabiner config, but to a casual user it might be confusing to not have to read changes read back.

What if we do this: if karabiner.jsonnet and karabiner.json files both exist, we merge the two? That way karabiner can write back changes to karabiner.json and those will be respected without any further changes. Power users can continue using the jsonnet file and that will continue working.

Pseudocode:

jsonnet_cfg = try_read_jsonnet() or {}
json_cfg = try_read_json() or {}
return json.merge(json_cfg, jsonnet_cfg)

Regarding using duktape, I think it is worth noting that jsonnet is the standard for "programmable json". It has a healthy ecosystem including editor and language server support. Whereas, most editors don't know what to do with eval statements inside a json files.

What do you think?

@tekezo
Copy link
Member

tekezo commented Jan 31, 2026

Jsonnet itself is fine, but I'm a bit concerned about how weak it is in terms of stopping malicious scripts. Without a way to interrupt things like semi-infinite loops as follows, it would be hard to adopt...

local fib(n) =
  if n < 2 then n
  else fib(n-1) + fib(n-2);

fib(45)

@nakulj
Copy link
Author

nakulj commented Jan 31, 2026

What if we use timeout around the jsonnet invocation? Something like 5 seconds should cover the most complex config while guarding against buggy configs like the ones above. The timeout could be left configurable by users.

@tekezo
Copy link
Member

tekezo commented Feb 1, 2026

Hmm, if we were to integrate this into the core, I'd really want to handle it directly with libjsonnet…
For now, I'll move forward with improving JavaScript support, and then we can decide based on how that turns out.

@tekezo
Copy link
Member

tekezo commented Feb 3, 2026

In the latest beta (v15.9.5), you can now define rules using JavaScript, so please give it a try.
https://github.com/pqrs-org/Karabiner-Elements/releases/tag/beta

Editing with an external editor is recommended.

Screenshot 2026-02-04 at 8 31 04 Screenshot 2026-02-04 at 8 31 28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support jsonnet configuration files

2 participants