This is a submission for the Hacktoberfest Open-Source AI Challenge: Week 4, Theme: Ghost in the Machine.
What I Built
GhostWatch is an open-source, local-first AI investigation tool that helps you understand unusual computer activity through a clear timeline, evidence-backed findings, and plain-language explanations — without sending a single byte to a cloud API.
Your computer is constantly doing things in the background: processes starting, log entries being written, system events firing. Most of it is normal. Some of it isn't. But raw logs and process lists are unreadable noise for most people.
GhostWatch turns that noise into a transparent investigation report: what happened, what looks unusual, what the evidence supports, and what remains unknown.
praveen-pravi6B
/
ghostwatch
Local-first AI investigation tool for unusual computer activity. Hacktoberfest 2026.
GhostWatch
Local-first AI investigation tool for unusual computer activity.
GhostWatch collects process snapshots and OS log events, applies deterministic rules to identify interesting sequences, then asks a locally-running open-weight model to explain what the evidence shows — without sending a single byte to a cloud API.
Hacktoberfest 2026 — Ghost in the Machine challenge entry
What it does
-
Collects process snapshots (via
psutil) and OS log events (journalctlon Linux,log showon macOS). - Normalises everything into a shared event schema and stores it in a local SQLite database.
- Applies rules deterministically: temp-directory processes, interpreter download patterns, hidden process names, high-severity log entries.
- Redacts sensitive fields (tokens, passwords, API keys) before any AI inference.
- Asks a local Ollama model to explain the evidence, express uncertainty, and suggest manual follow-up steps.
- Displays deterministic findings and AI explanations separately — facts stay facts.
GhostWatch is a lightweight investigator, not…
The Theme Connection
The ghost in the machine is a perfect metaphor for what GhostWatch does. Your computer runs dozens of background processes you never see: processes launched from temporary directories, interpreters making network connections, privilege escalations happening in /tmp. This activity is the literal ghost in the machine — invisible, difficult to interpret, and easy to miss.
GhostWatch makes it visible. And it keeps the analysis on your own machine.
Demo
Activity timeline — real macOS process data
28 new processes observed since the last snapshot. The incremental collector only shows what changed, not the whole system every time.
AI investigation — qwen2.5:1.5b running locally
The AI correctly identifies gh as GitHub CLI, wdk as Automox remote management, and mdmdmclient as macOS MDM — all from local inference with no internet connection.
How It Works
The pipeline is deliberately simple and auditable:
- Collect native OS telemetry via psutil and journalctl / log show
- Normalize everything into a shared Pydantic v2 event schema
- Store locally in SQLite with deduplication
- Apply deterministic rules — no AI involved yet
- Redact credentials and tokens before building the prompt
- Ask the local model to explain the evidence
- Display rule findings and AI output in separate UI sections
Deterministic rules come first. Four rules in the MVP:
| Rule | What it flags |
|---|---|
| PROC_TEMP_DIR | Process launched from /tmp, /var/tmp, or Downloads |
| PROC_HIDDEN_NAME | Process name starts with a dot |
| INTERP_NETWORK_CMDLINE | Python/bash/ruby with network URLs in command line |
| HIGH_SEVERITY_LOG | Log entries already rated high by the OS |
The AI explains findings in plain language — it cannot override severity or declare the system compromised. That separation stays enforced in the UI.
Stack
| Layer | Technology |
|---|---|
| Backend | Python 3.11 + FastAPI |
| Validation | Pydantic v2 |
| Storage | SQLite via aiosqlite |
| Process data | psutil |
| Linux logs | journalctl --output=json |
| macOS logs | log show --style=json |
| Local AI | Ollama with qwen2.5:1.5b |
| Dashboard | Vue 3 + Vite |
Why Local Open-Weight AI
System logs contain sensitive information: process names, command-line arguments, usernames, file paths, error messages. Sending this to a hosted AI service means your logs leave your machine, a third-party retains them, and you have no control over what happens next.
With an open-weight model running in Ollama, none of that happens. The model runs at 127.0.0.1. The API is bound to localhost. GhostWatch validates the configured URL at startup and refuses to connect to anything that is not a local address:
def __init__(self, base_url: str, model: str, timeout: float = 120.0) -> None:
if not base_url.startswith(("http://127.0.0.1", "http://localhost")):
raise ValueError(
f"AI base_url must be a localhost address, got: {base_url!r}. "
"GhostWatch never connects to remote AI endpoints."
)
This is not a config flag. It is enforced in code. You can read it. You can fork it.
This is what open-source AI makes possible: you can inspect the guarantee, not just trust a privacy policy.
Redaction Before Inference
Even with a local model, log content can contain credentials — tokens, passwords, API keys embedded in command-line arguments. GhostWatch redacts before building the prompt:
_SECRET_PATTERNS = [
re.compile(r"(?i)(password|passwd|secret|token|api[_-]?key)\s*[=:]\s*\S+"),
re.compile(r"Bearer\s+[A-Za-z0-9\-._~+/]+=*"),
re.compile(r"sk-[A-Za-z0-9]{20,}"),
]
Dict keys are also checked by name. An api_key field gets its value replaced regardless of what the value looks like. The original events in SQLite are never modified; redaction happens on a copy immediately before the AI request is built.
Running It
git clone https://github.com/praveen-pravi6B/ghostwatch
cd ghostwatch
bash scripts/setup_dev.sh
# Sample mode — no privileges required
GHOSTWATCH_SAMPLE_MODE=true .venv/bin/ghostwatch
# In a second terminal
cd frontend && npm run dev
# Open http://localhost:5173
For AI explanations:
ollama pull qwen2.5:1.5b
GHOSTWATCH_MODEL=qwen2.5:1.5b GHOSTWATCH_SAMPLE_MODE=true .venv/bin/ghostwatch
Live mode on real OS telemetry:
GHOSTWATCH_MODEL=qwen2.5:1.5b .venv/bin/ghostwatch
Build Session
Here is the full Claude Code session where GhostWatch was built — from an empty directory to a working MVP in two days:
Limitations
GhostWatch is a lightweight investigator, not a security product.
- Process polling misses short-lived processes. A process that starts and exits between two snapshots will not appear.
- macOS Unified Logging applies privacy redactions. Some fields appear as private. GhostWatch notes this in the capability status.
- journalctl requires systemd. Non-systemd Linux distributions see the journal listed as unavailable.
- No kernel-level tracing. No eBPF, no kernel module, no EDR. Lightweight observer only.
- Small models make small mistakes. qwen2.5:1.5b is fast on CPU but not infallible. Deterministic rules are the authority on severity, not the AI.
Why Open Innovation Matters Here
Security tooling is one of the last places you should trust a black box.
If a tool explains why a process looks suspicious, you should be able to read the rules that produced that finding. If a tool redacts credentials before AI inference, you should be able to verify that it actually does. If a tool claims it does not send your logs anywhere, you should be able to confirm that in the source.
GhostWatch works with the internet off. It works when hosted services change their pricing. It works in environments where sending system logs to a third party is simply not acceptable.
That is not a marketing claim. It is the architecture.
What's Next
- Live collection loop with configurable intervals
- More detection rules: unusual parent-child relationships, processes on unexpected ports
- Ubuntu CI matrix
- Baseline snapshots to flag new processes not seen in a previous run
Built with Python, FastAPI, Vue 3, Pydantic v2, psutil, aiosqlite, and Ollama. Tested on macOS. Sample mode works without OS privileges or a running Ollama instance. 40 tests, Ruff clean.


Top comments (0)