An operating system for search agents — scheduling, state management, monitoring, and skill reuse as system-level infrastructure.
Follow the complete Web UI workflow, from connecting model and search providers to building a schema, tracing live research, verifying evidence, repairing gaps, and exporting the final result.
SearchOS is operating-system-level infrastructure for search agents. It lifts the recurring problems of deep search — context governance, shared state, anomaly oversight, knowledge reuse, report synthesis — into system-level services, so search agents run like scheduled, supervised processes.
Its reference implementation pairs a long-lived Orchestrator — an LLM controller that plans, dispatches, and converges from real-time SOCM snapshots — with short-lived sub-agents, all wrapped by middleware that runs like a kernel in the background.
A query q decomposes into a chain of sub-question nodes; each table Tm (an entity×attribute coverage grid) frames the nodes it grounds. Two shapes recur: tables partition the chain to cover breadth, or tables overlap so that the node(s) framed by all of them form the answer set satisfying every constraint.
E* (the intersection).A worked case: q = “Compare leading 2025 LLMs — context window, price, benchmark”. Swimlanes per agent, time flows left→right. Solid arrows = dispatch / trigger (control); dashed arrows = return result.
explore_agent — Disambiguation / candidate enumerationsearch_agent — Evidence collectionwriter_agent — Structured drafting / finalizeConflict adjudication is handled at the system layer (Scheduler + conflict arbitration), not by a dedicated agent.
./install.sh
source .venv/bin/activate
searchos "your query"
searchos # interactive TUI
How SearchOS’s five layers couple and collaborate — control, data, state, signal, and skill flow.
Click a legend button to isolate a flow type; hover a component to trace its connections.
Three parts make the diagram work: the agents that decide, the state they share, and the middleware that runs around every step.
One brain, a small crew. A single Orchestrator plans and decides; it never searches the web itself — it hands out jobs to short-lived sub-agents and checks their work.
When a question is vague, it does a quick reconnaissance pass — what's out there, which entities exist, where the ambiguities are — so the Orchestrator can draft a sensible plan. It writes no answer.
search / open / find only, no evidence extraction. Optional (enable_explore); spawned via enqueue_tasks(agent_type="explore_agent") only when the schema can't be drafted directly. Persona in explore_agent/agent.md.The workhorse. Given a few specific cells to fill, it searches, opens authoritative pages, and pulls out facts. Several run in parallel, each on its own slice of the problem.
search/open/find) + access-skill executors. Findings reach state automatically — middleware extracts evidence from its open/find results; the agent itself never writes SOCM. Batched via enqueue_tasks. Persona in search_agent/agent.md.Once enough evidence is in, one long-lived writer reads the collected facts and drafts the report section by section — citing sources, flagging conflicts, and pointing out remaining gaps. It never browses the web.
write_section with cited evidence ids…) + SOCM read tools (read_coverage/read_evidence…); no browser. Singleton per session, gated by enable_writer_agent. Triggered by WriterTriggerSensor at a coverage stage (default ≥ 0.5) or proactively woken via send_followup. Persona in writer_agent/agent.md.The Orchestrator is the sole decision-maker — it reads the latest state each step and decides what to dispatch next or when to converge. Each sub-agent runs on a frozen state snapshot, so a dozen work in parallel without their reasoning bleeding together. Tap a card for the real tools & triggers.
The shared memory. Everything the agents learn is folded into four living objects — not a growing chat log.
A priority queue of search tasks. Each task moves pending → running → done (or blocked / cancelled), so the system always knows what's left to explore.
FrontierMemory of FrontierTask. Orchestrator pushes via enqueue_tasks; the Scheduler dispatches, unblocks, and reaps.Every claim found on the web becomes a node, linked by support / conflict / refine edges — so contradictions surface instead of getting buried.
EvidenceGraph. Written automatically by EvidenceExtractionMiddleware after each tool call.An entity × attribute table that marks each cell missing / filled / uncertain / hard. It's the system's sense of "what do we still not know?"
CoverageMap of CoverageCell (CellStatus). Seeded by create_schema(), backfilled as evidence grows; drives gap detection and Writer structure.A record of what isn't working — repeated queries, dead-end sources — so the system stops digging in the same dry hole.
StrategyMemory (state attr strategy_log): StrategyPattern anti-patterns + FailureMemory. Feeds the Sensor layer and post-mortem distillation.All four are persisted to workspace/<session>/search_state.json with atomic file locking, so multiple sub-agents can update them in parallel without clobbering each other. Tap a card for the real class names.
The automatic plumbing. Hooks wrap every model call and tool call, so the agents stay focused while context, safety, and bookkeeping happen on their own.
Keeps the prompt small and cache-friendly: layer the context, trim overflow, and splice in a skill playbook when one applies.
LayeredContextMiddleware · DynamicTrimMiddleware · ControlMiddleware (skill injection). Bound to awrap_model_call.Watches for trouble — loops, repeated queries, stalls — and either nudges the agent with advice or hard-stops runaway dispatch. Also fires the writer trigger.
LoopSensorImpl, StallEscalationSensor, DispatchRoundSensor, WriterTriggerSensor. LLM-based: StrategySensorImpl, EvaluatorSensorImpl (4-D verdict). Bound to awrap_tool_call / checkpoints.When a page is read, it cleans and de-dupes the text, runs an LLM judge to pull out claims, and writes them straight into the Evidence Graph and CoverageMap.
EvidenceExtractionMiddleware: gating (schema / length / error / dup-hash) → LLM extract & merge-by-URL → persist EvidenceNode + provenance → Coverage backfill. Background flush, synchronous drain on the final round.Two hook points hold it together. awrap_model_call shapes context going in and reads reasoning coming out; awrap_tool_call guards budget, runs the sensors, and triggers extraction. Sub-agents only read pages — middleware is the single place that writes state. Tap a card for the real class names.
Middleware is mounted on model_call and tool_call events; EvidenceExtraction writes evidence when tool results or final summaries are extractable.
Follow one question on its journey — from the moment it arrives to the finished report.md. Five milestones, one of them a loop.
A question arrives. SearchOS spins up a fresh workspace, starts with a blank slate of state, and wakes the Orchestrator — the single mind that will run the whole search.
The Orchestrator turns the question into a plan. When things are vague it sends a scout ahead first; then it draws a coverage map — a table of exactly which facts still need to be found.
The heart of it. Several search agents fan out in parallel, read pages, and evidence is captured automatically into the graph and the map. The Orchestrator checks progress and keeps dispatching — round after round — until coverage is enough.
Once the map is full enough, the writer agent reads the collected evidence and drafts the answer section by section — every claim tied back to its sources, conflicts flagged rather than hidden.
The harness assembles the final document and always guarantees a report.md — falling back through simpler synthesis modes if needed, so a session never ends empty-handed.
Head-to-head scores across deep-search benchmarks.
| Benchmark | Metric | Single Agent | Multi‑Agent System | ||||
|---|---|---|---|---|---|---|---|
| ReAct | Plan‑and‑Solve | Table‑as‑Search | A‑MapReduce | Web2BigTable | Ours | ||
| WideSearch | Item · Precision | 82.9 | 83.8 | 82.4 | 83.1 | 78.3 | 83.9 |
| Item · Recall | 70.2 | 72.9 | 73.5 | 74.2 | 73.4 | 79.7 | |
| Item · F1 | 72.9 | 75.2 | 75.4 | 76.0 | 73.8 | 80.3 | |
| Row · Precision | 58.0 | 58.7 | 57.1 | 56.9 | 57.5 | 59.0 | |
| Row · Recall | 48.8 | 50.2 | 51.6 | 49.8 | 54.0 | 55.8 | |
| Row · F1 | 50.9 | 52.2 | 52.7 | 51.4 | 54.5 | 56.5 | |
| GISA | Table · Item · F1 | 74.8 | 71.2 | 73.4 | 72.5 | 68.1 | 76.9 |
| Table · Row · F1 | 58.1 | 50.7 | 54.1 | 52.1 | 45.3 | 59.7 | |
| Set · F1 | 61.6 | 63.1 | 60.9 | 62.5 | 56.7 | 76.5 | |
| List · F1 | 67.1 | 53.8 | 54.2 | 57.4 | 65.5 | 68.1 | |
| Item · EM | 0.0 | 16.7 | 16.7 | 33.3 | 50.0 | 50.0 | |
Walkthroughs and real runs — more demos landing soon.
@misc{searchos2026,
title={SearchOS-v1: Towards Robust Open-Domain
Information-Seeking Agents Collaboration},
author={Zhang, Yuyao and Gao, Junjie and Wu, Zhengxian and
Fan, Jiaming and Zhang, Jin and Ma, Shihan and Yao, Yao and
Qi, Weiran and Ma, Guiyu and Xu, Xingzhong and Yang, Kai and
Wen, Ji-Rong and Dou, Zhicheng},
year={2026},
howpublished={\url{https://github.com/antins-labs/SearchOS}}
}