Thank you for considering contributing to ProcLens! This document covers the development setup, project structure, contribution workflows, and instructions on how to configure and execute ProcLens across various environments (bare-metal, VMs, Docker, and Kubernetes).
- Code of Conduct
- Ways to Contribute
- Development Setup
- Deployment & Execution Guide
- Project Structure
- Branch & Commit Conventions
- Adding a New Workload Archetype
- Pull Request Process
- Testing Requirements
- Code Style Guidelines
- Reporting Issues
All contributors are expected to follow the Code of Conduct. We are committed to keeping this a welcoming, respectful, and productive community.
| Contribution Type | Examples |
|---|---|
| 🐛 Bug Fix | Address a panic, wrong classification, or incorrect recommendation |
| ✨ New Feature | Introduce a new archetype, LLM provider support, or CLI command |
| 📖 Documentation | Improve code comments, terminologies, guides, or this reference |
| 🧪 Tests | Add table-driven tests, fuzz target checks, or benchmark scenarios |
| 🎨 UI/UX | Refine the Google Material ANSI colours or console outputs |
| ⚡ Performance | Reduce latency or memory allocations during process discovery |
To build and run ProcLens from source locally:
# 1. Fork the repo, then clone your fork
git clone https://github.com/<your-username>/proc-lens.git
cd proc-lens
# 2. Verify Go version is 1.24+
go version
# 3. Download dependencies
go mod download
# 4. Build the binary
go build -o proc-lens ./cmd/proc-lens
# 5. Run the full test suite
go test ./... -count=1
# 6. Run a quick smoke test
./proc-lens scan -d 1sProcLens operates in two distinct execution modes:
All core subcommands (scan, analyze, run) run entirely locally.
- Zero Outbound Connections: Requires no external network access, API keys, or heavy machine learning runtimes.
- Low Overhead: Features are scaled and compared using a fast, absolute-difference distance model in under 10 microseconds per process.
The enrich subcommand overlays process classification telemetry with generative SRE diagnostics:
- Enriched Analysis: Combines node coordinates (RAM, cores, kernel version) and process outputs, submitting them to a generative AI endpoint for diagnostic narratives.
- Supported Backends: Gemini, OpenAI, Claude, xAI (Grok), and self-hosted local Ollama instances.
Telemetry collection adapts to host platform support and capabilities:
| Telemetry Attribute | Linux VM (Root) | Linux VM (User) | Windows VM | macOS VM | Container (Docker/K8s) |
|---|---|---|---|---|---|
| CPU / RSS / Threads | Yes | Yes | Yes | Yes | Yes |
| Voluntary/Involuntary Ctx | Yes | Yes | No | No | Yes |
| Open FD Counts | Yes | Only Own | Yes | Yes | Yes |
| Socket Fast Path | Yes | Only Own | No (Fallback) | No (Fallback) | Yes (via SYS_PTRACE) |
| Parent PID & Name | Yes | Yes | Yes | Yes | Yes |
| Linux OOM Score & Adj | Yes | Yes | No | No | Yes |
| cgroups (v1/v2) Paths | Yes | Yes | No | No | Yes |
| Kubernetes Metadata | No | No | No | No | Yes (via /var/log/containers) |
Note: If a metric is unsupported (e.g. OOM scores on Windows) or blocked by permissions (e.g. scanning another user's file descriptors as a non-root user), ProcLens degrades gracefully, defaults the fields to 0/empty, and continues execution.
./proc-lens scan -c 0.1 -m 5.0 -d 1sCalculates process activity rates over a 1-second window and lists active processes consuming >0.1% CPU or >5.0 MB RAM.
./proc-lens scan --loop --interval 10sIn loop mode, rates are estimated using cached metrics from the previous iteration to eliminate double-sampling overhead.
./proc-lens analyze --pid 1024 --duration 2s./proc-lens run --cmd "tar -czf backup.tar.gz /var/log" --duration 3s --allow-run- Set your API key and include the mandatory
--allow-remote-llmsecurity gate flag.
export GEMINI_API_KEY="your-gemini-key"
./proc-lens enrich --top 5 --allow-remote-llm- Or query a local Ollama instance (no remote security flag or API keys required):
./proc-lens enrich --endpoint "http://localhost:11434/v1/chat/completions" --model "llama3" --top 5Because the container runs as the unprivileged user nobody (UID 65534), you must share the host's PID namespace and mount /proc and /sys to introspect the host:
docker run -d --name proc-lens \
--pid=host --cap-add=SYS_PTRACE \
-v /proc:/host/proc:ro -v /sys:/host/sys:ro \
-e HOST_PROC=/host/proc -e HOST_SYS=/host/sys \
proc-lens:latestTo run as a DaemonSet to gather process intelligence from every worker node:
Verify that the Helm chart configuration (deploy/proc-lens/values.yaml) runs without root privileges:
hostNetwork: false
podSecurityContext:
runAsUser: 65534
runAsGroup: 65534
fsGroup: 65534
securityContext:
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
runAsNonRoot: true
capabilities:
add:
- SYS_PTRACE
drop:
- ALL# Lint chart templates
helm lint deploy/proc-lens
# Deploy deployment agent
helm upgrade --install proc-lens deploy/proc-lens --namespace kube-system- Health Check: Port
8091exposes/healthzfor liveness and readiness audits. - Scraping Endpoint: Exposes low-cardinality Prometheus metrics
/metrics(e.g. process count per category) to prevent TSDB index bloat.
- Least-Privilege Bounds: Ensure containers drop all capabilities, disable privilege escalation, and only request
CAP_SYS_PTRACE. - HTTP Hardening: Supply
--http-bearer-tokento secure metrics endpoints in production environments. - Ingress Bounds: Set
NetworkPolicyto allow incoming traffic only from designated Prometheus collector namespaces. - Command-Line Security: Keep
--expose-cmdline=falsein production deployment flags to prevent environment variables and passwords from leaking to metrics logs.
proc-lens/
├── cmd/proc-lens/ # Main entrypoint (main.go)
├── pkg/
│ ├── classifier/ # 37-archetype absolute-difference classifier
│ │ ├── types.go # Category constants (one per archetype)
│ │ ├── centroids.go # Reference feature vectors per archetype
│ │ ├── classifier.go # Predict() + rule boosters
│ │ └── classifier_test.go
│ ├── collector/ # /proc telemetry collection (gopsutil)
│ ├── cmd/ # Cobra subcommands (scan, analyze, enrich, ...)
│ ├── optimizer/ # Kernel tuning recommendations + validation
│ ├── explain/ # "Why was this classified X?" explainer
│ ├── pressure/ # Linux PSI collection
│ ├── hardware/ # NUMA / storage / SIMD topology
│ ├── completeness/ # Data completeness score tracker
│ └── metrics/ # Prometheus low-cardinality metrics
├── deploy/proc-lens/ # Helm chart (DaemonSet)
├── .goreleaser.yml # GoReleaser v2 release pipeline
├── terminologies.md # Plain-English concept glossary
└── CONTRIBUTING.md # This file
Branch naming format:
feat/add-graphdb-archetype · fix/context-canceled-enrich · docs/update-readme-archetypes · test/fuzz-classifier-edge-cases
Commit messages must follow Conventional Commits:
feat(classifier): add GraphDB and TimeSeriesDB archetypesfix(enrich): use gemini-flash-latest model aliasdocs(readme): update archetype table to 37 categoriestest(classifier): add table-driven tests for all new archetypes
Adding an archetype involves editing exactly 4 files in this order:
pkg/classifier/types.go: Add theCategoryconstant inside the correct tier.pkg/classifier/centroids.go: Define typical profile values inside theCentroidsmap.pkg/classifier/classifier.go: Add name/cmdline boosters to adjust classifier weights.pkg/classifier/classifier_test.go: Add a table-driven test insideTestPredictNewArchetypesand register the category constant.- Update README.md: Register the category in the Comparison and Archetypes tables.
- Fork the repository and create your branch from
main. - Ensure the full test suite passes:
go test ./... -count=1. - Ensure the project builds cleanly:
go build ./.... - Document any new user-facing configuration options, commands, or behaviours.
- Open a Pull Request referencing the issue it addresses and outlining the design choices.
- Verification Build:
go build ./... - Test Verification:
go test ./... -count=1 - Fuzzing Checks:
go test ./pkg/classifier -fuzz=FuzzPredict -fuzztime=30s - Performance Benchmarks:
go test ./pkg/classifier -bench=. -run=^$
- Adhere to standard Go styling guidelines (
gofmt,go vet). - All tests should be table-driven and use
t.Run()scopes. - Add package-level comment headers with
Note:andCaveat:sections for new files. - Error messages should be lowercase and properly wrapped (e.g.
"failed to read /proc/stat: %w"). - Avoid informal phrasing ("kindly", "do the needful") in comments or documentation.
- Use GitHub Issues to report bugs, suggest features, or ask questions.
- Security vulnerabilities must be reported via GitHub's Private Security Advisory feature rather than a public ticket.