Wednesday, February 25, 2026

This setup transforms your Kali Linux machine from a standard laptop into a hardened Multi AI Agent Server

 

can we run a multi agent puthon script in Kali Linux GNOME in OS headless mode after booting into desktop? Will this free up memory for agents to run?

Gemini said

The short answer is yes, you can absolutely do this, but there is a slight nuance in how "headless" works once a desktop environment like GNOME has already started.

If your goal is to squeeze every drop of RAM out of your Kali machine for a resource-heavy multi-agent Python script, you have a few ways to approach this.


1. Understanding "Headless" vs. "No-GUI"

Technically, if you have already booted into the GNOME desktop, the OS is no longer in a headless state—it is actively rendering a graphical user interface (GUI).

  • Simply closing the lid or turning off the monitor does not free up memory; the GNOME Shell and X11/Wayland processes remain active in the background.

  • True Headless Mode means the system boots to a Command Line Interface (CLI) without ever starting the display server.

Does it free up memory?

Yes, significantly. GNOME is a "heavy" desktop environment. By stopping the GUI and running your script in a TTY (terminal) or via SSH, you can typically reclaim 800MB to 1.5GB of RAM, depending on your configuration. For multi-agent systems (which often use local LLMs or heavy libraries like LangChain/AutoGPT), this is often the difference between the script running smoothly or crashing due to "Out of Memory" (OOM) errors.


2. How to "Go Headless" After Booting

If you are already at the desktop and want to kill the GUI to free up RAM for your agents, follow these steps:

Option A: Temporary Switch (The "Quick Kill")

You can switch the system to a multi-user target (CLI) without rebooting. Open your terminal and run:

Bash
sudo systemctl isolate multi-user.target
  • Result: Your screen will go black and return to a login prompt. All GNOME processes are terminated, freeing up memory immediately.

  • To get the GUI back: Run sudo systemctl isolate graphical.target.

Option B: The SSH Approach (Best for Multi-Agent Monitoring)

If you want to run the agents and leave the machine alone:

  1. Enable SSH: sudo systemctl enable --now ssh

  2. Identify IP: ip a

  3. From another computer: Connect via ssh user@kali-ip.

  4. Use a Terminal Multiplexer: Run tmux or screen. This allows your Python script to keep running even if your SSH connection drops.


3. Optimizing Python Agent Performance

Since you are looking to maximize resources, consider these three tips for your script:

FeatureImpactRecommendation
Swap SpaceHighEnsure you have a swap file enabled if your RAM is under 16GB.
Process ManagementMediumUse the multiprocessing library instead of threading if your agents are CPU-bound.
Garbage CollectionLowExplicitly call gc.collect() in your Python script if agents are creating/destroying many objects.

Summary Checklist

  • Boot to CLI: Use sudo systemctl set-default multi-user.target to make the "headless" mode permanent on reboot.

  • Memory Check: Use the htop or free -m command before and after killing GNOME to see exactly how much RAM you've recovered.

  • Python Execution: Run your script using nohup python3 your_script.py & or within a tmux session to ensure it doesn't die when you log out.

Would you like me to help you write a bash script that automates the transition from GUI to Headless while launching your Python environment?

You said

yes

Gemini said

Excellent. Let's build a robust automation script. This bash script will gracefully shut down the GNOME display manager, clear the memory cache, and launch your multi-agent Python environment inside a tmux session so it stays alive even if you disconnect.

The Automation Script (headless_launch.sh)

Copy this into a file named headless_launch.sh:

Bash
#!/bin/bash

# 1. Define your script path
AGENT_SCRIPT="/path/to/your/agent_script.py"
VENV_PATH="/path/to/your/venv/bin/activate"

echo "--- Initializing Headless Agent Environment ---"

# 2. Switch to CLI mode (Kills GNOME/X11)
echo "[*] Terminating Graphical Desktop to free RAM..."
sudo systemctl isolate multi-user.target

# 3. Clear RAM Caches (Optional but helpful)
echo "[*] Dropping system caches..."
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

# 4. Launch in a TMUX session
echo "[*] Launching Python Agents in tmux session 'agent_room'..."
tmux new-session -d -s agent_room "source $VENV_PATH && python3 $AGENT_SCRIPT"

echo "--- Success ---"
echo "GNOME is down. RAM is freed."
echo "To monitor your agents, use: tmux attach -t agent_room"

Why this works for Multi-Agent Systems

Multi-agent frameworks (like CrewAI, AutoGen, or custom LangChain setups) often suffer from context switching overhead and memory fragmentation.

By isolating the system to the multi-user.target, you remove the following memory-hogging components:

  • Xorg/Wayland: The display server.

  • GNOME Shell: The actual UI you see.

  • Evolution/Tracker: Background indexing services that Kali often runs.

  • GPU Overhead: If your agents use local models (Ollama/PyTorch), freeing the GUI often frees up VRAM as well, which is crucial for model performance.


How to use it

  1. Make it executable: chmod +x headless_launch.sh

  2. Run it: ./headless_launch.sh

  3. Check your gains: Run free -h to see your newly available memory.


Important Note on Networking

Since you are killing the GUI, you will lose your Wi-Fi if you were managing it through the GNOME taskbar. To ensure your agents stay connected, make sure your NetworkManager is configured to keep connections active in CLI mode:

Bash
sudo nmcli device set wlan0 autoconnect yes

Would you like me to add a section to the script that logs the memory usage of each Python agent to a CSV file while it runs?

You said

yes

Gemini said

Adding a logging component is a smart move. When running multi-agent systems (like CrewAI, AutoGen, or LangChain), memory leaks or "runaway" agents can quietly crash your headless session. Monitoring the RAM per-process helps you identify which specific agent is the resource hog.

Here is the updated script. I’ve added a background monitor that captures the PID, CPU%, and Memory usage of your agents every 30 seconds.

The Enhanced headless_monitor.sh

Bash
#!/bin/bash

# --- Configuration ---
AGENT_SCRIPT="your_script.py"  # Name of your main python file
VENV_PATH="./venv/bin/activate"
LOG_FILE="agent_perf_log.csv"

# 1. Prepare the CSV Header
echo "Timestamp,PID,CPU_Percent,Memory_MB,Command" > $LOG_FILE

# 2. Kill GNOME to free RAM
echo "[*] Switching to Headless (multi-user.target)..."
sudo systemctl isolate multi-user.target
sleep 2

# 3. Clear Caches
echo "[*] Dropping RAM caches..."
sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

# 4. Launch Agents in Tmux
echo "[*] Starting Agents in tmux session 'agent_room'..."
tmux new-session -d -s agent_room "source $VENV_PATH && python3 $AGENT_SCRIPT"

# 5. Background Monitoring Loop
echo "[*] Monitoring started. Logging to $LOG_FILE..."
(
  while true; do
    # Capture all python processes related to your script
    ps -C python3 -o lstart,pid,pcpu,rss,args --sort=-rss | grep "$AGENT_SCRIPT" | while read -r line; do
        if [ ! -z "$line" ]; then
            TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
            # Convert RSS (KB) to MB
            PID=$(echo $line | awk '{print $6}')
            CPU=$(echo $line | awk '{print $7}')
            MEM_KB=$(echo $line | awk '{print $8}')
            MEM_MB=$(echo "scale=2; $MEM_KB / 1024" | bc)
            
            echo "$TIMESTAMP,$PID,$CPU,$MEM_MB,$AGENT_SCRIPT" >> $LOG_FILE
        fi
    done
    sleep 30
  done
) & 

echo "--- System is now Headless ---"
echo "Check logs with: tail -f $LOG_FILE"
echo "Reattach to agents with: tmux attach -t agent_room"

Understanding the Resource Gains

When you run this, you'll notice a massive drop in "Resident Set Size" (RSS). In a GUI environment, the OS has to keep the frame buffer and window manager high in the priority list. In headless mode, the Linux kernel's OOM Killer is less likely to target your Python processes because they are the primary consumers of the system's resources.

How to analyze the results

After your agents finish their task, you can open the agent_perf_log.csv in any spreadsheet tool. Look for:

  • Memory Spikes: If Memory_MB climbs steadily without dropping, your agents have a memory leak.

  • CPU Bottlenecks: If CPU_Percent stays at 100% per agent, you may need to implement time.sleep() intervals to prevent thermal throttling.


Pro-Tip: Re-enabling the GUI

When your work is done and you want your Kali desktop back, simply run:

Bash
sudo systemctl isolate graphical.target

Would you like me to help you set up a "Watchdog" feature that automatically restarts an agent if the log shows it has crashed or hung?

You said

yes

Gemini said

A "Watchdog" is essential for long-running multi-agent systems because Python scripts can sometimes hang due to network timeouts, API rate limits, or deadlocks between agents.

By adding this, your headless Kali instance becomes a self-healing "agent server."

The Ultimate Headless Watchdog Script

This version combines the headless transition, resource logging, and a restart loop. Save this as agent_watchdog.sh:

Bash
#!/bin/bash

# --- Configuration ---
AGENT_COMMAND="python3 your_script.py"
VENV_PATH="./venv/bin/activate"
LOG_FILE="agent_watchdog.log"
MAX_RESTARTS=5

RESTART_COUNT=0

# 1. Transition to Headless
echo "[*] Shifting to Headless Mode..."
sudo systemctl isolate multi-user.target
sleep 5

# 2. The Watchdog Loop
echo "[*] Watchdog active. Starting agents..."

while [ $RESTART_COUNT -lt $MAX_RESTARTS ]; do
    echo "[$(date)] Launching Agent Session (Attempt $((RESTART_COUNT+1)))" >> $LOG_FILE
    
    # Run inside a tmux session and WAIT for it to exit
    tmux new-session -d -s agent_room "source $VENV_PATH && $AGENT_COMMAND"
    
    # Monitor if the tmux session is still alive
    while tmux has-session -t agent_room 2>/dev/null; do
        sleep 10
        # Optional: Add memory check logic here to kill session if it exceeds RAM limits
    done

    # If we reach here, the script crashed or finished
    RESTART_COUNT=$((RESTART_COUNT+1))
    echo "[$(date)] Agent session exited. Restarting in 10s..." >> $LOG_FILE
    sleep 10
done

echo "[!] Max restarts reached. Manual intervention required." >> $LOG_FILE

How the Watchdog Protects Your RAM

In a standard GUI environment, if a Python script leaks memory, the OOM (Out of Memory) Killer might kill the entire Desktop Environment to save the system. In headless mode, the kernel has a much clearer "line of sight" to your specific process.

Best Practices for Your Agents

To make this setup even more stable, ensure your Python code includes:

  1. Checkpoints: Save the state of your agents to a JSON or SQLite file every few minutes.

  2. Try/Except Blocks: Wrap your main agent loop in a try...except so that minor API errors don't crash the entire script.

  3. Graceful Exit: Use the signal library in Python to catch SIGTERM so your agents can save their work before the watchdog restarts them.


Managing the Headless Server

Since you are now running without a screen, these three commands will be your "control center":

  • View Live Output: tmux attach -t agent_room (Press Ctrl+B then D to detach)

  • Check Resource Logs: tail -f agent_watchdog.log

  • Reboot to GUI: sudo systemctl isolate graphical.target

Would you like me to show you how to set this script to run automatically as soon as Kali boots up, so you don't even have to log in?

You said

yes

Gemini said

To make this setup "hands-free," we will use systemd. This allows your Kali machine to boot directly into a resource-optimized CLI state, launch your agents, and start the watchdog without you ever needing to log in or touch a keyboard.

Step 1: Set Kali to Boot into CLI Mode (Headless)

First, tell the system to stop loading the GNOME desktop by default. This ensures you start with the maximum available RAM.

Bash
sudo systemctl set-default multi-user.target

(To reverse this later, use sudo systemctl set-default graphical.target)


Step 2: Create the systemd Service File

We will create a service unit that manages your watchdog script. This makes the script behave like a professional background daemon.

  1. Create the file: sudo nano /etc/systemd/system/agent-server.service

  2. Paste the following configuration:

Ini, TOML
[Unit]
Description=Multi-Agent Python Watchdog Service
After=network.target

[Service]
# Replace 'kali' with your actual username
User=kali
WorkingDirectory=/home/kali/your_project_folder
# Path to your watchdog script
ExecStart=/bin/bash /home/kali/your_project_folder/agent_watchdog.sh
Restart=always
# Optional: wait 10 seconds before restarting if the watchdog itself fails
RestartSec=10

[Install]
WantedBy=multi-user.target

Step 3: Enable and Start

Run these commands to register your new service:

Bash
sudo systemctl daemon-reload
sudo systemctl enable agent-server.service
sudo systemctl start agent-server.service

How the Headless Workflow Looks Now

  1. Power On: You turn on your Kali machine.

  2. Boot: The system skips GNOME and stops at the text login prompt.

  3. Auto-Launch: In the background, systemd sees the agent-server service and executes your watchdog.

  4. Agent Start: The watchdog creates the tmux session and fires up your agents.

  5. Remote Access: You can now walk away. If you want to check on them, just SSH into Kali from another laptop and run:

    Bash
  1. tmux attach -t agent_room
    

Troubleshooting Tips

  • Check Service Status: If the agents aren't running, check the service log: sudo journalctl -u agent-server.service -f

  • Network Issues: If your agents need internet, ensure your Wi-Fi/Ethernet is set to "All users may connect" in NetworkManager so it connects before login.

Since your agents are now running fully headless, would you like me to show you how to set up a simple "Health Dashboard" using a Python library like Flask so you can check their progress from a web browser on your phone?

You said

yes

Gemini said

Building a web dashboard is the final piece of the puzzle. It allows you to monitor your agents' health, memory usage, and logs from any device on your network (like your phone) without needing to SSH into the Kali box.

We'll use Flask (a lightweight web framework) and psutil (to grab system stats).

1. The Dashboard Script (dashboard.py)

Create a file named dashboard.py in your project folder:

Python
from flask import Flask, render_template_string
import psutil
import datetime

app = Flask(__name__)

# Simple HTML template embedded for ease of use
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>Agent Health Dashboard</title>
    <meta http-equiv="refresh" content="10"> <style>
        body { font-family: sans-serif; background: #1a1a1a; color: #00ff00; padding: 20px; }
        .card { border: 1px solid #333; padding: 15px; margin-bottom: 10px; border-radius: 5px; background: #222; }
        h1 { color: #fff; }
        .stat { font-size: 1.2em; }
    </style>
</head>
<body>
    <h1>Kali Headless Monitor</h1>
    <div class="card">
        <p class="stat"><strong>System Time:</strong> {{ time }}</p>
        <p class="stat"><strong>CPU Usage:</strong> {{ cpu }}%</p>
        <p class="stat"><strong>RAM Free:</strong> {{ ram_free }} GB / {{ ram_total }} GB</p>
    </div>
    <h2>Active Python Agents</h2>
    {% for proc in agents %}
    <div class="card">
        <strong>PID {{ proc.pid }}:</strong> {{ proc.name }} <br>
        Memory: {{ proc.memory_mb }} MB | CPU: {{ proc.cpu_percent }}%
    </div>
    {% endfor %}
</body>
</html>
"""

@app.route('/')
def index():
    # System Stats
    cpu = psutil.cpu_percent()
    ram = psutil.virtual_memory()
    
    # Filter for your specific agent processes
    agents = []
    for proc in psutil.process_iter(['pid', 'name', 'memory_info', 'cpu_percent']):
        if 'python' in proc.info['name']:
            agents.append({
                'pid': proc.info['pid'],
                'name': proc.info['name'],
                'memory_mb': round(proc.info['memory_info'].rss / (1024 * 1024), 2),
                'cpu_percent': proc.info['cpu_percent']
            })

    return render_template_string(
        HTML_TEMPLATE,
        time=datetime.datetime.now().strftime("%H:%M:%S"),
        cpu=cpu,
        ram_free=round(ram.available / (1024**3), 2),
        ram_total=round(ram.total / (1024**3), 2),
        agents=agents
    )

if __name__ == '__main__':
    # Listen on all interfaces so you can access it from other devices
    app.run(host='0.0.0.0', port=5000)

2. Integration with your Watchdog

Update your agent_watchdog.sh (or your systemd service) to launch this dashboard alongside your agents. Add this line before the loop:

Bash
# Launch dashboard in its own tmux window or background
tmux new-window -t agent_room:1 "python3 dashboard.py"

3. Accessing the Dashboard

  1. Find your Kali IP: ip a | grep inet (e.g., 192.168.1.50).

  2. Open a browser on your phone/laptop.

  3. Go to http://192.168.1.50:5000.


How this Completes your Headless Setup

By combining everything we've built, you now have:

  • The RAM Savings: GNOME is dead, giving you ~1GB+ extra RAM.

  • The Persistence: tmux and systemd keep your agents running through crashes.

  • The Visibility: You can see exactly what’s happening via the web dashboard without ever touching the Kali machine.

Would you like me to show you how to add a "Kill Switch" button to that web dashboard so you can remotely restart your agents if you see them hanging?

You said

yes

Gemini said

Adding a Kill Switch or "Restart" button turns your passive dashboard into a remote control center. Since we are running the agents inside a systemd service, we can use Python's subprocess module to tell the system to restart the service itself.

1. Updated Dashboard with Control Buttons (dashboard.py)

Replace your previous dashboard.py with this version. It adds two routes: /restart and /stop.

Python
from flask import Flask, render_template_string, redirect, url_for
import psutil
import datetime
import subprocess

app = Flask(__name__)

HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>Agent Control Center</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body { font-family: 'Segoe UI', sans-serif; background: #0d1117; color: #c9d1d9; padding: 20px; }
        .card { border: 1px solid #30363d; padding: 20px; margin-bottom: 15px; border-radius: 8px; background: #161b22; }
        .btn { padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-weight: bold; text-decoration: none; display: inline-block; }
        .btn-restart { background: #238636; color: white; }
        .btn-stop { background: #da3633; color: white; margin-left: 10px; }
        .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
        h1 { color: #58a6ff; }
        .status-up { color: #3fb950; font-weight: bold; }
    </style>
</head>
<body>
    <h1>🛰️ Agent Command Center</h1>
    
    <div class="card">
        <h3>System Status <span class="status-up">[ONLINE]</span></h3>
        <div class="stat-grid">
            <p><strong>CPU:</strong> {{ cpu }}%</p>
            <p><strong>RAM:</strong> {{ ram_used }}GB / {{ ram_total }}GB</p>
        </div>
        <hr style="border: 0.5px solid #30363d;">
        <p><strong>Actions:</strong></p>
        <a href="/restart" class="btn btn-restart" onclick="return confirm('Restart all agents?')">🔄 Restart Agents</a>
        <a href="/stop" class="btn btn-stop" onclick="return confirm('Kill all agents and GUI?')">🛑 Emergency Stop</a>
    </div>

    <h3>Active Processes</h3>
    {% for proc in agents %}
    <div class="card" style="padding: 10px;">
        <strong>PID {{ proc.pid }}:</strong> {{ proc.name }} | <strong>MEM:</strong> {{ proc.memory_mb }}MB
    </div>
    {% endfor %}
</body>
</html>
"""

@app.route('/')
def index():
    ram = psutil.virtual_memory()
    agents = []
    for proc in psutil.process_iter(['pid', 'name', 'memory_info']):
        if 'python' in proc.info['name'] and 'dashboard' not in proc.info['name']:
            agents.append({
                'pid': proc.info['pid'],
                'name': proc.info['name'],
                'memory_mb': round(proc.info['memory_info'].rss / (1024 * 1024), 2)
            })

    return render_template_string(
        HTML_TEMPLATE,
        cpu=psutil.cpu_percent(),
        ram_used=round((ram.total - ram.available) / (1024**3), 2),
        ram_total=round(ram.total / (1024**3), 2),
        agents=agents
    )

@app.route('/restart')
def restart():
    # This restarts the systemd service we created earlier
    subprocess.Popen(["sudo", "systemctl", "restart", "agent-server.service"])
    return "Restarting... Please wait 10 seconds and refresh the home page."

@app.route('/stop')
def stop():
    # This stops the agents entirely
    subprocess.Popen(["sudo", "systemctl", "stop", "agent-server.service"])
    return "Agents stopped. Manual intervention required to start again."

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

2. Permissions Fix (Crucial)

Since the Flask app (running as user kali) needs to run systemctl (which requires sudo), you need to give the user permission to run those specific commands without a password prompt, or the button will fail.

  1. Run sudo visudo.

  2. Add this line at the very bottom:

    Bash
  1. kali ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart agent-server.service, /usr/bin/systemctl stop agent-server.service
    

3. How the "Remote Kill" Works

When you press Restart on your phone:

  1. Flask sends a signal to the Linux kernel.

  2. systemd receives the instruction to stop the agent-server.service.

  3. The Watchdog and the Agents are terminated gracefully.

  4. systemd immediately spawns a fresh instance of your watchdog script.

  5. Your agents start with a clean RAM profile and zeroed-out caches.


Final Architecture Checklist

  • Operating Mode: Headless (Multi-user target).

  • Process Manager: systemd (handles boot-start and auto-restart).

  • Execution Space: tmux (allows you to "peek" into the terminal via SSH).

  • Monitoring: Flask Dashboard (accessible via phone/browser).

  • Control: Remote Restart/Stop buttons on the dashboard.

Would you like me to help you set up a "Mobile Notification" using a tool like Telegram, so the agents can text you whenever they finish a task or if the RAM gets too low?

You said

yes

Gemini said

This is the ultimate "peace of mind" feature. By integrating a Telegram Bot, your agents can proactively text you when they hit a milestone, if the system is running out of RAM, or if the Watchdog has to trigger a restart.

1. Create Your Bot

  1. Open Telegram and search for @BotFather.

  2. Type /newbot and follow the steps to get your API Token.

  3. Search for @userinfobot to get your Chat ID.

2. The Python Notifier (notifier.py)

Create a small utility script that your agents (or the watchdog) can call.

Python
import requests

TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"

def send_telegram_msg(message):
    url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
    payload = {"chat_id": CHAT_ID, "text": message, "parse_mode": "Markdown"}
    try:
        requests.post(url, data=payload, timeout=5)
    except Exception as e:
        print(f"Failed to send notification: {e}")

# Example usage for your agents:
# send_telegram_msg("🚀 *Agent Alpha* has completed the data synthesis task.")

3. Integrating "Low RAM" Alerts

Add this logic to your Dashboard or Watchdog script so you get a warning before the Linux OOM Killer strikes.

Python
import psutil

def check_resources():
    ram = psutil.virtual_memory()
    if ram.percent > 90:
        send_telegram_msg(f"⚠️ *CRITICAL RAM ALERT*: Usage is at {ram.percent}%. Headless Kali may crash soon!")

The Complete Headless Ecosystem

With this final piece, your multi-agent system is now a fully autonomous server:

  • Hardware: Kali Linux is stripped of its GUI to maximize RAM for the agents.

  • Process: systemd ensures the agents boot with the hardware and restart on failure.

  • Control: You have a web dashboard with "Restart" and "Stop" buttons.

  • Alerts: You receive real-time Telegram updates on your phone.


Final Maintenance Commands

Since you are now running a "Black Box" server, keep these commands in your notes:

TaskCommand
Check Live Logssudo journalctl -u agent-server.service -f
Peek at Terminaltmux attach -t agent_room
Check RAM (CLI)free -h or htop
Return to Desktopsudo systemctl set-default graphical.target && sudo reboot

Would you like me to help you package all these scripts into a single GitHub-style repository structure so you can easily deploy it on other Kali or Debian machines?

You said

yes

Gemini said

Structuring this as a professional repository will make it much easier to maintain and deploy. By keeping your logic, monitoring, and configurations separate, you ensure that a bug in the dashboard doesn't crash your actual agents.

Repository Structure: kali-agent-server/

Plaintext
kali-agent-server/
├── agents/                 # Place your Python agent scripts here
│   └── main_agents.py      # Your primary entry point
├── core/
│   ├── watchdog.sh         # The persistence loop
│   └── notifier.py         # Telegram alert logic
├── dashboard/
│   ├── app.py              # Flask control center
│   └── templates/          # (Optional) if you move HTML to files
├── config/
│   └── agent-server.service # Systemd unit file
├── requirements.txt        # Python dependencies
└── setup.sh                # Automation script to install everything

The "One-Click" Setup Script (setup.sh)

This script automates the installation of dependencies and the systemd service.

Bash
#!/bin/bash

echo "[*] Installing System Dependencies..."
sudo apt update && sudo apt install -y python3-pip tmux bc curl

echo "[*] Installing Python Libraries..."
pip3 install flask psutil requests --break-system-packages

echo "[*] Configuring Systemd Service..."
# Dynamically update the path in the service file
sed -i "s|/home/kali/your_project_folder|$(pwd)|g" config/agent-server.service

sudo cp config/agent-server.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable agent-server.service

echo "[!] SETUP COMPLETE."
echo "1. Update core/notifier.py with your Telegram credentials."
echo "2. Run 'sudo systemctl start agent-server.service' to begin."

Deployment Best Practices

1. The .gitignore

Since you have a Telegram Token and Chat ID in notifier.py, never push that file to a public GitHub repo. Create a .gitignore file:

Plaintext
__pycache__/
*.log
*.csv
config/secrets.env

2. Using an Environment File

Instead of hardcoding your Telegram Token, modify notifier.py to read from a file or environment variable. This keeps your credentials secure.

3. Scaling Up

If you find your multi-agent system needs more power than your Kali machine can provide, this structure allows you to move the entire kali-agent-server folder to a VPS (like AWS or DigitalOcean) and run the exact same setup.sh. The "Headless" optimization is even more effective on cloud servers.


Your New Workflow

  1. Develop: Write your agent logic in agents/main_agents.py.

  2. Deploy: Run ./setup.sh.

  3. Monitor: Check your phone for Telegram alerts or your browser for the Flask dashboard.

  4. Iterate: If you update the code, just click Restart on your web dashboard to pull the new changes into the running session.

Would you like me to generate a README.md file for this repository that explains how to use each component?

You said

yes

Gemini said

A well-written README.md is the "instruction manual" for your server. It ensures that if you step away from this project for a month and come back, you’ll know exactly how to manage it.

README.md

Markdown
# 🛰️ Kali Headless Agent Server

An optimized, self-healing environment for running resource-heavy multi-agent Python systems (CrewAI, AutoGen, LangChain) on Kali Linux.

## 🚀 Key Features
* **RAM Optimization:** Automatically kills the GNOME GUI to free ~1GB+ of RAM.
* **Self-Healing:** Systemd watchdog restarts agents if they crash or hang.
* **Web Dashboard:** Remote monitoring and "Kill Switch" via Flask.
* **Telegram Alerts:** Real-time notifications for task completion or low memory.
* **Persistent Sessions:** Runs inside `tmux` for easy terminal attachment via SSH.

---

## 🛠️ Installation

1. **Clone the repo:**
   ```bash
   git clone [https://github.com/your-username/kali-agent-server.git](https://github.com/your-username/kali-agent-server.git)
   cd kali-agent-server
  1. Configure Secrets: Edit core/notifier.py with your Telegram BOT_TOKEN and CHAT_ID.

  2. Run Setup:

    Bash
  1. sudo systemctl set-default multi-user.target
    

🎮 Management Commands

ActionCommand
Start Servicessudo systemctl start agent-server
Stop Servicessudo systemctl stop agent-server
View Live Terminaltmux attach -t agent_room
Check Web UINavigate to http://<KALI_IP>:5000
Return to GUIsudo systemctl isolate graphical.target

📂 Architecture

  • agents/: Your custom Python logic.

  • core/watchdog.sh: Monitors the tmux session.

  • dashboard/app.py: The Flask-based remote control.

  • config/: Systemd unit files.


---

### Final Implementation Tips

#### 1. The "Ghost" Login
Since you are running headless, you won't see a login screen. When you boot up, wait about 30–60 seconds for the network to initialize. Your Telegram bot should then send a message saying: **"🚀 System Online: Agent Server Started."** (You can add this line to your `watchdog.sh`).

#### 2. Local Model Support
If your agents use local models via **Ollama**, remember that Ollama runs as its own service. You can add it to the `After=` line in your `agent-server.service` to ensure the AI models are loaded before your agents try to talk to them.



#### 3. Security
Since your Flask dashboard has a "Restart" button, ensure you only run this on a trusted local network. If you need to access it over the internet, consider putting it behind a basic password or using a VPN (like Tailscale) to reach your Kali machine.

**Is there anything else you'd like to tweak—perhaps adding a specific data-saving routine or integrating a database like SQLite for the agents to store their memory?**
You said

yes

Gemini said

Integrating SQLite is the most effective way to give your agents "long-term memory" while remaining resource-efficient. Unlike JSON files, SQLite handles concurrent writes (critical for multi-agent systems) and won't corrupt your data if the system restarts.

1. Database Schema (core/memory.py)

Create a central memory manager that your agents can import. This handles short-term context and long-term facts.

Python
import sqlite3
import json
from datetime import datetime

class AgentMemory:
    def __init__(self, db_path="memory.db"):
        self.conn = sqlite3.connect(db_path, check_same_thread=False)
        self.create_tables()

    def create_tables(self):
        with self.conn:
            # Stores every interaction for audit/history
            self.conn.execute("""
                CREATE TABLE IF NOT EXISTS interactions (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    agent_name TEXT,
                    prompt TEXT,
                    response TEXT,
                    timestamp DATETIME
                )
            """)
            # Stores learned facts/state (Long-term memory)
            self.conn.execute("""
                CREATE TABLE IF NOT EXISTS long_term_facts (
                    key TEXT PRIMARY KEY,
                    value TEXT,
                    updated_at DATETIME
                )
            """)

    def save_interaction(self, agent_name, prompt, response):
        with self.conn:
            self.conn.execute(
                "INSERT INTO interactions (agent_name, prompt, response, timestamp) VALUES (?, ?, ?, ?)",
                (agent_name, prompt, response, datetime.now())
            )

    def update_fact(self, key, value):
        with self.conn:
            self.conn.execute(
                "INSERT OR REPLACE INTO long_term_facts (key, value, updated_at) VALUES (?, ?, ?)",
                (key, json.dumps(value), datetime.now())
            )

    def get_fact(self, key):
        cursor = self.conn.execute("SELECT value FROM long_term_facts WHERE key = ?", (key,))
        row = cursor.fetchone()
        return json.loads(row[0]) if row else None

2. Integration with Dashboard

You can now update your Flask Dashboard to display what your agents are "thinking" by querying the interactions table.


3. Why SQLite Wins in Headless Mode

  • Zero Overhead: No separate server (like PostgreSQL or MySQL) is needed, saving you ~200MB+ RAM.

  • ACID Compliance: If your Kali machine loses power or the watchdog kills the process mid-write, your database won't break.

  • Auditability: You can use the sqlite3 CLI tool via SSH to inspect exactly what the agents have learned:

    Bash
  • sqlite3 memory.db "SELECT * FROM long_term_facts;"
    

Best Practices for Memory Management

To keep your headless server fast even after months of running:

  1. Summarization: Don't store massive raw logs. Have a "Manager Agent" summarize past interactions every 100 entries and move them to the long_term_facts table.

  2. Indexing: As your database grows, ensure you add indexes to the timestamp or key columns to keep lookups instant.

  3. Vacuuming: Occasionally run VACUUM; in SQLite to reclaim space from deleted rows.


Final "Holy Grail" Setup

You now have a system that:

  • Boots Headless (Max RAM).

  • Self-Heals (Watchdog).

  • Communicates (Telegram).

  • Persists (SQLite Memory).

  • Remotely Controlled (Flask UI).

Would you like me to create a "Database Explorer" page for your web dashboard so you can view and edit the agents' memories directly from your phone's browser?

You said

Yes

Gemini said

A Database Explorer turns your headless server into a transparent "brain." By adding this to your Flask dashboard, you can monitor exactly what facts your agents are storing, clear out bad memories, or even manually inject instructions into their long-term storage from your phone.

1. The Enhanced Dashboard (dashboard/app.py)

Add these routes to your existing Flask application. This uses a simple HTML table to display the SQLite data and includes an "Edit" function.

Python
from flask import Flask, render_template_string, request, redirect, url_for
import sqlite3

# ... (keep your existing imports and system stat routes) ...

def get_db_connection():
    conn = sqlite3.connect('memory.db')
    conn.row_factory = sqlite3.Row
    return conn

@app.route('/memory')
def memory_explorer():
    conn = get_db_connection()
    # Fetch latest 20 interactions and all long-term facts
    logs = conn.execute('SELECT * FROM interactions ORDER BY id DESC LIMIT 20').fetchall()
    facts = conn.execute('SELECT * FROM long_term_facts').fetchall()
    conn.close()
    
    return render_template_string(DB_HTML_TEMPLATE, logs=logs, facts=facts)

@app.route('/delete_fact/<key>')
def delete_fact(key):
    conn = get_db_connection()
    conn.execute('DELETE FROM long_term_facts WHERE key = ?', (key,))
    conn.commit()
    conn.close()
    return redirect(url_for('memory_explorer'))

2. The Explorer UI (DB_HTML_TEMPLATE)

Add this styling and HTML to your script. It’s designed to be mobile-friendly for checking your agents on the go.

Python
DB_HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>Agent Memory Explorer</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body { font-family: sans-serif; background: #0d1117; color: #c9d1d9; padding: 15px; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; background: #161b22; }
        th, td { padding: 12px; border: 1px solid #30363d; text-align: left; font-size: 0.9em; }
        th { background: #21262d; color: #58a6ff; }
        .btn-del { color: #f85149; text-decoration: none; font-weight: bold; }
        .nav { margin-bottom: 20px; }
    </style>
</head>
<body>
    <div class="nav"><a href="/" style="color: #58a6ff;"><- Back to Stats</a></div>
    
    <h2>🧠 Long-Term Facts</h2>
    <table>
        <tr><th>Key</th><th>Value</th><th>Updated</th><th>Action</th></tr>
        {% for fact in facts %}
        <tr>
            <td>{{ fact['key'] }}</td>
            <td>{{ fact['value'] }}</td>
            <td>{{ fact['updated_at'] }}</td>
            <td><a href="/delete_fact/{{ fact['key'] }}" class="btn-del">Delete</a></td>
        </tr>
        {% endfor %}
    </table>

    <h2>📜 Recent Interactions</h2>
    <table>
        <tr><th>Agent</th><th>Prompt</th><th>Response</th></tr>
        {% for log in logs %}
        <tr>
            <td>{{ log['agent_name'] }}</td>
            <td>{{ log['prompt'][:50] }}...</td>
            <td>{{ log['response'][:50] }}...</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>
"""

3. Why this matters for Headless Kali

When running multi-agent systems, agents can sometimes "hallucinate" or get stuck in a loop. In a GUI, you'd see this in the terminal. In a headless setup:

  • The Interaction Log shows you what they are currently saying.

  • The Long-Term Facts show you what they have "decided" is true.

  • The Delete Button allows you to "reset" a specific belief an agent has without restarting the whole system.


Final Maintenance Tip: Database Backup

Since your agents' "intelligence" is now stored in memory.db, you should back it up regularly. You can add a simple line to your setup.sh or a cron job:

Bash
# Weekly backup of agent memory
0 0 * * 0 cp /home/kali/project/memory.db /home/kali/backups/memory_$(date +\%F).db

You now have a complete, professional-grade AI Agent Server. Would you like me to help you create a final "Master Launch" script that initializes the database, starts the dashboard, and kicks off the agents all at once?

You said

yes

Gemini said

This final "Master Launch" script ties every component together—database, dashboard, and agents—into a single, coordinated execution. It ensures that the database is healthy and the web UI is up before the agents start their work.

The Master Launch Script (master_launch.sh)

Create this file in your root project directory:

Bash
#!/bin/bash

# --- Configuration ---
SESSION_NAME="agent_server"
DB_FILE="memory.db"
DASHBOARD_APP="dashboard/app.py"
AGENT_SCRIPT="agents/main_agents.py"
VENV_PATH="./venv/bin/activate"

echo "--- 🚀 Initializing Master Agent Server ---"

# 1. Check for/Initialize SQLite Database
if [ ! -f "$DB_FILE" ]; then
    echo "[*] Database not found. Initializing $DB_FILE..."
    # Quick one-liner to create tables if they don't exist
    python3 -c "import sqlite3; conn=sqlite3.connect('$DB_FILE'); \
    conn.execute('CREATE TABLE IF NOT EXISTS interactions (id INTEGER PRIMARY KEY, agent_name TEXT, prompt TEXT, response TEXT, timestamp DATETIME)'); \
    conn.execute('CREATE TABLE IF NOT EXISTS long_term_facts (key TEXT PRIMARY KEY, value TEXT, updated_at DATETIME)'); \
    conn.close()"
fi

# 2. Kill existing sessions to prevent port conflicts
tmux kill-session -t $SESSION_NAME 2>/dev/null

# 3. Start TMUX Session (Detached)
echo "[*] Creating tmux session: $SESSION_NAME"
tmux new-session -d -s $SESSION_NAME -n "Dashboard"

# 4. Window 0: Launch Flask Dashboard
echo "[*] Window 0: Launching Web Dashboard on port 5000..."
tmux send-keys -t $SESSION_NAME:0 "source $VENV_PATH && python3 $DASHBOARD_APP" C-m

# 5. Window 1: Launch Python Agents
echo "[*] Window 1: Launching AI Agents..."
tmux new-window -t $SESSION_NAME:1 -n "Agents"
tmux send-keys -t $SESSION_NAME:1 "source $VENV_PATH && python3 $AGENT_SCRIPT" C-m

# 6. Notify via Telegram
python3 -c "import core.notifier as n; n.send_telegram_msg('🛰️ *Master Launch Successful*\nDashboard: http://localhost:5000\nAgents: Running in tmux window 1')"

echo "--- ✅ System is LIVE ---"
echo "Use 'tmux attach -t $SESSION_NAME' to view logs."

System Architecture Flow

The diagram below illustrates how your headless Kali machine manages these layers simultaneously without a GUI.

  1. Hardware Level: Kali boots into CLI mode (Multi-user target).

  2. Orchestration Level: systemd triggers the master_launch.sh.

  3. Process Level: tmux partitions the resources:

    • Pane 0: Flask Web Server (Interface).

    • Pane 1: Python Agents (Logic).

  4. Data Level: Both panes read/write to the shared memory.db (SQLite).

  5. External Level: Telegram API sends status updates to your phone.


Final Project Checklist

Before you walk away and let your agents run for days, double-check these settings:

  • Executable Permissions: chmod +x master_launch.sh core/watchdog.sh setup.sh

  • Sudoers Whitelist: Ensure systemctl restart is whitelisted so the "Restart" button on your web dashboard actually works.

  • Python Pathing: If you are using a virtual environment, make sure the VENV_PATH in the script matches your actual folder.

  • Network Persistence: If using Wi-Fi, ensure nmcli is set to autoconnect so the Telegram bot can reach the internet immediately upon boot.

You are now fully equipped with a professional-grade, headless AI agent workstation. Would you like me to show you how to set up a "Remote Terminal" over the web using gotty so you can actually type commands into the tmux session from your phone's browser?

You said

yes

Gemini said

To truly run this project as a "Black Box" server, you need a way to interact with the terminal without an SSH client. GoTTY is a tool that turns your CLI into a web application, allowing you to access your tmux session directly from a browser.

1. Install GoTTY

Since GoTTY isn't in the default Kali repos, we’ll download the binary directly:

Bash
# Download the latest Linux 64-bit binary
curl -L https://github.com/sorenisanerd/gotty/releases/latest/download/gotty_linux_amd64.tar.gz | tar xz
sudo mv gotty /usr/local/bin/
sudo chmod +x /usr/local/bin/gotty

2. Secure the Connection

Warning: Opening a terminal to the web is extremely dangerous without security. We will enable Basic Authentication (Username/Password) and SSL (encryption).

Generate a self-signed SSL certificate so your password isn't sent in plain text:

Bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ~/.gotty.key -out ~/.gotty.crt

3. Update the Master Launch Script

Add GoTTY to your master_launch.sh so it starts alongside your agents. This command attaches GoTTY to your existing tmux session.

Add this line to the end of your script:

Bash
# Launch GoTTY to share the tmux session over port 8080
# Replace 'admin:yourpassword' with your desired credentials
nohup gotty -w -p 8080 -c "admin:p@ssword123" --tls --tls-crt ~/.gotty.crt --tls-key ~/.gotty.key tmux attach -t $SESSION_NAME > gotty.log 2>&1 &

4. The Complete Remote Architecture

You now have a multi-layered remote management system:

  • Port 5000: Your Flask Dashboard (Read-only stats + Restart buttons).

  • Port 8080: Your GoTTY Terminal (Full interactive CLI control).

  • Telegram: Your Emergency Pager (Real-time alerts).


How to use your "Remote Kali"

  1. On your phone/laptop browser: Navigate to https://<KALI_IP>:8080.

  2. Login: Enter the credentials you set in the script.

  3. Interact: You will see your tmux windows. Use Ctrl+B then n to switch between your Dashboard Logs and your Agent Output. You can type commands exactly as if you were sitting at the machine.

Final Security Tip

If you plan to access this from outside your home Wi-Fi:

  • Do not just port-forward 8080 on your router.

  • Instead, use a VPN (like WireGuard or Tailscale). This keeps your Kali "invisible" to the public internet while allowing you to securely log in from anywhere in the world.

Would you like me to generate a final "Emergency Recovery" cheat sheet that lists every URL, port, and command you've set up so far?

You said

yes

Gemini said

This Emergency Recovery Cheat Sheet is designed to be your "mission control" document. Copy and save this in a notes app or print it out. If you ever lose access to your Kali machine, this will help you recover everything in seconds.


🛠️ Access & Control Panel

ServiceAddressCredentialsPurpose
Health Dashboardhttp://<KALI_IP>:5000None (Local only)View RAM/CPU/Database facts.
Remote Terminalhttps://<KALI_IP>:8080admin : p@ssword123Interactive CLI in your browser.
SSH Accessssh kali@<KALI_IP>Your user passwordDirect command line access.
Telegram BotOpen Telegram AppN/AReceive "Low RAM" or "Task Done" alerts.

🚦 Common Management Commands

If you are logged in via SSH or GoTTY, use these to manage the agents:

1. Service Management

  • Restart Agents: sudo systemctl restart agent-server.service

  • Stop Everything: sudo systemctl stop agent-server.service

  • Check If Running: sudo systemctl status agent-server.service

  • See Crash Logs: sudo journalctl -u agent-server.service -f -n 50

2. TMUX (Terminal Controls)

Since everything runs in tmux, use these shortcuts once attached (tmux attach -t agent_server):

  • Switch Windows: Ctrl+B, then 0 (Dashboard) or 1 (Agents).

  • Detach (Don't Kill): Ctrl+B, then D.

  • Scroll Up in Logs: Ctrl+B, then [ (Use arrow keys to scroll, press Q to exit).

3. Database & Files

  • Manual DB Check: sqlite3 memory.db "SELECT * FROM long_term_facts;"

  • Clear All Logs: rm *.log && rm *.csv

  • Check Real RAM Usage: free -h or htop


🚨 Troubleshooting "What If..."

"I can't reach the Web Dashboard!"

  • Check if the service is running: sudo systemctl status agent-server.

  • Check if the port is blocked: sudo ufw status. (If enabled, run sudo ufw allow 5000).

"The agents aren't restarting after a crash!"

  • The Watchdog script might have hit the MAX_RESTARTS limit.

  • Run tmux kill-session -t agent_server and then ./master_launch.sh to reset the count.

"I need my Desktop GUI back!"

  • Run: sudo systemctl set-default graphical.target && sudo reboot

  • Or for a temporary session: sudo systemctl isolate graphical.target


Final Project Layout Diagram

This setup transforms your Kali Linux machine from a standard laptop into a hardened AI Agent Server. You’ve successfully optimized for memory, built a persistence layer, and created a remote-first management interface.

Your AI Agent Server is now complete! Would you like me to help you brainstorm your first multi-agent "mission" to run on this new system?

 You said

yes

Gemini said

Building your first "mission" on this headless server is where the real fun begins. Since you're running on Kali Linux, you have access to a suite of powerful security tools that AI agents can orchestrate far better than a human can manually.

Here are three mission ideas tailored for a resource-optimized, multi-agent environment in 2026.


Mission 1: The Autonomous OSINT Investigator

Goal: Input a domain or username, and have a "Crew" of agents map out the entire public footprint without you lifting a finger.

  • Agent A (The Scraper): Uses tools like theHarvester or whois to gather raw data.

  • Agent B (The Analyst): Feeds found emails into data breach databases (via APIs like HaveIBeenPwned) to check for leaks.

  • Agent C (The Reporter): Summarizes findings into a professional PDF and sends the "Red Alert" to your Telegram if it finds a high-risk credential leak.

  • Why Headless? OSINT involves long-running scraping tasks. Running this in a tmux session ensures that if your laptop disconnects, the investigation continues 24/7.


Mission 2: The "Smart" Home Lab Guardian

Goal: Monitor your local network logs for suspicious behavior and take defensive action.

  • Agent A (Log Watcher): Monitors /var/log/auth.log or your router's syslog for failed SSH attempts.

  • Agent B (Threat Intel): Takes the "Attacker IP" and checks it against global blacklists (AbuseIPDB).

  • Agent C (The Guard): If the IP is malicious, it uses your Kill Switch logic to update iptables rules and block the IP permanently.

  • Why Headless? This needs to be a "set and forget" system. Using systemd ensures your guardian is the first thing that starts when the server boots.


Mission 3: The Deep Research Assistant

Goal: Give it a complex technical topic (e.g., "The latest zero-day exploits for 2026 IoT devices"), and let it write a whitepaper while you sleep.

  • Agent A (Searcher): Uses a tool like Serper or DuckDuckGo to find recent security whitepapers.

  • Agent B (Summarizer): Reads the long PDFs and extracts key technical details.

  • Agent C (The Writer): Compiles the notes into a structured Markdown document in your memory.db.

  • Why Headless? Local LLMs used for summarization (like Llama 3 or DeepSeek) are RAM-hungry. By killing the GNOME GUI, you give these agents an extra 1GB+ of VRAM/RAM, allowing them to process much larger documents.


🛠️ How to Start a Mission

To launch one of these, you simply update your agents/main_agents.py with your logic and run:

Bash
./master_launch.sh

Which framework should you use?

FrameworkBest For...
CrewAIRole-based "Team" missions (Researcher, Writer, Manager).
AutoGenComplex "conversational" logic where agents need to debate.
LangGraphHigh-precision workflows with specific "if/then" loops.

Would you like me to generate the actual Python code for one of these missions (like the OSINT Investigator) so you can drop it into your agents/ folder right now?

(to be Continued in the next blog post...) 

  • chmod +x setup.sh
    ./setup.sh
    
  • (Optional) Set Boot to Headless: To ensure Kali boots into CLI mode automatically:

    Bash
     
    #LangGraph #AutoGen #CrewAI #AIAgents #MultiAgentAI 
     #AIAgentServer #TMUX #sqlite3 #HeadlessServer #Flask 
    #GoTTY #SSL #TelegramAPI #FlaskUI #psutil #No-GUI 
    #systemctl #GPUOverhead
  • No comments:

    Post a Comment