Skip to content

feat: added eval option - #384

Open
pasteley wants to merge 2 commits into
kubie-org:masterfrom
pasteley:in-place
Open

feat: added eval option#384
pasteley wants to merge 2 commits into
kubie-org:masterfrom
pasteley:in-place

Conversation

@pasteley

@pasteley pasteley commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

Closes: #85 #371

This PR os also a prerequisite for #378 — shell keybindings to activate a context in the current shell

Summary

kubie always spawn a new shell (or switch in-place inside an existing kubie shell). This makes it impossible to use it from shell keybindings or wrapper functions, there's no way to set KUBECONFIG in the current shell without spawning a subshell.

Added --eval flag solves this by printing export statements to stdout instead of spawning a shell like this: eval "$(kubie ctx --eval my-context)"

This reflects pattern used by tools like direnv, fzf, and zoxide.

What changed

  • kubie ctx --eval / kubie ns --eval — writes temp kubeconfig and session files, then emits shell export statements (bash/zsh/fish) to stdout. The caller evals the output to activate the context in the current shell
  • ActivationMode enum replaces the recursive: bool parameter, centralizing the spawn/switch/eval decision in one place
  • Terminal detection changed from stdout.is_terminal() to stdin.is_terminal()
    • The old check broke eval mode: inside $(...), stdout is captured (not a tty), so kubie would list contexts instead of showing the interactive selector.
    • Checking stdin is also more correct semantically: "can the user interact?" depends on keyboard input, not output destination
  • Previous temp files are cleaned up on each --eval invocation to avoid leaking files in /tmp

@pasteley pasteley changed the title feat: added evel option feat: added eval option Jan 9, 2026
@sbstp

sbstp commented Jan 15, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR, can you share your thoughts on this issue?

@pasteley
pasteley force-pushed the in-place branch 6 times, most recently from 7a0f1fb to 44805ed Compare March 28, 2026 14:56
@pasteley
pasteley force-pushed the in-place branch 2 times, most recently from 3216768 to f33ea2f Compare April 10, 2026 22:04
@pasteley

Copy link
Copy Markdown
Collaborator Author

@lotheac Lauri, hi, what do you think about this one?

@lotheac

lotheac commented May 11, 2026

Copy link
Copy Markdown
Collaborator

@lotheac Lauri, hi, what do you think about this one?

sorry, took me a long time to get to this.

IMHO, we should not do this. In my view, it is a design decision that kubie only supports new shells -- it makes each session cleanly contained, and gives it a place to properly clean up on shell exit -- as you've noticed, removing the kubeconfigs becomes difficult if you don't know when the kubie session terminates.

@pasteley can you elaborate on why you want this? Is there some specific use case that cannot be supported otherwise?

@lotheac

lotheac commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Specifically on the subject of shell keybindings: I don't see why a keybinding for switching context would not work, as long as you are already in a kubie shell. Unless I'm missing something.

@mihaitodor

Copy link
Copy Markdown

@lotheac Thought I'd chime in on this one since I think it should fix an issue I'm seeing when using kubie. In my case, spawning a new shell isn't ideal, because that confuses the zsh command history. As soon as I close the shell, I lose the commands I executed. Maybe this can be fixed via some config setting in zsh, but kubie is the only CLI app I use which has this issue. Otherwise, it works great!

Signed-off-by: pasteley <ceasebeing@gmail.com>
@pasteley

pasteley commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

@lotheac

kubie only supports new shells point

I don't think that's actually holds in the codebase, we had this:

if vars::is_kubie_active() && !recursive {
    let path = kubeconfig::get_kubeconfig_path()?;
    kubeconfig.write_to_file(path.as_path())?;
    session.save(None)?;
} else {
    spawn_shell(settings, kubeconfig, &session)?;
}

Which mean when you're already inside an active kubie session and switch context without -r, kubie just rewrites the kubeconfig file in place without spawning new shell. --eval is the same idea applied one step earlier: before you're inside a kubie shell, so there's no existing file to rewrite, you set env vars in the calling shell instead. (this PR pulls that inline check into the ActivationMode enum in activation.rs and adds Eval as a third option alongside it)

I actually tried building the keybinding without --eval first, and it doesn't work at all. spawn_shell (shell/zsh.rs:141-146) doesn't redirect the new shell's output, it inherits whatever the parent has. A keybinding has to call kubie through output=$(kubie ctx ...) to capture anything, which means stdout is a pipe, not the terminal, so the second you spawn a shell that way, its whole session (prompt, output, everything) goes into that pipe instead of the screen.

On the implementation itself: it's opt-in, so nothing changes unless you pass the flag, and it uses its own temp file naming (kubie-eval-*) so it can't collide with the regular spawn flow's files (tested for that too). Repeated --eval calls in the same session reuse the same files instead of piling up new ones.

One thing worth flagging myself: kubie's temp files normally clean up because it waits on the spawned shell and deletes them on exit. --eval prints and exits immediately, so there's no automatic cleanup -> files sit until reused or cleared by the OS. Same tradeoff tools likes direnv and zoxide live with, so I don't see it as a blocker.

@pasteley
pasteley requested a review from lotheac August 8, 2026 11:33
@lotheac

lotheac commented Aug 8, 2026 via email

Copy link
Copy Markdown
Collaborator

@pasteley

pasteley commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

@lotheac The output isn't shell code though, it's 5 env vars, no hooks, no functions, no logic. Idea is basically copied from direnv, where subprocess computes the diff and caller applies it. So "injected into anything" doesn't really describe what's printed here.

"One thing worth flagging myself" stinks of LLMs

Just wording, may be the case of llm corrupting language, but mentioned it because found it while playing around with this feature.
And here precisely I get the ownership point, since spawn mode's temp files clean up via Drop when child exits, and eval mode has no child so they persists.

Is there some specific use case that cannot be supported otherwise?

As I mentioned in description, activating kubie via keybinding from a shell that isn't already a kubie session is exactly such use case, there's no other way to get a context/namespace switch back into the calling shell. I couldn't manage to make ZLE widget to spawn an interactive child without breaking the terminal, nested shell's output just gets swallowed into the capture pipe.
This way I use kubie day to day myself (builded from this branch), and judging by the reactions on the original issue, it seems like a fairly anticipated feature.

@lotheac

lotheac commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

@pasteley A big part of the reason why I started using kubie initially, instead of alternatives, is because the subprocess design is clean: you can go back to kubie-less state by just exiting the shell, no temp files are leaked. It is a design decision for it to work this way, and adding --eval is an escape hatch from that design -- that's why I'm arguing against it.

To be clear, I'm not against improving user experience with respect to keybindings, but I don't think --eval is a good tradeoff. Using --eval makes kubie semantically a shell code generator instead of a shell wrapper, which means its responsibilities change: from "modify environ, run subprocess, wait for it to exit, clean up" to: "create temp file, generate shell-specific code to set env vars, hope someone else cleans up".

I realize kubie already does emit shell code for the prompt modifications etc. However, if anything goes wrong there, the shell that ran kubie is unaffected -- unlike when using eval.

Also, as your implementation shows, the emitted code needs to be shell-specific. kubie already requires a supported shell, but you've only implemented --eval for a subset of those supported shells.

As an alternative, what if you had a shell keybinding that clears the input line, types in "kubie ctx" and runs it? That way you keep all the benefits of the subshell, with its cleanups and ability to return to a kubie-less shell. As an additional improvement, you could detect in the keybinding whether you're in a kubie shell, and if so, no need to touch the input line.

BTW, have you considered kubie export? It would allow you to implement what you want in your own shell config, which IMHO is the right place to implement things that are meant to directly manipulate the shell's own process environment.

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.

Eval instead of new shell?

4 participants