Skip to content

Kiinitix/parallax

Repository files navigation

Parallax

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.


What it actually does

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.


Quick start

Option A — Docker (recommended)

git clone https://github.com/kiinitix/parallax
cd parallax
docker compose up

First run pulls the models (~12 GB). After that it starts in seconds.

Interactive CLI:

docker compose exec app python -m src.interfaces.cli.interactive

Gradio UI (browser, port 7860):

docker compose exec app python -m src.interfaces.ui.gradio_app

Streamlit dashboard (browser, port 8501):

docker compose exec app streamlit run src/interfaces/ui/streamlit_app.py

Option B — Local install

Prerequisites: 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:8501

Interfaces

Interactive CLI

python -m src.interfaces.cli.interactive

Type 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

Gradio UI

python -m src.interfaces.ui.gradio_app
# → http://localhost:7860

Five 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 Dashboard

streamlit run src/interfaces/ui/streamlit_app.py
# → http://localhost:8501

Dashboard 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.


Security suite

The security suite adds four specialised pipeline modes, two security agents, and four security-specific personas on top of the core framework.

Pipeline modes

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

Security agents

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.

Security personas

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

What the security output includes

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

Example security queries

# 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?

Pipeline modes (all modes)

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

Deliberation Mode

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

Personas

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


Memory and data ingestion

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 --list

Good 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

Project structure

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

Customising the system

Changing which model each agent uses

Edit config/agents.yaml no code change needed:

agents:
  synthesis:
    model: llama3       # swap to mistral, phi3, or any ollama model
    temperature: 0.4

Adding a new agent

  1. Create src/agents/my_agent.py inheriting BaseAgent
  2. Implement AGENT_NAME, system_prompt, build_prompt(), parse_response()
  3. Add to src/graph/builder.py in the relevant mode's node list
  4. Add config to config/agents.yaml

The base class handles retries, logging, timeout, and persona injection automatically.

Adding a new tool

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())

Creating a custom persona

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.

Adding a new pipeline mode

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.

Adjusting retrieval

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

Hardware requirements

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.


Troubleshooting

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 menu

Confidence 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.


License

MIT


Name and inspiration

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.

About

A local multi-agent decision support framework. Six AI agents analyse problems from different perspectives to converge on a structured recommendation, built on LangGraph and Ollama. Fully local, no API keys required.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors