Local-first • Red/Blue Team • MCP-Powered • Docker-Integrated
Execute. Analyze. Harden.
RamiBot connects AI reasoning with real cybersecurity tools through a structured operations pipeline.
-
🧠 Multi-provider LLM support
OpenAI, Anthropic, OpenRouter, LM Studio, and Ollama -
🧠 Skill Pipeline
Structured methodology: Recon → Exploit → Defense → Reporting -
🔐 Evidence-Locked Reporting
Prevents hallucinated CVEs, versions, or findings
-
🧰 Real security tool execution via MCP
Integrates pentesting tools inside controlled environments -
🕵️ Rami-Kali MCP server
45+ pentesting tools available to the LLM
-
🐳 Docker-integrated terminal
Run commands directly inside containerized environments -
🛑 Tool Approval Gate
Human approval before executing security tools -
📄 One-click PDF report export
Generate structured security reports instantly
A local-first AI chat interface for security operations. Supports multiple LLM providers, real-time streaming, MCP tool integration, a dynamic security skill system, Docker terminal access, Tor transparent proxy management, a persistent findings database, one-click PDF report export, a human-in-the-loop Tool Approval Gate that pauses execution before every MCP tool call, a global Evidence-Locked Reporting system that prevents the model from fabricating versions, CVEs, severity ratings, or security properties not explicitly present in tool output, a dedicated Burp Suite web assessment skill, a response language selector, Hermes tool chaining that detects and executes <tool_call> XML emitted by Llama/Hermes fine-tuned models, zsh shell with syntax highlighting and autosuggestions in the Docker terminal, proxychains4 proxy routing with ready-made Burp and Tor profiles, Service-Bound CVE Correlation that locks every CVE to its exact detected service via CPE data, and a CVE Query Lock rule that prevents semantic drift when generating NVD lookup queries after service discovery.
RamiBot is a self-hosted chat application built for security engineers who need a controllable, extensible interface between LLMs and operational tooling.
It does not depend on any cloud chat product. Conversations are stored locally in SQLite. Provider API keys are configured at runtime. All tool execution happens inside Docker containers.
The core differentiator is the skill pipeline: a prompt engineering system that detects the operational context from user input (reconnaissance, exploitation, defense, analysis, reporting), selects the appropriate skill, and injects structured methodology instructions into the system prompt before each LLM call. Team mode (red or blue) controls which skills are available and how the LLM frames its responses.
Who it is for:
- Security engineers running structured red team or blue team workflows
- Analysts who need LLM-assisted reasoning alongside real tool execution via MCP
- Researchers integrating local models (Ollama, LM Studio) into security workflows
- Teams that need full local data control with no cloud dependency for conversation history
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React 19) │
│ Sidebar │ ChatPanel │ SettingsModal │ DockerTerminal │
│ Zustand State Store │
│ SSE consumer / fetch client (port 5173) │
└───────────────────────────┬─────────────────────────────────────┘
│ HTTP / SSE
┌───────────────────────────▼─────────────────────────────────────┐
│ BACKEND (FastAPI) │
│ │
│ /api/chat/stream ──► SkillPipeline ──► LLM Adapter │
│ │ │ │
│ PromptComposer httpx (SSE) │
│ │ │ │
│ System Prompt Provider API │
│ │
│ Tool call detected ──► MCPClient ──► rami-kali MCP server │
│ (auto-configured) (docker exec stdio) │
│ ──► MCP Server (stdio/HTTP) │
│ Tool result ──────────────────────► LLM follow-up │
│ │
│ /api/terminal/* ──► TerminalSession ──► docker exec │
│ /api/docker/tor ──► tor_start/stop ──► iptables (container) │
│ │
│ aiosqlite ──► ramibot.db │
│ settings.json ──► provider credentials + docker config │
└─────────────────────────────────────────────────────────────────┘
Data flow for a streaming chat request:
- Frontend sends
POST /api/chat/streamwith conversation ID, provider, model, team mode, MCP flag, and optionalrequire_tool_approval - Backend loads conversation history from SQLite
- If MCP is enabled: skill pipeline classifies the input, selects a skill, builds a system prompt, and injects it as the first message in history
- Adapter streams the LLM response as Server-Sent Events (token events)
- If the LLM emits a tool call and Approval Mode is on: backend yields a
tool_approval_requiredSSE event and waits (up to 120 s) for the operator's decision viaPOST /api/chat/approve; auto-denies on timeout - If approved (or Approval Mode is off): the MCP client executes the tool, the result is appended to history, and a follow-up generation is triggered
- Backend saves the final message to SQLite with token usage and latency
- Frontend renders tokens incrementally and tool traces in real time
The skill system is invoked on every MCP-enabled chat request. It classifies input, selects a skill, and builds a structured system prompt tailored to the operation phase and team mode.
| Component | File | Responsibility |
|---|---|---|
SkillPipeline |
skills/pipeline.py |
Orchestrates the full build-prompt flow |
InputClassifier |
skills/classifier.py |
Regex and substring trigger matching |
PromptComposer |
skills/composer.py |
Assembles system prompt from selected skill |
SkillRegistry |
skills/registry.py |
Loads skill definitions from JSON |
| Skill | Teams | Priority | Risk | Trigger examples |
|---|---|---|---|---|
recon |
red, blue | 10 | low | scan, nmap, enumerate, port, subdomain, dns |
exploit |
red only | 20 | high | exploit, payload, shell, rce, xss, sqli, privesc, metasploit |
defense |
blue only | 20 | low | harden, firewall, patch, mitigate, incident, siem, ids |
analysis |
red, blue | 30 | low | analyze, log, traffic, pcap, forensic, anomaly, wireshark |
reporting |
red, blue | 50 | low | report, document, executive, findings, export |
burp_expert |
red, blue | 15 | high | burp, web app, proxy history, repeater, intruder, fuzz, owasp |
- Trigger classification: Word-boundary regex matches user input against skill trigger lists
- Phase inference: If no triggers match, the last 3 messages are scanned for phase markers (
[RECON],payload,patch, etc.) - Dominant skill selection: Highest-priority match wins.
reportingis suppressed ifexploitordefenseis also matched. - Fallback: No match defaults to the team default (recon for red, analysis for blue)
- Context extraction: IPv4, URL, and
host:portpatterns are extracted from input and recent history and injected asCONTEXT TARGETin the prompt - Execution intent: Imperative verbs ("run", "execute", "scan", "exploit") are detected and signaled to the composer
- Prompt assembly: Team preamble + skill methodology section +
EVIDENCE_RULES+COMMON_FOOTER - Audit log: Every decision is appended as JSON to
skill_decisions.log
Red (team_mode: "red")
- Preamble: authorized engagement, attacker perspective, tool-first
- Active skills: recon, exploit, analysis, reporting
- Priority order: exploit > recon > analysis > reporting
Blue (team_mode: "blue")
- Preamble: incident responder, remediation-driven
- Active skills: defense, analysis, reporting, recon
- Priority order: defense > analysis > reporting > recon
Team mode is selected per conversation from the sidebar toggle and persisted in localStorage.
RamiBot enforces a strict evidence discipline across all team modes and all skills to prevent LLM hallucinations in security reports and operational output.
Tool result wrapping (backend/main.py):
Every successful MCP tool result is wrapped in immutable evidence tags before being injected into the LLM's follow-up context:
[EVIDENCE BLOCK — DO NOT MODIFY]
<raw tool output>
[END OF EVIDENCE]
Global enforcement (backend/skills/composer.py):
EVIDENCE_RULES is injected into every system prompt regardless of team mode or skill. Ten mandatory rules apply to all responses:
| Rule | Enforcement |
|---|---|
| Only Evidence Block content is fact | No information from model training cited as operational finding |
| No fabricated versions / CVEs / CVSS | "Version not detected." / "Requires manual validation." / score omitted |
| No external gap-filling | If nmap shows a service with no version, no version is assumed |
| No inferred properties | Encryption status, authentication state, EOL status, exploitability, internet exposure, and credential weakness may only be stated if the Evidence Block explicitly contains them |
| Conditional risk language | Forbidden: "is vulnerable", "is exploitable", "is exposed". Required: "may be", "appears to", "consistent with" — unless the tool itself uses assertive language |
| Severity from confirmed findings only | No Critical/High/Medium/Low from port number, service name, or version string alone. Default: "Informational" if no vulnerability is explicitly reported |
| Three-layer output discipline | [RAW OUTPUT] / [PARSED DATA] / [INTERPRETATION] clearly separated |
| No Evidence Block → no fabrication | State "No tool output available" and stop |
| Service-Bound CVE Correlation | Each CVE result carries a SERVICE BINDING line (derived from CPE data). A CVE may only be attached to the detected service whose name matches that binding — never reassigned across unrelated services on the same host |
| CVE Query Lock | cve_lookup queries must be derived from the exact product name and version string in the Evidence Block. Forbidden: host IP as query input; semantic pivots to adjacent software (Apache detected → do not query Log4j); famous CVEs introduced from background knowledge without confirmed product presence |
Skill-level reinforcement:
Each skill definition carries its own EVIDENCE DISCIPLINE: note scoped to its operational context:
recon: report only scan output; no added versions or CVEsexploit: CVE candidates are hypotheses ("may be vulnerable — requires validation"), not confirmed matchesanalysis: TTP attribution uses conditional language only ("consistent with","suggests")defense: remediation only for confirmed findings; no hypothetical patchingreporting: verbatim Evidence Block excerpts in the Evidence field; severity and CVSS only from tool output
When reasoning-capable models (LM Studio / DeepSeek / QwQ) emit <think>...</think> content, it is stripped at two independent points:
- Storage layer (
store.js—stripReasoning()): applied tofullContentbefore it is committed to the messages array. Stored messages and SQLite records never contain reasoning blocks. - Export layer (
reportPdf.js): three-pass cleaning before HTML rendering — strip reasoning tags, discard content before<!-- REPORT -->marker, strip internal markers. Defense-in-depth for messages stored before the stripping was deployed.
All providers implement a common BaseAdapter interface:
async def capabilities() -> dict
async def list_models() -> list[dict]
async def generate(messages, model, **kwargs) -> dict
async def stream(messages, model, **kwargs) -> AsyncGenerator[dict, None]Streaming events emitted by all adapters:
| Event | Payload |
|---|---|
token |
{"data": "<text>"} |
tool_call |
{"data": {"id", "name", "arguments"}} |
usage |
{"data": {"prompt_tokens", "completion_tokens", "total_tokens"}} |
done |
{"data": None} |
OpenAI
- Endpoint:
https://api.openai.com/v1(configurable base URL) - Models: fetched dynamically from
/v1/models - Tool calling: yes (OpenAI format)
- Reasoning: yes (o1/o3/o4 series via
reasoning_effort) - Streaming: yes, with
stream_options: include_usage
Anthropic
- Endpoint:
https://api.anthropic.com/v1 - Models: fetched dynamically from
/v1/models(requires API key) - Tool calling: yes (tool_use blocks; input schema sanitized to remove oneOf/anyOf/allOf)
- Reasoning: yes (extended thinking via
thinking.budget_tokens) - Streaming: yes (Anthropic SSE event protocol)
OpenRouter
- Endpoint:
https://openrouter.ai/api/v1(configurable) - Models: fetched dynamically from OpenRouter API
- Tool calling: yes (OpenAI-compatible)
- Reasoning: no
LM Studio
- Endpoint: configurable (default
http://localhost:1234/v1) - Models: fetched from local LM Studio instance
- Tool calling: yes (accumulated across stream chunks)
- Reasoning: yes (filters
<think>...</think>blocks; appends/no_thinksuffix when disabled) - Timeout: 300s
Ollama
- Endpoint: configurable (default
http://localhost:11434) - Models: fetched from local Ollama instance
- Tool calling: no
- Reasoning: no
- Token counts: from
eval_count/prompt_eval_count
- Full conversation history is sent on every request (no summarization or windowing)
- System prompt from the skill pipeline is injected as the first history entry
- After a tool call: the assistant message with
tool_callsand the tool result messages are appended before the follow-up generation - Token usage and latency are stored per message in SQLite
RamiBot implements the Model Context Protocol client for connecting external tool servers.
- stdio: Spawns a local subprocess and communicates via JSON-RPC 2.0 over stdin/stdout. Uses a background reader thread (compatible with Windows selector loop limitation).
- HTTP: POST requests to a remote MCP server URL.
All tools are prefixed: {server_name}__{tool_name}. This allows multiple MCP servers to coexist without name collisions. The prefix is stripped before the server call.
MCP server configurations are stored in the SQLite mcp_servers table. On startup, all saved servers are automatically reconnected.
Tool schemas are wrapped in {"type": "function", "function": {...}} format for OpenAI-style tool calling compatibility across all adapters.
Individual tools can be disabled per session from the Settings modal. Disabled names are sent in ChatRequest.disabled_tools and filtered before injection into the LLM context.
RamiBot ships with a pre-integrated red team toolserver built on Kali Linux and delivered as a Docker container (rami-kali/).
- 45 pentest tools available as MCP tools, callable by the LLM during any MCP-enabled session
- Auto-connection: on first backend startup, RamiBot seeds the
rami-kaliMCP server entry automatically — no manual configuration required - Transport: stdio via
docker exec -i rami-kali python3 /opt/rami-kali/mcp_server.py - Scope enforcement:
config.yamlinside the container defines allowed target ranges; the server rejects out-of-scope calls - Evidence gate: tool output is only forwarded to the LLM after a scope check passes
- Audit log: every tool call is appended to an internal audit trail
| Category | Example tools |
|---|---|
| Recon | nmap, masscan, whois, theHarvester, amass, subfinder, dnsx |
| Web | nikto, gobuster, ffuf, nuclei, sqlmap, whatweb, wafw00f |
| CVE Intelligence | cve_lookup (NVD 2.0 API — exact CVE ID, keyword, CPE name, match string, severity filter, date ranges; returns CVSS, SERVICE BINDING, CPEs, references) |
| Proxy routing | proxychains4 (Burp profile + Tor profile) |
| Exploit | metasploit-framework, searchsploit, msfvenom |
| Credential | hydra, medusa, hashcat, john, crackmapexec |
| SMB / AD | enum4linux, smbclient, bloodhound, impacket suite |
| Wireless | aircrack-ng, reaver, hcxtools |
| Social eng | gophish, setoolkit |
rami-kali/knowledge/ contains 28 structured Markdown files used by the MCP server to prepend tactical context to tool results. Categories include: tool usage guides, MITRE ATT&CK mappings, result interpretation guides, and operational checklists.
The container ships with two ready-made proxychains4 profiles for routing tool traffic through Burp Suite or Tor without modifying any tool configuration:
| Mode | Command | Result |
|---|---|---|
| Analysis only | proxychains <tool> |
Routes through Burp on Windows host |
| Anonymity only | proxychains -f /etc/proxychains4-tor.conf <tool> |
Routes through Tor inside the container |
| Analysis + anonymity | Start Tor in RamiBot → configure Burp SOCKS upstream → proxychains <tool> |
tool → Burp → Tor → internet |
Burp → Tor chaining: In Burp Suite, go to Settings → Network → Connections → SOCKS proxy and set 127.0.0.1:9050. This works because the container uses network_mode: host, so 127.0.0.1 resolves to the Windows host running Tor.
Profile paths inside the container:
/etc/proxychains4.conf— routes through Burp (defaultproxychainscommand)/etc/proxychains4-tor.conf— routes directly through Tor TransPort
The gobuster_dir MCP tool accepts a proxy parameter to route directory bruteforce traffic through a specific proxy (e.g., http://127.0.0.1:8080 for Burp or socks5://127.0.0.1:9050 for Tor).
# Build the image (one-time)
make rami-kali-build
# Start the container
make rami-kali-start
# View logs
make rami-kali-logs
# Stop
make rami-kali-stopOn next backend start, [MCP] Auto-configured rami-kali server 'rami-kali' will appear in the logs and the server will be listed in Settings > MCP with its full tool set.
RamiBot includes a browser-based terminal connected to a Docker container via docker exec.
- Unix:
pty.openpty()for full PTY allocation. Supports interactive programs (vim, tmux, etc.), resize events, and full ANSI rendering. - Windows: Pipe-based communication (
docker exec -i). Usesscriptutility for PTY emulation if available; falls back to plain bash. Shell detection interminal.pyprefers zsh → bash → sh. The rami-kali container runs zsh by default withzsh-syntax-highlighting(valid commands turn green, invalid turn red) andzsh-autosuggestions(press Tab or → to accept suggestions from history).
| Step | Endpoint |
|---|---|
| Create session | POST /api/terminal/start |
| Stream output (SSE, base64) | GET /api/terminal/stream?session_id=X |
| Send input (base64) | POST /api/terminal/input |
| Resize PTY | POST /api/terminal/resize |
| Terminate session | POST /api/terminal/stop |
Up to 2 concurrent terminal panels can be open simultaneously in the UI.
When a Docker container has NET_ADMIN capability:
POST /api/docker/tor {"action": "start"}installs iptables rules to redirect TCP traffic through Tor TransPort (9040) and DNS through port 5353POST /api/docker/tor {"action": "stop"}removes the rules and stops the Tor processGET /api/docker/torreturns{ running, transparent_proxy, kill_switch }
Requires a Tor installation inside the container. Intended for use in isolated lab environments only.
- Python 3.10+
- Node.js 18+
- npm
- Docker (optional, for terminal and Tor features; required for rami-kali MCP server)
git clone <repository-url>
cd ramibotcd backend
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txtcd frontend
npm installRami-Kali is the official MCP tool server for RamiBot and provides real penetration testing tooling (nmap, metasploit, hydra, etc.).
While RamiBot can run as an AI-only interface, its full operational capability is unlocked when rami-kali is running.
Docker is required for rami-kali.
Docker installed and running.
- Windows / macOS: Docker Desktop
- Linux: Docker Engine
# Via Makefile
make rami-kali-build
# Or directly
docker build -t rami-kali rami-kali/The image is based on kalilinux/kali-rolling and installs ~60 penetration testing tools. The first build takes several minutes depending on your connection.
# Via Makefile
make rami-kali-start
# Or directly
docker compose -f rami-kali/docker-compose.yml up -ddocker ps | grep rami-kaliAllowed target ranges are managed from Settings > Scope in the UI. Changes are written to rami-kali/config.yaml and the container is restarted automatically — no rebuild required.
You can also edit the file directly before starting the container:
security:
require_scope_check: true # set to false to disable enforcement
allowed_scope:
- "192.168.1.0/24"
- "10.0.0.0/8"
- "172.16.0.0/12"The MCP server rejects any tool call whose target IP falls outside these ranges.
On the next backend startup, RamiBot detects the running container and registers it as an MCP server automatically:
[MCP] Auto-configured rami-kali server 'rami-kali'
The server appears in Settings > MCP with its full tool list. No manual configuration needed.
make rami-kali-stop # stop the container
make rami-kali-logs # follow logs
make rami-kali-build # rebuild after changes
docker exec -it rami-kali zsh # open a zsh shell insideTwo terminals:
# Terminal 1
cd backend
python -m uvicorn main:app --reload --port 8000
# Terminal 2
cd frontend
npm run devMakefile (macOS/Linux):
make install
make devOpen http://localhost:5173.
API keys and base URLs are configured through the Settings modal in the UI and saved to backend/settings.json.
| Provider | Field | Default |
|---|---|---|
| OpenAI | api_key |
— |
| Anthropic | api_key |
— |
| OpenRouter | api_key |
— |
| LM Studio | base_url |
http://localhost:1234/v1 |
| Ollama | base_url |
http://localhost:11434 |
Set the container name in Settings > Docker. The container will be started automatically if it is stopped when a terminal session is requested.
Add MCP servers from Settings > MCP. Each server requires:
- Name: identifier used for tool namespacing
- Type: stdio (command + args) or remote (HTTP URL)
Servers are persisted in SQLite and reconnected on backend restart.
Note: The
rami-kaliserver is pre-configured automatically on first startup if therami-kaliDocker container is running. No manual entry is needed. If the container is not running, the server will appear as disconnected in Settings > MCP and can be reconnected after starting the container withmake rami-kali-start.
Allowed target ranges for the rami-kali MCP server are managed from Settings > Scope.
- Add or remove CIDR ranges with immediate visual feedback
- Toggle Enforce Scope Check to enable or disable enforcement entirely
- Click SAVE & RESTART to write
rami-kali/config.yamland restart the container in one action
No Docker rebuild is required. The config file is bind-mounted, so the container picks up the new values on restart.
The underlying file (rami-kali/config.yaml) can also be edited directly — the UI reads from it on load.
All skill activation decisions are written to backend/skill_decisions.log in newline-delimited JSON. Each entry contains: timestamp, team mode, input snippet, matched triggers, activated skills, risk level, extracted target, prompt length.
GET /api/skills/log?limit=50 # retrieve
DELETE /api/skills/log # clearAlso accessible from Settings > Skill Log in the UI.
.env.example is provided as a reference template:
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
OPENROUTER_API_KEY=
LMSTUDIO_BASE_URL=http://localhost:1234/v1
OLLAMA_BASE_URL=http://localhost:11434
DATABASE_URL=sqlite:///./ramibot.db
CORS_ORIGINS=http://localhost:5173Note: runtime credentials are read from backend/settings.json (written by the UI), not from .env. The .env file is a reference template.
- Select a provider and model from the top bar
- Type a message and press Enter
- Response streams token by token in real time
- Set team mode to Red in the sidebar
- Enable MCP if tool execution is needed
- Start with a recon prompt:
scan 10.10.10.0/24 for open ports and services
The pipeline detects the recon context, injects nmap methodology instructions, and routes any nmap__* tool calls to the MCP server.
- Follow up with exploitation:
enumerate SMB shares on 10.10.10.15 and check for anonymous access
The pipeline transitions to the exploit skill. Tool results from each step are fed back into history for chained reasoning.
- Set team mode to Blue
- Enable MCP
- Analyze:
analyze these auth.log entries for brute force indicators: [paste logs]
The pipeline selects the analysis skill. The LLM returns a structured timeline, IOCs, and mitigations.
- Remediate:
harden SSH configuration on Ubuntu 22.04 to prevent this attack vector
The pipeline transitions to the defense skill, returning severity-tagged findings with exact commands.
When MCP is enabled and the LLM emits a tool call:
- The tool call is displayed in real time as a collapsible trace in the chat
- The MCP client executes the tool against the configured server
- The result is displayed and injected back into the LLM context
- The LLM generates a follow-up response interpreting the result
When Approval Mode is enabled (sidebar toggle, visible only when MCP is active), RamiBot pauses before executing every MCP tool call and waits for explicit operator confirmation.
Enabling it:
- Enable MCP in the sidebar
- The Approval Mode toggle appears — activate it
What happens on a tool call:
- A banner appears inline between the chat and the message input, showing:
- The tool short name (prefix stripped) and up to 4 key arguments (
target,host,port, etc.) - A risk badge colored by level:
low(green),medium(amber),high(orange),critical(red) — sourced fromrami-kali/config.yaml → risk_levels - A countdown timer from 120 s; turns red at ≤ 15 s
- The tool short name (prefix stripped) and up to 4 key arguments (
- Click APPROVE → tool executes normally; stream continues
- Click DENY → backend injects
[TOOL EXECUTION DENIED BY USER]into the LLM context; LLM reports the denial and suggests alternatives - Timeout (120 s with no response) → auto-denied; banner shows "TIMED OUT — AUTO-DENIED"
- Pressing Stop mid-approval clears the banner immediately
Risk levels are read from rami-kali/config.yaml → risk_levels. Tools not listed default to medium.
Tool execution results can be saved as structured security findings for later review and export.
Saving a finding:
- Expand any tool trace in the chat (click the tool name row)
- Click SAVE AS FINDING at the bottom of the trace
- The modal pre-fills the title (
tool → target), description (cleaned evidence gate text — no raw JSON), and target from the tool arguments - Select severity (Info / Low / Medium / High / Critical) and save
Reviewing findings:
Open Settings > Findings to see all saved findings. From there you can:
- Filter by severity
- Expand long descriptions inline (▼ SHOW MORE / ▲ SHOW LESS)
- Export the filtered set as JSON or CSV (respects the active severity filter)
- Export a single finding as JSON or CSV using the per-card buttons
- Delete individual findings
Description extraction:
The finding description is auto-populated from the tool's evidence gate — the structured summary block that RamiBot's MCP server prepends to every tool result. This gives clean, human-readable evidence (verified facts, status, finding count) without raw JSON dumps or internal instruction text.
The reporting skill generates structured security reports (executive summary, per-finding analysis, attack path, recommendations, appendix). All claims in the report are constrained by the Evidence-Locked Reporting rules — severity, CVEs, and CVSS scores only appear when explicitly present in tool output.
After generating a report, the LLM offers PDF export:
¿Quieres exportar este reporte como PDF? Escribe pdf para descargarlo.
Type pdf (or sí, dale, yes, etc.) — the frontend intercepts the message without making an LLM call, opens a print-ready window, and triggers the browser print dialog automatically.
The PDF export runs three cleaning passes before rendering:
- Strip
<think>...</think>/<thinking>...</thinking>blocks (internal model reasoning — never included in deliverables) - If
<!-- REPORT -->marker is present, discard all content before it (removes any preamble or stray reasoning) - Strip the internal
<!-- REPORT -->marker and PDF offer line
The PDF includes:
- RamiBot logo in the header with generation timestamp
- Full report in clean typography (sans-serif, proper heading hierarchy)
- Severity badges colored by level (
[CRITICAL],[HIGH], etc.) - Formatted tables, code blocks, and lists
- Print-optimized CSS with page-break handling
No additional npm packages are required — PDF generation uses the browser's native print-to-PDF capability via window.print().
- Configure a container name in Settings > Docker
- Click the terminal icon in the chat header to open a terminal panel
- A second panel can be opened (max 2 concurrent)
- The terminal runs inside the configured container via
docker exec
| Method | Path | Description |
|---|---|---|
| GET | /api/conversations |
List all conversations |
| POST | /api/conversations |
Create conversation |
| GET | /api/conversations/{id} |
Get conversation with messages |
| DELETE | /api/conversations/{id} |
Delete conversation |
| GET | /api/conversations/{id}/export?format=json|markdown |
Export |
| Method | Path | Description |
|---|---|---|
| POST | /api/chat |
Non-streaming chat |
| POST | /api/chat/stream |
SSE streaming chat with MCP tool execution |
| POST | /api/chat/approve |
Resolve a pending tool approval (approval_id, approved: bool) |
| Method | Path | Description |
|---|---|---|
| GET | /api/providers |
List providers and capabilities |
| GET | /api/models?provider=X |
List models for provider |
| Method | Path | Description |
|---|---|---|
| GET | /api/mcp/servers |
List configured servers |
| POST | /api/mcp/servers |
Add server |
| DELETE | /api/mcp/servers/{name} |
Remove server |
| GET | /api/mcp/all-tools |
All tools across all servers |
| GET | /api/mcp/tools?server=X |
Tools from specific server |
| POST | /api/mcp/call |
Execute tool directly |
| Method | Path | Description |
|---|---|---|
| POST | /api/terminal/start |
Create terminal session |
| GET | /api/terminal/stream?session_id=X |
SSE output stream |
| POST | /api/terminal/input |
Send input (base64) |
| POST | /api/terminal/resize |
Resize PTY |
| POST | /api/terminal/stop |
Terminate session |
| Method | Path | Description |
|---|---|---|
| GET | /api/scope |
Read allowed_scope and require_scope_check from config.yaml |
| PUT | /api/scope |
Write scope config and restart the rami-kali container |
PUT /api/scope body:
{
"allowed_scope": ["192.168.1.0/24", "10.0.0.0/8"],
"require_scope_check": true
}| Method | Path | Description |
|---|---|---|
| POST | /api/findings |
Save a new finding |
| GET | /api/findings?severity=X&conversation_id=Y&limit=N |
List findings (all filters optional) |
| DELETE | /api/findings/{id} |
Delete a finding |
| GET | /api/findings/export?format=json|csv&severity=X&conversation_id=Y |
Export findings as file download |
POST /api/findings body:
{
"conversation_id": "uuid-or-null",
"tool": "rami-kali__nmap",
"severity": "high",
"title": "nmap → 192.168.1.54",
"description": "status: success\nverified_facts:\n - 22/tcp open ssh ...",
"target": "192.168.1.54"
}| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Health check |
| POST | /api/settings |
Save configuration |
event: token
data: {"token": "<text>"}
event: tool_call
data: {"id": "call_xxx", "name": "server__tool", "arguments": "{...}"}
event: tool_result
data: {"tool": "server__tool", "arguments": {...}, "result": {...}}
event: tool_approval_required
data: {"approval_id": "uuid", "tool_name": "server__tool", "arguments": {...}, "risk_level": "high"}
event: clear_content
data: {}
event: usage
data: {"prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}
event: done
data: {"token_usage": {...}, "latency_ms": 1840.5}
event: error
data: {"error": "..."}
RamiBot is designed for use in authorized, controlled environments.
- No built-in authentication. Do not expose to untrusted networks.
- API keys are stored in plaintext in
backend/settings.json. Protect this file accordingly. - The terminal feature executes commands inside Docker containers. Ensure containers are properly isolated from the host and network.
- The Tor feature modifies iptables rules inside containers. It requires NET_ADMIN or privileged mode and is intended for isolated lab use only.
- The skill system generates security-focused LLM prompts. Use only within the scope of authorized engagements or controlled research environments.
- No liability is assumed for use outside of authorized contexts. The user is responsible for compliance with applicable laws and organizational policies.
| Layer | Technology |
|---|---|
| Backend framework | FastAPI + Uvicorn |
| Async database | aiosqlite (SQLite 3, WAL mode) |
| HTTP client | httpx |
| Server-Sent Events | sse-starlette |
| Frontend framework | React 19 |
| Bundler | Vite 7 |
| State management | Zustand 5 |
| Terminal emulator | xterm.js (@xterm/xterm 6) |
| Markdown rendering | react-markdown + remark-gfm + rehype-highlight |
| Icons | lucide-react |
cd backend
python -m pytest tests/ -vRamiBot uses GitHub Discussions as the main place for community interaction.
Join the discussions to share ideas, experiments, and workflows.
📣 Announcements Project updates, releases, and important news.
🧠 Local LLMs Running RamiBot with local models, benchmarks, GPU performance, and configuration tips.
🧪 Labs & Experiments Experiments with workflows, tool chaining, and AI-assisted security operations.
🌍 Real-World Cases Examples of practical security analysis workflows using RamiBot.
💡 Ideas Feature proposals and suggestions for improving the project.
🛠 Troubleshooting Help with errors, setup problems, Docker issues, and debugging.
👉 Join the discussions here: https://github.com/RamiBotAI/ramibot/discussions

