Agent skill
sysinfo
System and process information for Rust applications
Install this agent skill to your Project
npx add-skill https://github.com/johnlindquist/script-kit-next/tree/main/.opencode/skill/sysinfo
SKILL.md
sysinfo
Cross-platform library for retrieving system information: processes, CPUs, memory, disks, and networks.
Key Types
Core Types
| Type | Purpose |
|---|---|
System |
Main struct holding all system information |
Process |
Information about a single process |
Pid |
Process identifier (platform-specific wrapper) |
ProcessesToUpdate |
Enum specifying which processes to refresh |
Refresh Kind Types (Performance Critical)
| Type | Purpose |
|---|---|
ProcessRefreshKind |
Controls what process info to refresh |
RefreshKind |
Controls what system info to refresh |
UpdateKind |
Never, OnlyIfNotSet, or Always |
Usage in script-kit-gpui
Process Manager (process_manager.rs)
The crate is used for orphan process detection - checking if child bun processes are still running:
use sysinfo::{Pid, System};
/// Check if a process is currently running
pub fn is_process_running(&self, pid: u32) -> bool {
let mut system = System::new();
system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
system.process(Pid::from_u32(pid)).is_some()
}
Key patterns used:
System::new()- Create minimal system instancerefresh_processes(ProcessesToUpdate::All, true)- Refresh all processes, remove dead onessystem.process(Pid::from_u32(pid))- Look up specific process by PIDPid::from_u32()- Convert platform u32 to sysinfo's Pid type
Process Information
Checking if Process Exists
use sysinfo::{Pid, ProcessesToUpdate, System};
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
// Check by PID
if let Some(process) = sys.process(Pid::from_u32(1234)) {
println!("Process {} is running", process.name().to_string_lossy());
}
// Check specific PIDs only (more efficient)
let pids = [Pid::from_u32(1234), Pid::from_u32(5678)];
sys.refresh_processes(ProcessesToUpdate::Some(&pids), true);
Process Properties
// Available on Process
process.pid() // -> Pid
process.name() // -> &OsStr (limited to 15 chars on Linux!)
process.exe() // -> Option<&Path>
process.cmd() // -> &[OsString]
process.cwd() // -> Option<&Path>
process.environ() // -> &[OsString]
process.memory() // -> u64 (RSS in bytes)
process.virtual_memory() // -> u64
process.cpu_usage() // -> f32 (percentage)
process.status() // -> ProcessStatus
process.parent() // -> Option<Pid>
process.start_time() // -> u64 (Unix timestamp)
process.run_time() // -> u64 (seconds)
Killing Processes
use sysinfo::Signal;
// Simple kill (SIGKILL)
process.kill();
// Kill with specific signal
if let Some(success) = process.kill_with(Signal::Term) {
println!("Signal sent: {}", success);
}
// Wait for termination
process.wait();
Refresh Patterns
CRITICAL: Always Refresh Before Reading
sysinfo works on diffs - you must refresh to get current data:
// BAD - stale data
let sys = System::new_all();
let mem = sys.used_memory(); // May be outdated!
// GOOD - fresh data
let mut sys = System::new();
sys.refresh_memory();
let mem = sys.used_memory();
Performance: Refresh Only What You Need
use sysinfo::{ProcessRefreshKind, ProcessesToUpdate, System};
// SLOW - refreshes everything
sys.refresh_all();
// FAST - only refresh processes, only memory info
sys.refresh_processes_specifics(
ProcessesToUpdate::All,
true, // remove dead processes
ProcessRefreshKind::nothing().with_memory(),
);
// FASTEST - check specific PIDs only
let pids = [Pid::from_u32(1234)];
sys.refresh_processes(ProcessesToUpdate::Some(&pids), true);
ProcessRefreshKind Builder
use sysinfo::{ProcessRefreshKind, UpdateKind};
// Nothing (fastest)
ProcessRefreshKind::nothing()
// Everything (slowest)
ProcessRefreshKind::everything()
// Custom - only what you need
ProcessRefreshKind::nothing()
.with_memory() // RSS, virtual memory
.with_cpu() // CPU usage
.with_disk_usage() // Disk I/O
.with_exe(UpdateKind::OnlyIfNotSet) // Executable path
Reuse System Instance
// BAD - creates new instance each time
fn check_process(pid: u32) -> bool {
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
sys.process(Pid::from_u32(pid)).is_some()
}
// GOOD - reuse instance (especially for CPU usage which needs history)
struct ProcessMonitor {
sys: System,
}
impl ProcessMonitor {
fn check_process(&mut self, pid: u32) -> bool {
self.sys.refresh_processes(ProcessesToUpdate::All, true);
self.sys.process(Pid::from_u32(pid)).is_some()
}
}
CPU Usage Notes
CPU usage requires two measurements with time between them:
use sysinfo::{System, MINIMUM_CPU_UPDATE_INTERVAL};
use std::thread;
let mut sys = System::new_all();
// First measurement (will be 0%)
sys.refresh_cpu_usage();
// Wait minimum interval
thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
// Second measurement (accurate)
sys.refresh_cpu_usage();
for cpu in sys.cpus() {
println!("{}%", cpu.cpu_usage());
}
Platform Differences
Process Names on Linux
- Limited to 15 characters
- May not match executable name
- Use
process.exe()for full path when available
macOS Sandboxing
For App Store apps, use feature flags:
[dependencies]
sysinfo = { version = "0.33", features = ["apple-app-store"] }
Windows
- Admin privileges may be needed for some process info
- PID is
usize, notpid_t
Pid Conversions
use sysinfo::Pid;
// From u32 (most portable)
let pid = Pid::from_u32(1234);
// To u32
let n: u32 = pid.as_u32();
// From/to usize (platform-specific)
let pid = Pid::from(1234_usize);
let n: usize = pid.into();
// Parse from string
let pid: Pid = "1234".parse().unwrap();
Anti-patterns
Creating System::new_all() Repeatedly
// BAD - expensive allocation every call
fn get_memory() -> u64 {
System::new_all().used_memory()
}
// GOOD - reuse instance
fn get_memory(sys: &mut System) -> u64 {
sys.refresh_memory();
sys.used_memory()
}
Not Refreshing Before Reading
// BAD - returns initialization values (often 0)
let sys = System::new();
let procs = sys.processes(); // Empty!
// GOOD
let mut sys = System::new();
sys.refresh_processes(ProcessesToUpdate::All, true);
let procs = sys.processes();
Refreshing Everything When You Need One Thing
// BAD - refreshes CPUs, memory, processes, etc.
sys.refresh_all();
let mem = sys.used_memory();
// GOOD - only refresh memory
sys.refresh_memory();
let mem = sys.used_memory();
Trusting process.name() on Linux
// BAD - may be truncated or changed
let name = process.name(); // "my-very-long-a" (truncated!)
// GOOD - use exe when available
let name = process.exe()
.and_then(|p| p.file_name())
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| process.name().to_string_lossy().to_string());
Reading CPU Usage Without History
// BAD - first reading is always 0%
let mut sys = System::new_all();
let cpu = sys.global_cpu_usage(); // 0%!
// GOOD - wait for second sample
let mut sys = System::new_all();
std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
sys.refresh_cpu_usage();
let cpu = sys.global_cpu_usage(); // Accurate!
Common Patterns
Find Process by Name
// Exact name match
for process in sys.processes_by_exact_name("bun".as_ref()) {
println!("{}: {}", process.pid(), process.name().to_string_lossy());
}
// Substring match
for process in sys.processes_by_name("bun".as_ref()) {
println!("{}: {}", process.pid(), process.name().to_string_lossy());
}
Monitor Process Until Exit
use std::time::Duration;
fn wait_for_exit(pid: u32, timeout: Duration) -> bool {
let mut sys = System::new();
let deadline = std::time::Instant::now() + timeout;
let target_pid = Pid::from_u32(pid);
while std::time::Instant::now() < deadline {
sys.refresh_processes(
ProcessesToUpdate::Some(&[target_pid]),
true
);
if sys.process(target_pid).is_none() {
return true; // Process exited
}
std::thread::sleep(Duration::from_millis(100));
}
false // Timeout
}
Feature Flags
[dependencies]
sysinfo = { version = "0.33", default-features = false }
# Optional features:
# - multithread: Parallel refresh (increases memory on macOS)
# - serde: Serialize System and related types
# - apple-app-store: Disable APIs prohibited in App Store
# - apple-sandbox: Sandbox-safe subset
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
Generate Component Documentation
Based on existing docs styles and specific API implementations, and referencing same name stories, generate comprehensive documentation for the new component.
Generate Component Story
Generate a comprehensive story for a new component for as example.
new-component
How to write a new component of GPUI Component.
troubleshooting
Diagnose and fix common Script Kit issues. Use when the user reports bugs, crashes, missing features, or unexpected behavior in Script Kit GPUI.
script-authoring
Create and manage TypeScript scripts for Script Kit. Use when the user wants to write a new script, edit an existing script, or understand Script Kit's SDK and metadata system.
agents
Create mdflow-backed agent files for Script Kit. Use when the user wants to create AI agents, configure agent backends (Claude, Gemini, Codex), or manage agent metadata.
Didn't find tool you were looking for?