OpenPlanter: Recursive LLM Agents for Network Investigation
Hook
Most investigative journalism tools help you visualize data you've already connected—but what if an LLM agent could recursively discover those connections for you, spawning sub-investigations and building knowledge graphs in real-time?
Context
Investigative research across fragmented public records has always been a game of manual cross-referencing. A journalist digging into corporate influence might pull campaign finance data from the FEC, lobbying disclosures from Senate records, and corporate registration documents from state agencies—then spend weeks manually matching entity names across inconsistent formats. Traditional OSINT platforms like Maltego provide structured transforms, but they require upfront integration work for each data source and don't adapt to novel investigation patterns.
OpenPlanter takes a different approach: it treats investigation itself as a recursive LLM workflow. Instead of pre-built transforms, it gives agents 19 tools—file I/O, shell execution, web search via Exa, and critically, the ability to delegate subtasks to child agents. The primary interface is a Tauri 2 desktop app that renders discoveries as an interactive Cytoscape.js knowledge graph while agents work in the background. A Python CLI provides headless automation for batch workflows. This hybrid architecture assumes LLMs can reason about entity resolution better than hand-coded heuristics, while still requiring human oversight of findings.
Technical Insight
The core architectural choice is recursive agent delegation. When the main investigator agent encounters a complex task—say, resolving all board members of a shell company across five jurisdictions—it can spawn a child agent with focused acceptance criteria. That child might spawn its own sub-agents to validate individual entity matches. Here's a simplified version of the delegation mechanism:
def delegate_subtask(self, task_description: str, acceptance_criteria: str, max_depth: int = 4):
if self.current_depth >= max_depth:
return {"error": "Max recursion depth reached"}
child_agent = InvestigatorAgent(
task=task_description,
tools=self.tools,
current_depth=self.current_depth + 1,
llm_provider=self.llm_provider
)
result = child_agent.execute(max_steps=100)
# Verify result meets acceptance criteria via LLM check
validation = self.llm.verify(
result=result,
criteria=acceptance_criteria
)
return result if validation.passed else self.retry_or_escalate()
This pattern enables parallelizable investigation—while one agent searches campaign finance records, another can be scraping corporate registries, and a third validating addresses against property records. The Tauri frontend receives real-time updates via IPC events and renders entities as graph nodes the moment they're discovered.
The knowledge graph visualization uses Cytoscape.js with category-coded node styling. When an agent identifies a new entity—say, a PAC making donations—it emits an event that the frontend captures:
import { invoke } from '@tauri-apps/api/core';
import cytoscape from 'cytoscape';
const cy = cytoscape({
container: document.getElementById('graph'),
style: [
{
selector: 'node[category="organization"]',
style: { 'background-color': '#e74c3c' }
},
{
selector: 'node[category="person"]',
style: { 'background-color': '#3498db' }
}
]
});
// Listen for agent discovery events
await listen('entity-discovered', (event) => {
const { id, label, category, sources } = event.payload;
cy.add({
group: 'nodes',
data: { id, label, category },
classes: category
});
// Update wiki drawer with source documents
updateWikiDrawer(id, sources);
});
The multi-provider LLM abstraction is particularly clever. OpenPlanter supports OpenAI, Anthropic, OpenRouter, Cerebras, and critically, local Ollama instances. This lets investigators run entire workflows without sending potentially sensitive public records to external APIs:
class LLMProvider:
def __init__(self, provider_type: str, config: dict):
self.provider = self._initialize_provider(provider_type, config)
def _initialize_provider(self, provider_type, config):
if provider_type == "ollama":
return OllamaClient(
base_url=config.get("base_url", "http://localhost:11434"),
model=config.get("model", "llama3.1")
)
elif provider_type == "openai":
return OpenAIClient(api_key=config["api_key"])
# ... other providers
def generate(self, prompt: str, tools: list) -> dict:
return self.provider.generate_with_tools(prompt, tools)
The trade-off is significant: local models like Llama 3.1 70B can run investigations without API costs or data exfiltration, but they're noticeably worse at complex entity resolution than GPT-4o or Claude 3.5 Sonnet. In testing with campaign finance data, local models had a ~40% false positive rate on entity matches compared to ~15% for frontier models.
The tool ecosystem gives agents surprising autonomy. Beyond standard LLM tools like web search and document reading, OpenPlanter includes execute_shell, write_file, and run_python_script. This means an agent investigating cryptocurrency flows could write a Python script to parse blockchain data, execute it, and analyze the output—all autonomously. The risk, of course, is that an agent with access to rm -rf and no sandboxing can destroy data. The current implementation trusts the LLM not to be malicious, which is... optimistic.
A background curator agent maintains wiki consistency. As the knowledge graph grows, it identifies contradictions—if one agent found that "John Smith" is CEO of Company A, but another found "J. Smith" in the same role, the curator flags this for review and potentially merges entities. This asynchronous reconciliation prevents the graph from becoming a jumbled mess during long investigations.
Gotcha
The security model is essentially non-existent. Agents have unrestricted shell access to your workspace, and there's no sandboxing, capability restrictions, or approval workflows. If you're investigating adversarial datasets—say, scraped documents that might contain prompt injections—a malicious payload could theoretically trick the agent into executing arbitrary commands. This isn't theoretical paranoia; LLM agents with shell access have been demonstrated to be exploitable. Until OpenPlanter implements containerization or at least capability-based security, treat it like running untrusted code on your machine.
The recursive delegation model can spiral out of control. With 4 depth levels and 100 steps per agent, a poorly-scoped investigation could spawn dozens of child agents, each making hundreds of LLM calls. On expensive providers like GPT-4, this can rack up hundreds of dollars before you realize what's happening. There's no budget limiting or cost estimation before execution. The CLI provides some controls, but the desktop app's conversational interface makes it easy to casually kick off an investigation that burns through your API quota. Even with local models, the computational cost is real—running Llama 3.1 70B on consumer hardware means investigations can take hours for complex graphs.
Verdict
Use OpenPlanter if you're conducting exploratory investigations across heterogeneous public datasets where hypothesis generation matters more than guaranteed accuracy—think investigative journalism, corporate due diligence, or academic research into influence networks. The recursive agent model excels at discovering non-obvious connections that would take weeks of manual cross-referencing, and the real-time knowledge graph makes pattern recognition visceral. It's especially powerful if you have access to frontier LLMs (Claude 3.5 Sonnet or GPT-4o) and the budget to let agents explore freely. Skip it if you're working with sensitive data that can't be sent to external APIs (the local Ollama option has severe quality trade-offs), need audit trails for regulatory compliance (agent reasoning is often opaque), or lack the expertise to critically validate LLM-generated entity matches. The unrestricted shell access makes this fundamentally unsuitable for production automation or untrusted environments. This is a power tool for experts who understand its sharp edges.