Probe is a lightweight, cross-platform Go library for detecting whether a file descriptor is connected to a terminal. It is designed for high performance, thread safety, and ease of use in modern Go applications.
- ⚡ High Performance — Fast terminal detection with intelligent result caching
- 🌍 Cross-Platform — Works seamlessly on Windows, macOS, Linux, BSD, and more
- 🧵 Thread-Safe — Fully safe for concurrent use across goroutines
- 🧠 Zero Allocations — Designed to avoid heap allocations entirely
- 🧩 Minimal Dependencies — Built using only the Go standard library and x/sys
- 🧼 Simple API — Clean and intuitive interface for fast integration
go get github.com/droqsic/probepackage main
import (
"fmt"
"os"
"github.com/droqsic/probe"
)
func main() {
// Check if standard streams are terminals
if probe.IsTerminal(os.Stdout.Fd()) {
fmt.Println("Stdout is a terminal")
} else {
fmt.Println("Stdout is not a terminal (redirected to a file or pipe)")
}
// On Windows, check for Cygwin/MSYS2 terminals
if probe.IsCygwinTerminal(os.Stdout.Fd()) {
fmt.Println("Running in a Cygwin/MSYS2 terminal")
}
}Probe is engineered for speed. Its caching layer makes repeated checks on the same file descriptor nearly instantaneous. Here are benchmark results under typical usage:
BenchmarkIsTerminal 89545555 13.61 ns/op 0 B/op 0 allocs/op
BenchmarkIsCygwinTerminal 89867444 13.68 ns/op 0 B/op 0 allocs/op
These results demonstrate Probe's ultra-low overhead and suitability for high-throughput applications.
Probe uses platform-specific mechanisms for terminal detection:
- Unix-like systems: Uses appropriate ioctl calls (
TIOCGETA,TCGETS, orTCGETA) - Windows: Uses the Win32
GetConsoleModefunction - Cygwin/MSYS2: Detects special named pipes used by Cygwin terminals
- WebAssembly: Detects terminals based on Node.js environment variables
- Other platforms: Always returns
false
All results are cached after the first check per file descriptor to avoid repeated syscalls.
| Platform | Support | Implementation |
|---|---|---|
| Windows | ✅ | GetConsoleMode |
| Linux | ✅ | TCGETS ioctl |
| Android | ✅ | TCGETS ioctl |
| macOS (Darwin) | ✅ | TIOCGETA ioctl |
| iOS | ✅ | TIOCGETA ioctl |
| FreeBSD | ✅ | TIOCGETA ioctl |
| OpenBSD | ✅ | TIOCGETA ioctl |
| NetBSD | ✅ | TIOCGETA ioctl |
| DragonFly BSD | ✅ | TIOCGETA ioctl |
| Hurd | ✅ | TIOCGETA ioctl |
| z/OS | ✅ | TIOCGETA ioctl |
| Solaris | ✅ | TCGETA ioctl |
| Illumos | ✅ | TCGETA ioctl |
| Haikou | ✅ | TCGETA ioctl |
| AIX | ✅ | TCGETA ioctl |
| Plan9 | ✅ | Fd2path |
| WebAssembly | ✅ | Node.js detection |
Other platforms will compile but terminal detection will always return false.
Probe is built with concurrency in mind. It uses a read-write mutex to protect its internal cache, allowing many goroutines to read in parallel while safely handling updates. The design ensures scalability and efficiency for read-heavy workloads.
Contributions are welcome! Whether you're fixing bugs, adding features, or improving documentation, your input helps make Probe better for everyone.
- Read the Contributing Guidelines
- Follow the Code of Conduct
Probe is released under the MIT License. For the full license text, please see the LICENSE file.
Probe is inspired by go-isatty by Yasuhiro Matsumoto. While conceptually similar, Probe provides an enhanced implementation focused on performance and scalability.
Special thanks to:
- The Go team for their exceptional language and tooling
- The maintainers of x/sys for low-level system access
- All contributors who help make Probe better