A local multi-agent decision support framework. Six AI agents observe the same problem from different angles to triangulate a recommendation built on LangGraph and Ollama. Fully local, no API keys required.
Now with a dedicated cybersecurity suite: incident triage, vulnerability prioritisation, threat modelling, and policy analysis — each with a specialist agent pipeline, MITRE ATT&CK mapping, and compliance analysis built in.
You give it a question, a security incident, a build-vs-buy decision, a CVE prioritisation call and a pipeline of specialised AI agents works through it together. One structures the problem, one researches it, one analyses it from domain angles, one specifically tries to poke holes in the logic, one synthesises a recommendation, and one rates how confident the whole thing is.
In Deliberation Mode, two adversarial agents (Optimist and Pessimist) take explicitly opposing stances before synthesis, so the final recommendation is forced to resolve a real conflict rather than smooth one over.
In Security Mode, a Red Teamer and a Compliance Officer replace those adversarial agents, one models the worst-case attacker interpretation, the other maps regulatory obligations and policy gaps.
Everything runs locally. No API keys. No internet connection required. No data leaving your machine.
git clone https://github.com/kiinitix/parallax
cd parallax
docker compose upFirst run pulls the models (~12 GB). After that it starts in seconds.
Interactive CLI:
docker compose exec app python -m src.interfaces.cli.interactiveGradio UI (browser, port 7860):
docker compose exec app python -m src.interfaces.ui.gradio_appStreamlit dashboard (browser, port 8501):
docker compose exec app streamlit run src/interfaces/ui/streamlit_app.pyPrerequisites: Python 3.11+, Ollama, NVIDIA GPU recommended
git clone https://github.com/kiinitix/parallax
cd parallax
# Pull the models (once)
ollama pull llama3
ollama pull mistral
ollama pull phi3
ollama pull nomic-embed-text
# Set up environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e .
# Launch
python -m src.interfaces.cli.interactive # CLI
python -m src.interfaces.ui.gradio_app # Gradio UI → localhost:7860
streamlit run src/interfaces/ui/streamlit_app.py # Streamlit → localhost:8501python -m src.interfaces.cli.interactiveType any question directly. Commands:
| Command | What it does |
|---|---|
ask <question> |
Run the decision pipeline |
persona |
View and switch expert personas |
mode |
Switch pipeline mode |
memory |
Browse and search the memory store |
history |
View recent session history |
help |
Show all commands |
python -m src.interfaces.ui.gradio_app
# → http://localhost:7860Five tabs: Incident Triage, Vulnerability Prioritisation, Threat Modelling, Policy & Controls, General Decisions. Each tab is pre-configured with the right pipeline mode, default persona, and placeholder examples.
streamlit run src/interfaces/ui/streamlit_app.py
# → http://localhost:8501Dashboard layout with severity badges, confidence bars, MITRE technique display, expandable reasoning trace, and persistent persona selector in the sidebar. Better for actual workflow use than the Gradio UI.
The security suite adds four specialised pipeline modes, two security agents, and four security-specific personas on top of the core framework.
| Mode | Agents | Use case |
|---|---|---|
triage |
intake → research → red_teamer → compliance → domain_expert → critic → synthesis → confidence | Active incident — isolate, escalate, or monitor? |
vuln |
intake → research → red_teamer → compliance → critic → synthesis → confidence | CVE or finding prioritisation |
threat_model |
intake → research → red_teamer → domain_expert → critic → synthesis → confidence | Architecture review, attack surface analysis |
policy |
intake → research → compliance → domain_expert → critic → synthesis → confidence | Security policy decisions, control selection |
RedTeamerAgent (mistral)
Thinks like an attacker. Assumes breach until proven otherwise. Maps behaviours to MITRE ATT&CK tactics and techniques. Produces: attacker interpretation, kill chain stage, worst-case scenario, immediate actions, escalation call.
ComplianceAgent (mistral)
Thinks like a regulator. Identifies applicable frameworks (GDPR, ISO 27001, NIST CSF, SOC 2, PCI-DSS, HIPAA), breach notification obligations, policy gaps, and required documentation. Reads the Red Teamer's output before responding so it's not working in isolation.
| ID | Name | Bias |
|---|---|---|
red_teamer |
Red Teamer | Assume breach, worst-case interpretation, MITRE mapping |
compliance_officer |
Compliance Officer | Regulatory obligations, audit trail, legal exposure |
soc_analyst |
SOC Analyst | Alert fatigue aware, triage speed, actionable in 15 minutes |
ciso |
CISO | Business risk framing, board-level communication |
Every security run produces:
- Severity — critical / high / medium / low extracted from the analysis
- Escalation flag — yes/no with reasoning
- Red team analysis — attacker perspective with MITRE technique IDs
- Compliance analysis — applicable frameworks, breach notification, policy gaps
- Immediate actions — ordered, specific, actionable steps
- Confidence score — calibrated 0–100%, not inflated
- Reasoning trace — full chain of agent reasoning, auditable
# Incident triage
Unusual outbound traffic to 3 unknown IPs from a dev box at 2am.
No user logged in. Process: svchost.exe. Packets ~400KB every 5 minutes.
Should we isolate the machine now?
# Vulnerability prioritisation
CVE-2024-1234: CVSS 9.1, affects our public auth service, no patch yet.
CVE-2024-5678: CVSS 7.8, affects internal Jenkins, patch available.
CVE-2024-9012: CVSS 6.5, affects dev dependency, not in production.
Which do we prioritise?
# Threat modelling
We're building a payment microservice that stores card tokens.
It communicates with the fraud engine over internal gRPC.
Deployed on AWS ECS behind an ALB. What are the critical threat vectors?
# Policy decision
Should we enforce MFA on all internal developer tools including
local environments, or scope it to production access only?
| Mode | Agents | Time | Use when |
|---|---|---|---|
full |
6 agents | ~3 min | High-stakes decisions |
quick |
3 agents | ~60s | Fast gut-check |
research |
2 agents | ~45s | Just need context |
critical |
4 agents | ~2 min | Surface weaknesses |
deliberate |
8 agents | ~5 min | Genuine disagreement needed |
triage |
8 agents | ~5 min | Security incident triage |
vuln |
7 agents | ~4 min | Vulnerability prioritisation |
threat_model |
7 agents | ~4 min | Threat modelling |
policy |
7 agents | ~4 min | Security policy decisions |
The standard pipeline has all agents writing toward convergence — each reads the previous output and naturally aligns with it. Deliberation Mode fixes this by adding two adversarial agents that take explicitly opposing stances before synthesis.
> mode
# select: deliberate
> Should we rewrite our legacy codebase from scratch or keep patching it?
The Optimist argues for the most promising path. The Pessimist counters it directly — it sees the Optimist's position before responding. The Domain Expert analyses from domain perspectives. The Synthesis agent must then name the central conflict, pick a side, explain why, and acknowledge what the losing side got right.
The output includes:
- Each agent's structured perspective with confidence score
- A conflict map with disagreement score (0–100%)
- Explicit conflict resolution from synthesis
- What the losing side got right
| ID | Name | Bias |
|---|---|---|
balanced |
Balanced Analyst | No particular bias (default) |
startup_cto |
Startup CTO | Speed-first, lean, small-team assumptions |
risk_analyst |
Risk Analyst | Evidence-driven, failure-mode-first |
vc_investor |
VC Investor | ROI and scalability lens |
senior_engineer |
Senior Engineer | Maintainability, technical debt |
contrarian |
Contrarian Analyst | Challenges every consensus |
pragmatist |
Pragmatist | What can we actually ship? |
red_teamer |
Red Teamer | Assume breach, attacker perspective |
compliance_officer |
Compliance Officer | Regulatory obligations first |
soc_analyst |
SOC Analyst | Triage speed, alert fatigue aware |
ciso |
CISO | Business risk framing |
Switch persona in the CLI: > persona
Create a custom persona: > persona new
The Research agent automatically retrieves relevant context from past decisions using ChromaDB. Every completed run is saved to memory. Feed your own data with ingest.py:
# Files
python ingest.py --file path/to/incident-report.pdf
python ingest.py --folder data/documents/
# URLs
python ingest.py --url https://yourwiki.com/playbooks
# Raw text
python ingest.py --text "Our policy: never deploy on Fridays." --source "team-rules"
# View what's stored
python ingest.py --listGood data to ingest for security use:
- Incident postmortems and lessons learned
- Internal runbooks and playbooks
- Threat intel reports
- Asset inventory and criticality ratings
- Past CVE analysis and patch decisions
- MITRE ATT&CK technique descriptions
parallax/
├── config/
│ ├── agents.yaml # model + parameters per agent
│ ├── graph.yaml # execution settings and timeouts
│ ├── memory.yaml # ChromaDB and embedding config
│ └── personas.json # saved custom personas
├── data/
│ ├── chroma/ # vector store (persistent)
│ ├── documents/ # drop files here for file_reader tool
│ └── history.jsonl # session history
├── docs/
│ ├── ADR.md # architecture decision records
│ ├── DIAGRAMS.md # Mermaid architecture diagrams
│ └── VIDEO_SCRIPT.md # demo walkthrough script
├── logs/ # daily JSON log files
├── src/
│ ├── agents/
│ │ ├── base.py # BaseAgent — all agents inherit this
│ │ ├── intake.py
│ │ ├── research.py # RAG-enabled
│ │ ├── domain_expert.py
│ │ ├── critic.py
│ │ ├── synthesis.py # deliberation-aware
│ │ ├── confidence.py
│ │ ├── deliberation.py # OptimistAgent + PessimistAgent
│ │ └── security.py # RedTeamerAgent + ComplianceAgent
│ ├── graph/
│ │ ├── state.py # GraphState + AgentPerspective + SecurityContext
│ │ ├── builder.py # graph compiler, all modes
│ │ └── validator.py # output validation
│ ├── interfaces/
│ │ ├── cli/
│ │ │ ├── interactive.py # main CLI
│ │ │ └── deliberation_display.py
│ │ └── ui/
│ │ ├── gradio_app.py # Gradio UI → :7860
│ │ └── streamlit_app.py # Streamlit dashboard → :8501
│ ├── memory/
│ │ └── store.py # ChromaDB + Ollama embeddings
│ ├── tools/
│ │ └── registry.py # calculator, file_reader, summariser
│ ├── config.py
│ ├── logger.py
│ └── personas.py
├── ingest.py # data ingestion CLI
├── run.py # single-question runner
├── test_adversarial.py # adversarial test suite
├── Dockerfile
├── docker-compose.yml
└── pyproject.toml
Edit config/agents.yaml no code change needed:
agents:
synthesis:
model: llama3 # swap to mistral, phi3, or any ollama model
temperature: 0.4- Create
src/agents/my_agent.pyinheritingBaseAgent - Implement
AGENT_NAME,system_prompt,build_prompt(),parse_response() - Add to
src/graph/builder.pyin the relevant mode's node list - Add config to
config/agents.yaml
The base class handles retries, logging, timeout, and persona injection automatically.
In src/tools/registry.py:
class MyTool(BaseTool):
NAME = "my_tool"
DESCRIPTION = "Does X. Input: query (str)."
def run(self, query: str = "", **kwargs) -> str:
return call_my_api(query)
registry.register(MyTool())Via CLI:
> persona new
Via JSON add to config/personas.json:
{
"personas": {
"legal_advisor": {
"name": "Legal Advisor",
"description": "Compliance-first, contract-aware.",
"context": "You are advising a company with significant legal exposure...",
"style": "cautious"
}
}
}As a built-in add to DEFAULT_PERSONAS in src/personas.py.
In src/graph/builder.py:
MODES = {
# existing modes...
"my_mode": ["intake", "research", "my_agent", "critic", "synthesis", "confidence"],
}Also add to MODES in src/interfaces/cli/interactive.py to make it appear in the mode command.
Edit config/memory.yaml:
retrieval:
top_k: 5 # documents to retrieve per query
score_threshold: 0.3 # similarity threshold — raise to 0.5 for tighter matching| Setup | Minimum | Recommended |
|---|---|---|
| GPU VRAM | 6 GB | 12 GB+ |
| RAM | 16 GB | 32 GB |
| Disk | 15 GB | 25 GB |
| GPU | Any NVIDIA (CUDA) | RTX 3070+ |
CPU-only works but runs take 10–20 minutes instead of 3–5.
ollama list shows no models after restart
[System.Environment]::SetEnvironmentVariable("OLLAMA_MODELS", "D:\your-path\ollama-models", "User")
taskkill /F /IM ollama.exe
# Restart Ollama from Start menuConfidence score shows 50% with no explanation
Known phi3 formatting quirk. The output validator catches it and defaults to 0.5. The confidence.py agent has an updated prompt that reduces frequency of this.
ChromaDB error on startup
Delete data/chroma/ and restart. The store rebuilds from future runs.
First run is slow Normal. Models load into GPU memory on first call (~10–30s). Subsequent agents in the same run are faster.
make_initial_state() got an unexpected keyword argument
Your src/graph/builder.py is outdated. Replace it with the latest version — make_initial_state takes deliberation and security keyword arguments.
MIT
Parallax is a technique in astronomy and physics for measuring the distance to an object by observing it from two or more different positions. The object itself doesn't move but by shifting your vantage point and measuring the apparent displacement, you can determine something about it that no single observation could tell you alone.
That's the idea behind this framework.
A single AI model asked a question gives you one answer from one position. It has no way to challenge its own assumptions, no mechanism to surface what it doesn't know, and no honest accounting of how confident it actually is. You get a response, not a deliberation.
Parallax runs the same problem through six agents, each observing from a different position, structural, empirical, domain-specific, adversarial, synthetic, and evaluative. The recommendation that emerges isn't the output of one model's best guess. It's the result of triangulation: multiple vantage points, measured displacement, a clearer fix on the truth.
The name also felt right for another reason. Parallax is a local measurement. You don't need to phone anyone. You just need to move, look again, and do the geometry yourself.
That's what this software does and it does it entirely on your own machine.