Activating a kitten via remote control #9065
Replies: 5 comments 6 replies
-
I didnt read all that, but I'll just point you to kitten @ run which will work for playing sounds and opening browsers using arbitrary commands, and launch neovide. Though if I were you I'd ditch neovide in favor of nvim and use the edit-in-kitty command that the ssh kitten makes for you. |
Beta Was this translation helpful? Give feedback.
-
I dont follow at all.
a) You dont need kittens for what you want to do, only remote control.
b) You have available to you the exact payload of every remote control command and you
can choose to allow/disallow them based on arbitrary code written in an
easy to use and widely known language, so I dont know how the "DX" can
be made any better. If you have some suggestions to improve the docs,
feel free to send a PR.
|
Beta Was this translation helpful? Give feedback.
-
For #1, I think setting a watcher should cover the usecases? Though I don't really understand all of it (a manual sound on succeed?) https://sw.kovidgoyal.net/kitty/launch/#watchers For #2, can't you just modify open actions to get different behavior per protocol? https://sw.kovidgoyal.net/kitty/open_actions/ For #3, can't confirm if the docs are incorrect or not |
Beta Was this translation helpful? Give feedback.
-
On Sun, Oct 05, 2025 at 05:46:09AM -0700, Ryan Patterson wrote:
I thought about your suggestion to use "kitten @ run" a bit more. Unfortunately, it's worse than what I've built. The command for playing a sound / opening a browser is different between macOS and Linux. If I were to proceed down the "just use kitten @ run" path, each remote machine needs to understand the possible kitty host machines and their implementations, and the kitty host has to to validate the effectively arbitrary shell script (to prevent arbitrary code execution), or more realistically it hav to hard code the same script into the `is_cmd_allowed` script. What I have is a custom kitten where the implementation can be swapped on my Linux and macOS machines, so the remote machine doesn't need to know how to play a sound, it just calls the "play sound" kitten.
So create a "play sound" script in ~/.config/kitty/play_sound.sh (or
some other stable location) and run
that and it can do per platform dispatching as needed. No need for a
kitten at all.
Which brings me back to the DX:
- I don't like the fact that I have to use `is_cmd_allowed` to validate the payload of a command that I didn't write. The docs don't specify the payload fields used for `cmd: "kitten"`, so they are free to change at any time. If Kitty allowed me to make my own command, I would have full confidence that the payload object wouldn't change out from under me.
So check all the fields in cmd_payload (it is a dict and you can enumerate them)
and if they are different from exactly what you
expect, deny permission. And the docs do specify them, for example, for @
run: https://sw.kovidgoyal.net/kitty/rc_protocol/#run
Though there is no guarantee the fields will never be added to, of
course. Hence check the totality of the payload.
- If I could define custom commands, I could put two custom commands into one python file. This would fix the minor annoyance that I talked about in my open_url command.
Like I said above use @ run and run your own script taking
whatever command parameters you like and combining whatever functionality you
like.
- The docs for [Adding options to kittens](https://sw.kovidgoyal.net/kitty/kittens/custom/#adding-options-to-kittens) are outdated/wrong; the [linked example](https://github.com/kovidgoyal/kitty/blob/master/kittens/diff/main.py) is a Go kitten which doesn't really help me implement my Python kitten. It looks like this whole section is intended to only cover Go kittens, since all the usages I see in the kitty repo are for Go kittens, so maybe it's not something I should be looking at at all.
Only builtin kitten are in Go, custom kittens are written in Python. The
syntax for adding options is the same between python and Go, and it is
done in main.py, a Python file. You would do exactly what is shown in
the example (which is in python) or you would read main.py from the diff
kitten to see how to add options from it. I should probably change the
link in the docs to link to main.py directly instead of the diff folder.
Not to mention that entire section is optional, it's needed only if
you want to use kitty's own config handling infrastructure.
Frankly it's overkill for you as it brings niceties like static type
checking, includes, shortcut parsing etc which you dont need.
You can use any config framework you like, for example tomllib or configparser
from the python stdlib instead. Though given you are writing a one use
kitten for yourself only not sure why you need config at all?
|
Beta Was this translation helpful? Give feedback.
-
On Sun, Oct 05, 2025 at 08:57:47PM -0700, Ryan Patterson wrote:
Taking a step back, given that I thought what I wanted is exactly the scope for a custom kitten, and you repeatedly say that it is not, can you explain what exactly *is* the use case for custom kittens? I have a few more advanced customizations I want to attempt and would love to do it in the most idiomatic way for Kitten (two examples are: use/modify the ssh kitten to work with containers as well as remote machines, overlay the terminal / scrollback with timestamps of when the lines were modified).
kittens are useful when you have something you want to do in response to
a mapping that typically involves showing some UI (drawn as a TUI)
to the user and then the user interacts with the UI and then the kitten
does something with the result of those interactions. The other use case
of kittens is when you want to do something that isnt covered by the
remote control API by directly manipulating internal kitty data
structures, but this has the downside that those data structures are not
stable. And finally kittens serve as a nice integration point for
creating pure TUI interfaces to enhance functionality, the diff
kitten and ssh kitten are good examples of this, they are meant to be
run from the command line not via a mapping and there is no "do something
with the result of user interactions" step after they are run.
You wont be able to do either of those two things using kittens alone, they
will both require changes to actual kitty code. Indeed, the second is
likely to be impossible since kitty does not store modification
times for lines, it would be a performance/memory cost and not something I
am likely to accept. As for containers, you could do most of it with a kitten
but the "create new window with the same cwd as the current" part would
need changes to kitty itself.
> You would do exactly what is shown in the example (which is in python)
I mentioned this in my original post, but doing exactly what is shown in the example gives an ImportError. You're telling me that it's not worth me pursuing this, so I'll follow your advice, but I just want to reiterate what I said before, that what's in the example is outdated/wrong.
OK, like I said, I didn't actually read your full post, too much text :)
The example may indeed need to be updated a bit.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I've been evaluating Kitty as an alternative to iTerm 2. I have made some custom escape codes in iTerm 2, which I want to re-implement using Kittens. This discussion is half "experience report" and half request for help on the parts I got stuck on. So, I have 3 target use cases:
sounds.py
I use a custom escape code to play a sound on my local computer. The system bell is insufficient; I use different sounds for different purposes (automatic sound on shell command failed; manual sound on shell command succeeded; sound when Claude is waiting for input).open_url.py
I want programs likevite dev
that automatically open a browser to work over SSH. I do not want this to happen in response to me pressing a key; I want it to happen automatically at the request of the remote program.neovide.py
I have a custom wrapper forneovide
that will trigger it to open over SSH. This is likekitten @ launch
, but uses an allowlist to prevent arbitrary code execution.Creating
sounds.py
kittenThis is the simplest Kitten as it has no UI. Here's the gist:
sounds.py
Add the line
remote_control_password "" "sounds.py"
to kitty.conf, invoke using:OK, so this works, but it's janky. Problems I see:
is_cmd_allowed
function has to understand the implementation details of Kitten's remote protocol.main
function, but it's unused. I guess if I wanted to add support for invoking this kitten from a binding I would use it. Would be nice if this were not required.handle_result
is not handling any result, because themain
function is never called, but it's the only way to do anything with the invocation.Questions:
is_cmd_allowed
would continue to work, but thecmd
would be my command instead of "kitten".Creating
open_url.py
kittenThis kitten is a bit more complicated because I do want UI... sometimes. I want this to work like a browser's URL handling: for "safe" http and https URLs, it just works, but for "unsafe" URLs it requests permission. I was able to get this working, mostly:
open_url.py
Add the line
remote_control_password "" "open_url.py"
to kitty.conf, invoke using:This follows the same basic outline as before but it uses a UI this time. It has one minor flaw:
If it were possible to define a custom command, I could resolve the shortcoming by defining two commands:
open_url
andopen_unsafe_url
, the former conditionally invoking the second when necessary. I can do this now, of course, but it is inconvenient enough that it's not worth it.Creating
neovide.py
kittenI haven't written this one yet, but here's how it should work:
kitten @ neovide.py named-env /path/within/env [--filename SPECIFIC_FILENAME]
There is a doc section called Adding options to kittens but it doesn't work (ImportError for
kitten_options_definition
when runningkitty.conf.generate.main
), and the docs refer to the diff kitten which doesn't look anything like the documentation. I tried copying it, invoking it askitten neovide.py
fails due to the raise inmain
, andkitten @ kitten neovide.py
just blinks my screen and returns. Unclear how to access any of the options.Questions:
argparse
on myargs
array, but I won't get completion.__name__ == "__main__"
in my kitten?main
functions?__name__ == '__doc__'
or__name__ == '__conf__'
? When/where are they invoked?Conclusion
One thing that took me some time to wrap my head around is exactly where kittens get executed. Here's what I've figured out:
kitten @ kitten my_kitten.py
remote_control_password
, thenis_cmd_allowed
is run in the kitty host process. Changing the implementation requires restarting kitty.main
is invoked in a new process on the kitty host machine using an overlay window (and a separate tty?).handle_result
function is invoked in the kitty host process, but the python module is reloaded each time the kitten is invoked.kitten my_kitten.py
main
function is invoked in the remote kitten process, without an overlay window.handle_result
function is not called.Overall I think the extensibility kitten model for extensibility looks exciting, particularly for my target use case (which primarily involves developing in containers, sometimes over SSH). I know that the direct feature request of custom escape codes has been dismissed in the past, but invoking kittens using escape codes is established and doesn't seem to be explored as an alternative to custom escape codes yet.
Beta Was this translation helpful? Give feedback.
All reactions