CLI tool
jacek-kurlit/pik avatar
jacek-kurlit/pik

pik: an interactive process killer for the terminal

Process Interactive Kill

581 stars19 forksRustMIT

At a glance

What is it?
pik is a terminal user interface for finding and killing a running process. The search is fuzzy, and it can look at the process name, the command path, the arguments, the listening port, or the whole picture, and the kill itself is a key chord rather than a command, which is the difference between a tool you use and a tool you fight.
Who is it for?
pik fits somebody who has ever typed a process name, guessed wrong, and killed the wrong thing, and it fits a developer working with a machine running many long-lived servers. It does not fit a script that needs a deterministic answer, because the whole interface is interactive.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 31 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What it does, and the one idea behind it

Pik is a command line tool that helps to find and kill a process, and the readme puts the difference in one sentence: it works like the familiar pattern-killing command but the search is interactive.

That is the whole product, and it is a small idea with a large effect. The familiar command takes a pattern and kills what matches, and the problem is that you are guessing. You type the first few letters of a name, the tool matches a substring, and if two processes share it, one of them is going to die that you did not mean. The interactive version replaces the guess with a list: you type, the candidates narrow as you type, and you look at what is about to be killed before you kill it.

The readme also says the tool is still under development, which is a thing to weigh when you are deciding whether to adopt it. The release history suggests that the development is real rather than abandoned: there is a version one release, a version zero point thirty point two, and the version one point zero one came a few months later.

The licence is MIT, the language is Rust, the project is published to the crate registry, and the last push was on 2026-09-22.

Seven ways to search, and why the prefixes exist

The feature list is the interesting part, because it explains that the search is not one search but seven, and that the mode is chosen by a single character at the front of what you type.

Searching by name is the default and needs no prefix at all: you type the process name and the candidates narrow. Searching by the command path is a prefix search with a forward slash, so the same name typed with a slash in front matches on the path rather than on the name. Searching by arguments is a prefix with a hyphen, and the readme immediately warns about a consequence of that choice, which is that in the command line you have to put a separator before it so the argument is not taken by the tool itself.

Searching by port is a colon, so a colon and a port number finds the process holding it. Searching everywhere is a tilde, which searches across the name, the path, the arguments, and the port together. Selecting a process by its identifier is an equals sign, and selecting a process family is an at sign, which takes a process and its children.

That last one is the most useful of the seven and the least obvious. A modern application is rarely one process. A development server, a watcher, a compiler, and the thing they supervise are four processes, and killing the parent alone may leave the children running, which is the failure that makes people reach for a heavier tool.

The prefixes are a design decision with a cost, and the readme is candid about it: a single character changes what the list means, and a mistake in that character shows you a different set of processes rather than an error. The alternative designs would each have their own problem, but this one is compact and the modes are learnable in a minute.

Then the two kill actions, and they are as simple as the rest. You select a process and kill it with one chord, which sends the polite termination signal, and you force it with another chord, which sends the immediate one. There is no confirmation prompt, and no reason there should be, because the confirmation is the list you are looking at.

Installing it, and how many ways there are

The installation section is long, and the reason is that the tool is packaged for every distribution that matters.

Precompiled archives are published for the three major desktop platforms, and then the packages follow. On Arch it is a single command. On Fedora there are two, because the package is built in a personal repository that has to be enabled first. On the rolling distribution of the same family it is one. On Gentoo it comes through an overlay that has to be enabled and synced before the package can be emerged.

sh
pacman -S pik
sh
sudo dnf copr enable rusty-jack/pik
sudo dnf install pik

Windows has a bucket that has to be added before the install, and macOS has a tap, and both follow the same pattern of one line to register the source and one to install from it.

sh
scoop bucket add jacek-kurlit https://github.com/jacek-kurlit/scoop-bucket
scoop install pik
sh
brew tap jacek-kurlit/tap
brew install pik

Linux also has a snap package, and because the package is a terminal interface the snap is named for the interface rather than for the tool.

sh
snap install pik-tui

And for the people who will actually read the source, there is a package manager for Rust binaries, and the tool is installable from the crate registry with the usual command.

sh
cargo install pik

So there are many routes, and the readme does something sensible that most projects skip: it puts the precompiled archives first, on the grounds that most users should take the binary and only the people who want to build from source should look further down.

The repository listing backs up the packaging story. There is a directory for the snap, a specification file for the distribution package, a script that appears to handle the long form of the command line arguments, and a separate make file variant, which suggests the build is driven by a task runner with a couple of different front ends.

Configuration, and the two things that will bite you

The configuration is a file, and the readme gives its location for each platform in a table, with the two candidate directories on the systems that have more than one convention. Everything in it is optional, and the defaults apply when a value is absent.

The precedence rule is stated plainly: some configuration fields have a command line equivalent, and if both are set the command line wins. And there is a command that prints the final configuration, which is the right way to debug a merge like this, because it shows the resolved values rather than the file.

Two details in the readme are worth more than the rest, and both are about the way terminals report keys.

The first is that a binding is always a list, even when it holds one key, and the bare string form is rejected with a message about the type. That is a small design decision with a real reason behind it: it makes the shape uniform, so the parser has one case rather than two, and it makes it possible for one action to have several bindings.

toml
[key_mappings]
# Single modifier
quit = ["ctrl+c"]

# Combined modifiers
toggle_debug = ["ctrl+alt+d"]

# Multiple bindings, with different modifier combinations, for the same action
toggle_help = ["ctrl+alt+h", "f1", "alt+shift+H"]

The second is about the shifted letter. Terminals report a shifted key as an uppercase character, so the letter has to be written uppercase, and the lowercase form is accepted by the parser and then never matches anything you press.

And then the one that is genuinely useful to know, because it explains a design decision rather than just a rule. A control and shift combination with a letter cannot be detected on Unix terminals at all, because the control and shift versions send the same bytes. That is why the force kill is bound to a chord that every platform reports unambiguously.

So the readme is not just documenting a limitation, it is explaining why the default bindings avoid it. And the list of modifiers the tool understands is long, including the super, hyper, and meta keys, so a binding can be written in whichever vocabulary your terminal uses.

The configuration merge, and the trap inside it

The most interesting documentation in the repository is the migration guide, because it describes a behaviour that will surprise people.

Version one embedded a default configuration file and merges it with your local one, and the readme warns that in some cases the merge result may not be what you intended. Then it gives a worked example.

The default configuration sets a table cell's highlighting to a yellow background with an italic modifier, and your local configuration sets the same field to a red background and says nothing about the modifier. The resolved result is a red background with the italic modifier, because the merge is per field and the modifier survived from the default.

toml
[ui.process_table.cell]
highlighted = { bg = "Red", add_modifier = "ITALIC" }

And then the instruction for the case where you wanted the modifier gone: you have to be explicit about it and set it to the empty string.

toml
highlighted = { bg = "Red", add_modifier = "" }

That is a proper deep merge of nested tables, and it is the right choice in one sense and the wrong one in another. It is right because a configuration file that only sets one colour should not have to restate the whole style. It is wrong because you cannot remove an inherited value by omitting it, and the only way to remove it is to write the empty value, which is not obvious and is not discoverable from the error message you would get if you tried it.

The readme handles this the right way, by giving the example and the fix, and by putting the warning right at the top of the migration section rather than in a list of caveats further down. A user upgrading from the older line is exactly the person who will hit this, and the guide is written for them.

The rest of the configuration is more conventional. There is a configuration document for the options, the theme, and the key mappings, and a separate document of ready-to-use snippets: themes, the readline and the vim editing modes, the paths to ignore on macOS, icon sets for a patched font, and a compact fullscreen layout. And there is a minimal starting point that sets the screen size to fullscreen and chooses an icon set.

toml
screen_size = "fullscreen"

[ui]
icons = "nerd_font_v3"

So the project ships both the mechanism and the recipes, which is the combination that makes a configurable tool usable by somebody who does not want to design a theme from nothing.

Editorial conclusion

pik fits somebody who has ever typed a process name, guessed wrong, and killed the wrong thing, and it fits a developer working with a machine running many long-lived servers. It does not fit a script that needs a deterministic answer, because the whole interface is interactive. Verify first which search prefixes you will use, because the tool distinguishes between them with a single character and mixing them up changes what you are shown, that the signal you want is the one you get, since the normal kill sends a termination signal and the force kill does not, and that your terminal reports the shifted keys the way the configuration expects, because the readme is explicit that a lowercase letter after shift will never match anything.

Frequently asked questions

What does the pik tool do?

It is a terminal tool for finding and killing a running process. The search is interactive and fuzzy, and it can match the process name, the command path, the arguments, the listening port, or all of them, and a selected process is killed with a key chord.

How do you search by different attributes in pik?

With a single character at the front of the query. No prefix searches the name, a slash searches the command path, a hyphen searches the arguments, a colon searches the port, a tilde searches everything at once, an equals sign selects a process by its identifier, and an at sign selects a process together with its children.

How do I kill a process in pik?

Select it and use one chord, which sends the polite termination signal, or another chord, which sends the immediate one. The force kill is deliberately bound to a combination that every platform reports unambiguously, because a control and shift combination with a letter cannot be told apart from the plain control version on Unix terminals.

How is the pik configuration file organised?

It is a file in the configuration directory of the platform, with every option optional and the defaults applying when a value is absent. The command line overrides the file, and there is a command that prints the resolved configuration, which is the practical way to check what a merge produced.

What changed in version 1.0 of pik?

Version 1.0 embedded a default configuration file that is merged with your local one, field by field, so a value you omit is inherited rather than removed. The migration guide shows a worked example where a modifier survived a changed colour, and explains that removing an inherited value means setting it explicitly to the empty string.

Official sources

  1. jacek-kurlit/pik on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jacek-kurlit-pik.svg)](https://hysenlabs.com/projects/jacek-kurlit-pik)

Was this useful?