[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"readme:searchbox":3},"\u003Ch1>Searchbox\u003C\u002Fh1>\n\u003Cp>Given a query, \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhanxiao\u002Fdataroom\" rel=\"nofollow ugc noopener\">a \u003Ccode>.zip\u003C\u002Fcode> dataroom\u003C\u002Fa>, and a token budget. The local \u003Ccode>Qwen3.6-35B-A3B\u003C\u002Fcode> in a\nminimal \u003Ca href=\"https:\u002F\u002Fpi.dev\" rel=\"nofollow ugc noopener\">Pi\u003C\u002Fa> harness explores the dataroom with local tools such as bash, grep, embeddings, rerankers in an \u003Cstrong>airgapped\u003C\u002Fstrong> loop, then answers.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fraw.githubusercontent.com\u002Fhanxiao\u002Fsearchbox\u002FHEAD\u002Fdocs\u002Fimg\u002Fbanner.png\" alt=\"Searchbox\" \u002F>\u003C\u002Fp>\n\u003Cp align=\"center\">\n  \u003Cb>Live demo → \u003Ca href=\"https:\u002F\u002Fhanxiao.io\u002Fsearchbox\" rel=\"nofollow ugc noopener\">hanxiao.io\u002Fsearchbox\u003C\u002Fa>\u003C\u002Fb>\n\u003C\u002Fp>\u003Ch2>Why\u003C\u002Fh2>\n\u003Cp>Everyone who knows me knows I'm super test-time-com\"pilled\". In my view, \u003Cstrong>search is test-time compute (TTC)\u003C\u002Fstrong>: you wire trained embeddings, rerankers, multi-vector retrievers, query expanders into a pipeline at test-time to squeeze out relevancy. Don't scale TTC, say a keyword search hands you the answer, and it's probably not good enough. Scale it, say add embedding search then filter with a reranker, and you most likely get a better one. So I built \u003Ccode>searchbox\u003C\u002Fcode> as a testbed to explore a few questions on TTC:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Model preferences: which tool does it reach for in agentic search?\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Farxiv.org\u002Fabs\u002F2605.15184\" rel=\"nofollow ugc noopener\">Is grep really all you need\u003C\u002Fa>, i.e. where does a dense retriever add nothing to search quality?\u003C\u002Fli>\n\u003Cli>Does scaling test-time compute via token budget forcing give better answers, especially on the hard questions?\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>To make this work, I prebuilt a few projects to pave the road for searchbox: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhanxiao\u002Fdataroom\" rel=\"nofollow ugc noopener\">dataroom\u003C\u002Fa>, which does agentic crawling and spits out a zip; and \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhanxiao\u002Fknowledge-graph-extractor\" rel=\"nofollow ugc noopener\">knowledge-graph\u003C\u002Fa>, which extracts entity relations and walks the longest path to find non-trivial questions to test searchbox with. Feel free to dig into those too.\u003C\u002Fp>\n\u003Cp>Finally, I made searchbox an airgapped harness, because I don't want the model cheating with web information. I want to lock search in the box and it should exhaustively and exclusively use what's in the box (which is a knowledge dump .zip from the web via \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhanxiao\u002Fdataroom\" rel=\"nofollow ugc noopener\">dataroom\u003C\u002Fa>, but not at the searchbox step).\u003C\u002Fp>\n\u003Ch2>How it works\u003C\u002Fh2>\n\u003Cp>You submit a prompt, \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fhanxiao\u002Fdataroom\" rel=\"nofollow ugc noopener\">an optional dataroom \u003Ccode>.zip\u003C\u002Fcode>\u003C\u002Fa> (when not given the built-in \u003Ccode>jina-corpus.zip\u003C\u002Fcode> is then used), and a turn budget from the homepage:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fraw.githubusercontent.com\u002Fhanxiao\u002Fsearchbox\u002FHEAD\u002Fdocs\u002Fimg\u002Fmain-ui.png\" alt=\"Searchbox main UI\" \u002F>\u003C\u002Fp>\n\u003Cp>\u003Ccode>server\u002Frun_searchbox.py\u003C\u002Fcode> then drives a \u003Ccode>pi --mode rpc\u003C\u002Fcode> session:\u003C\u002Fp>\n\u003Col>\n\u003Cli>The dataroom is unzipped to \u003Ccode>dataroom\u002F\u003C\u002Fcode> (read-only; a single wrapper dir is stripped). The\nsidecar (\u003Ccode>server\u002Fdataroom_service.py\u003C\u002Fcode>) indexes \u003Cstrong>nothing\u003C\u002Fstrong> at boot - retrieval scopes are\nembedded lazily on first use, and embeddings are cached per \u003Ccode>(text, role)\u003C\u002Fcode> for the life of the\njob process so identical text is never embedded twice (across turns or tools).\u003C\u002Fli>\n\u003Cli>The task is appended to Pi's \u003Cstrong>system prompt\u003C\u002Fstrong> (\u003Ccode>--append-system-prompt\u003C\u002Fcode>): answer from\n\u003Ccode>dataroom\u002F\u003C\u002Fcode>, no network, use any tools or build your own, write the answer to \u003Ccode>ANSWER.md\u003C\u002Fcode>. It\nis present every turn and never compacted, so the task stays stable for the whole budget. The\nquestion is sent once as the first user message. No skill.\u003C\u002Fli>\n\u003Cli>Pi runs its own loop and compaction, untouched. The only thing added over vanilla Pi: while\nthe budget is unspent and Pi goes idle, send a bare \u003Ccode>Continue.\u003C\u002Fcode>. As a backstop the harness\nalso captures the model's final non-thinking message to \u003Ccode>ANSWER.md\u003C\u002Fcode> each turn, so there is an\nanswer even if the model never wrote the file itself (it never clobbers a model-written one).\u003C\u002Fli>\n\u003Cli>Force-budget OFF (default): stop after the \u003Cstrong>first turn\u003C\u002Fstrong> (turn=1 probe - the common case for\nmeasuring single-shot answer quality). ON: run until the turn budget is used (one turn = one\n\u003Ccode>Continue.\u003C\u002Fcode> -&gt; agent works -&gt; idle). \u003Ccode>run_meta.json\u003C\u002Fcode> records stop reason, turns, per-turn token\nbreakdown, tool calls, and config. (We stop at a turn boundary because a run cannot be cleanly\ninterrupted mid-turn anyway, and turns are the user-legible unit.)\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>The per-job dashboard streams the live run: context window, token usage, turn budget, tool-call\ndistributi\u003C\u002Fp>\n",1784240408032]