Skip to content
Documentation menu

Safety

Target identity, confirmations, protected processes, and the checks applied before Kickoutchi sends a signal.

A port can change owners between inspection and termination. Kickoutchi resolves and checks the target again before signaling it. This page documents those checks and their limits.

Confirmations

Nothing is terminated without a confirmation step, and the prompt scales with the risk:

  • Normal kill • type y.
  • Force kill • type the word force (unless you set confirm_force_kill = false).
  • Tree kill • type tree for normal scoped termination, or force for force tree kill.
  • Group kill • type group for normal scoped termination, or force for force group kill.
  • Protected process • type the PID or the process name.

Before any prompt, Kickoutchi prints the target’s identity, the affected ports, the equivalent shell command, and any warnings.

Hard guardrails

  • PID 0, PID 1, Kickoutchi’s own PID, and Windows PID 4 are blocked outright • they can’t be targeted at all.
  • kill --port refuses ambiguous ports. If two PIDs own the same port, Kickoutchi lists the candidates and makes you choose with --pid instead of guessing.
  • A port with no readable owner is not killable • it exits 4 (permission denied) rather than acting on incomplete information.
  • Incomplete Linux ownership scans also block kill --port. Even when one owner is visible, Kickoutchi signals nothing if restricted process visibility could hide a co-owner of that port.
  • Scoped kills are bounded. Over-cap or non-converging trees/groups refuse instead of partially killing a moving target.

Protected processes

Some processes are load-bearing: init, your database, Docker, core OS services. These are marked protected and require typing the PID or name to confirm • force or --yes can’t shortcut it. The built-in list includes Docker owners such as dockerd, docker-proxy, and com.docker.backend, and it is extensible via config.

On Linux, process names truncated by the kernel midway through a Unicode character use the same bounded decoding for listing, protection matching, and final validation. A truncated character alone no longer blocks termination; ownership and process identity checks still apply.

Human-facing output also sanitizes OS-provided names, paths, and status text before rendering them, including control bytes, ANSI escapes, bidi controls, and zero-width display controls.

The target can’t wander off

This is the important one. After you confirm, Kickoutchi re-validates the target right before it signals:

  • It re-collects ports and checks the confirmed target still matches.
  • If the port’s owner changed, it aborts • no termination is sent.
  • If the owner became unreadable, it aborts as ownership-unavailable (exit 4).
  • If the target became protected in the meantime, it aborts (exit 6).

For normal process scope, only the confirmed PID is ever signalled. For tree/group scope, only the explicitly confirmed scope is signalled, after a fresh scan and verification.

Scoped-kill safety on Linux/macOS

Tree and group kill are ogre-sized controls: broader than one PID, so they use a stricter pipeline:

  • They are opt-in: --tree, --group, or TUI t/T for tree scope.
  • They count before signalling; cap refusals happen with zero side effects.
  • They freeze the root first, then sweep members to a fixed point.
  • They verify every stopped member’s identity where PID reuse is impossible, and pin that post-stop identity for rollback, so a recycled PID is resumed rather than signalled.
  • They thaw everything on any refusal, permission problem, identity drift, protected descendant, or partial metadata, and a cleanup error names only processes whose SIGCONT was refused.
  • Group termination queues every SIGTERM before any SIGCONT, so parent-like members cannot wake up early and spawn survivors.

Read the full flow in Scoped kills.

Scoped-kill safety on Windows

Windows tree kill uses Job Object containment rather than a freeze-first signal pipeline:

  • It preflights the confirmed root and observed tree before any Job Object assignment.
  • It refuses before commit for unsafe PIDs, protected descendants, incomplete metadata, identity drift, or an over-cap tree.
  • It proves Job Object freeze/thaw support on an empty disposable job before touching the target.
  • It treats assigning the root to the Job Object as the irreversible commit boundary.
  • It freezes the committed job for a final validation sweep, closing the descendant-spawn window, and reapplies --yes warning authorization during that sweep.
  • It withholds all termination when a live member cannot join the job, rather than terminating that process individually and reopening the containment gap.
  • It terminates contained members with hard termination and reports delivered, already-exited, unconfirmed, and not-terminated members separately.
  • It fails closed when missing creation-time metadata could hide a descendant inside the confirmed tree.

Platform specifics

In a nested Linux PID namespace, a process outside the namespace may still hold the same socket. Kickoutchi marks that ownership evidence as partial and refuses termination when the required ownership checks cannot be completed, even if one owner is visible.

Platform How termination stays honest
Linux Uses pidfd on kernel 5.3+ for delivery. Tree/group kill opens pidfds before SIGSTOP, then reuses them for thaw/final signals.
macOS No pidfd, so tree/group kill uses stop-verify: once a process is stopped, its verified PID cannot be recycled before the signal lands.
Windows Uses process handles for precise single-PID termination and Job Objects for CLI tree kill. inspect is available; --group and TUI t/T are not.

After the kick

After a successful termination, Kickoutchi performs a best-effort re-collection and reports whether the confirmed ports disappeared.

See the exit codes for how each of these outcomes is reported to scripts.