[{"data":1,"prerenderedAt":2286},["ShallowReactive",2],{"navigation":3,"page-\u002Fchapters\u002Fwhat-transfers":102,"surround-\u002Fchapters\u002Fwhat-transfers":2281},[4,8],{"title":5,"path":6,"stem":7},"Home","\u002F","index",{"title":9,"path":10,"stem":11,"children":12,"page":101},"Chapters","\u002Fchapters","2.chapters",[13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97],{"title":14,"path":15,"stem":16},"Chapter 1. What an Agent Actually Is","\u002Fchapters\u002Fwhat-an-agent-actually-is","2.chapters\u002F01.what-an-agent-actually-is",{"title":18,"path":19,"stem":20},"Chapter 2. The Minimum Viable Loop","\u002Fchapters\u002Fminimum-viable-loop","2.chapters\u002F02.minimum-viable-loop",{"title":22,"path":23,"stem":24},"Chapter 3. Messages, Turns, and the Transcript","\u002Fchapters\u002Fmessages-turns-transcript","2.chapters\u002F03.messages-turns-transcript",{"title":26,"path":27,"stem":28},"Chapter 4. The Tool Protocol","\u002Fchapters\u002Ftool-protocol","2.chapters\u002F04.tool-protocol",{"title":30,"path":31,"stem":32},"Chapter 5. Streaming, Interruption, and Error Handling","\u002Fchapters\u002Fstreaming-interruption-errors","2.chapters\u002F05.streaming-interruption-errors",{"title":34,"path":35,"stem":36},"Chapter 6. Safe Tool Execution","\u002Fchapters\u002Fsafe-tool-execution","2.chapters\u002F06.safe-tool-execution",{"title":38,"path":39,"stem":40},"Chapter 7. The Context Window Is a Resource","\u002Fchapters\u002Fcontext-window-as-resource","2.chapters\u002F07.context-window-as-resource",{"title":42,"path":43,"stem":44},"Chapter 8. Compaction","\u002Fchapters\u002Fcompaction","2.chapters\u002F08.compaction",{"title":46,"path":47,"stem":48},"Chapter 9. External State: The Scratchpad","\u002Fchapters\u002Fscratchpad","2.chapters\u002F09.scratchpad",{"title":50,"path":51,"stem":52},"Chapter 10. Retrieval","\u002Fchapters\u002Fretrieval","2.chapters\u002F10.retrieval",{"title":54,"path":55,"stem":56},"Chapter 11. Designing Tools Models Can Actually Use","\u002Fchapters\u002Fdesigning-tools","2.chapters\u002F11.designing-tools",{"title":58,"path":59,"stem":60},"Chapter 12. The Tool Cliff and Dynamic Loading","\u002Fchapters\u002Ftool-cliff","2.chapters\u002F12.tool-cliff",{"title":62,"path":63,"stem":64},"Chapter 13. MCP: Tools From the Outside World","\u002Fchapters\u002Fmcp","2.chapters\u002F13.mcp",{"title":66,"path":67,"stem":68},"Chapter 14. Sandboxing and Permissions","\u002Fchapters\u002Fsandboxing-permissions","2.chapters\u002F14.sandboxing-permissions",{"title":70,"path":71,"stem":72},"Chapter 15. Sub-agents","\u002Fchapters\u002Fsub-agents","2.chapters\u002F15.sub-agents",{"title":74,"path":75,"stem":76},"Chapter 16. Structured Plans and Verified Completion","\u002Fchapters\u002Fplans-verified-completion","2.chapters\u002F16.plans-verified-completion",{"title":78,"path":79,"stem":80},"Chapter 17. Parallelism and Shared State","\u002Fchapters\u002Fparallelism-shared-state","2.chapters\u002F17.parallelism-shared-state",{"title":82,"path":83,"stem":84},"Chapter 18. Observability","\u002Fchapters\u002Fobservability","2.chapters\u002F18.observability",{"title":86,"path":87,"stem":88},"Chapter 19. Evals","\u002Fchapters\u002Fevals","2.chapters\u002F19.evals",{"title":90,"path":91,"stem":92},"Chapter 20. Cost Control","\u002Fchapters\u002Fcost-control","2.chapters\u002F20.cost-control",{"title":94,"path":95,"stem":96},"Chapter 21. Resumability and Durable State","\u002Fchapters\u002Fresumability","2.chapters\u002F21.resumability",{"title":98,"path":99,"stem":100},"Chapter 22. What Transfers, Where to Go","\u002Fchapters\u002Fwhat-transfers","2.chapters\u002F22.what-transfers",false,{"id":103,"title":98,"body":104,"description":117,"extension":2276,"meta":2277,"navigation":2278,"path":99,"seo":2279,"stem":100,"__hash__":2280},"content\u002F2.chapters\u002F22.what-transfers.md",{"type":105,"value":106,"toc":2266},"minimark",[107,111,118,121,328,331,336,355,1775,1778,1785,1787,1791,1794,1800,1806,1816,1826,1832,1838,1848,1858,1861,1863,1867,1870,1873,1875,1879,1882,1887,1900,1905,1916,1921,1935,1940,1951,1956,1967,1972,1983,1988,1999,2004,2012,2017,2028,2033,2041,2044,2046,2050,2053,2059,2068,2074,2080,2086,2092,2098,2104,2110,2116,2118,2122,2125,2131,2137,2143,2157,2163,2165,2169,2218,2222,2248,2250,2262],[108,109,98],"h1",{"id":110},"chapter-22-what-transfers-where-to-go",[112,113,114],"p",{},[115,116,117],"em",{},"Previously: twenty-one chapters of cumulative engineering. The harness has a loop, a transcript, adapters for three providers, a tool registry with validation and loop detection, streaming, async, permissions, MCP integration, a scratchpad, retrieval, compaction, sub-agents, structured plans, parallel coordination, observability, evals, cost control, and durable checkpointing.",[112,119,120],{},"One chapter left. Not for more machinery — the machinery is done. For stepping back. We run the full harness against three providers to prove the adapter seam earns its name. We name what the harness doesn't do and where each gap would be filled. We close with a scorecard for the next framework you evaluate.",[122,123,127,208,321],"figure",{"className":124},[125,126],"not-prose","my-8",[128,129,136,164,186],"div",{"className":130},[131,132,133,134,135],"grid","grid-cols-1","md:grid-cols-5","gap-3","items-center",[128,137,143,156,160],{"className":138},[139,140,141,142],"md:col-span-2","flex","flex-col","gap-2",[128,144,155],{"className":145},[146,147,148,149,150,151,152,153,154],"rounded-lg","border","border-default","bg-elevated","px-3","py-2","text-sm","text-center","text-default","Anthropic",[128,157,159],{"className":158},[146,147,148,149,150,151,152,153,154],"OpenAI",[128,161,163],{"className":162},[146,147,148,149,150,151,152,153,154],"Local \u002F OSS",[128,165,169],{"className":166},[167,140,168],"md:col-span-1","justify-center",[128,170,181,182,185],{"className":171,"style":180},[172,173,174,149,175,176,153,177,178,179],"rounded-md","border-2","border-primary","px-2","py-6","text-xs","font-mono","text-primary","max-width:140px;","Provider",[183,184],"br",{},"interface",[128,187,189],{"className":188},[139,140,168],[128,190,194,199],{"className":191,"style":193},[146,147,148,149,192,176,153],"px-4","max-width:260px;",[128,195,198],{"className":196},[154,197],"font-semibold","harness",[128,200,204,205,207],{"className":201},[177,202,203],"text-muted","mt-1","loop \u002F tools \u002F context",[183,206],{},"unchanged",[128,209,213],{"className":210},[211,212],"mt-4","overflow-x-auto",[214,215,218,249],"table",{"className":216},[217,177,147,148],"w-full",[219,220,222],"thead",{"className":221},[149],[223,224,225,232,237,241,245],"tr",{},[226,227,231],"th",{"className":228},[175,229,230,202,178],"py-1","text-left","provider",[226,233,236],{"className":234},[175,229,235,202,178],"text-right","tokens",[226,238,240],{"className":239},[175,229,235,202,178],"iterations",[226,242,244],{"className":243},[175,229,235,202,178],"compactions",[226,246,248],{"className":247},[175,229,235,202,178],"seconds",[250,251,253,277,298],"tbody",{"className":252},[154],[223,254,257,261,265,269,273],{"className":255},[256,148],"border-t",[258,259,155],"td",{"className":260},[175,229,178],[258,262,264],{"className":263},[175,229,235],"6,412",[258,266,268],{"className":267},[175,229,235],"4",[258,270,272],{"className":271},[175,229,235],"0",[258,274,276],{"className":275},[175,229,235],"7.1",[223,278,280,283,287,291,294],{"className":279},[256,148],[258,281,159],{"className":282},[175,229,178],[258,284,286],{"className":285},[175,229,235],"6,980",[258,288,290],{"className":289},[175,229,235],"5",[258,292,272],{"className":293},[175,229,235],[258,295,297],{"className":296},[175,229,235],"8.4",[223,299,301,305,309,313,317],{"className":300},[256,148],[258,302,304],{"className":303},[175,229,178],"Local",[258,306,308],{"className":307},[175,229,235],"9,108",[258,310,312],{"className":311},[175,229,235],"6",[258,314,316],{"className":315},[175,229,235],"1",[258,318,320],{"className":319},[175,229,235],"22.3",[322,323,327],"figcaption",{"className":324},[177,202,325,153,326],"mt-3","italic","Three providers, one Provider interface, one harness. Same code runs against each; the numbers shift, the shape doesn't.",[329,330],"hr",{},[332,333,335],"h2",{"id":334},"_221-running-against-three-providers","22.1 Running Against Three Providers",[112,337,338,339,342,343,346,347,350,351,354],{},"The commitment from Chapter 1, tested. Provider-agnostic means the core harness — loop, tools, registry, context engineering — works unchanged against any ",[340,341,181],"code",{},". The ",[340,344,345],{},"AnthropicProvider",", ",[340,348,349],{},"OpenAIProvider",", and ",[340,352,353],{},"LocalProvider"," are the three we built. Let's run the same example against each and observe.",[356,357,362],"pre",{"className":358,"code":359,"language":360,"meta":361,"style":361},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","# examples\u002Fch22_multi_provider.py\nimport asyncio\nimport os\nimport time\nfrom pathlib import Path\n\nfrom harness.agent import arun\nfrom harness.context.accountant import ContextAccountant\nfrom harness.context.compactor import Compactor\nfrom harness.observability.tracing import setup_tracing\nfrom harness.providers.anthropic import AnthropicProvider\nfrom harness.providers.openai import OpenAIProvider\nfrom harness.providers.local import LocalProvider\nfrom harness.tools.scratchpad import Scratchpad\nfrom harness.tools.selector import ToolCatalog\nfrom harness.tools.std import STANDARD_TOOLS\n\n\nTASK = (\n    \"Read the file \u002Fetc\u002Fhostname. Using the calculator, compute the length \"\n    \"of its contents squared. Write the result to \u002Ftmp\u002Fhostname-square.txt. \"\n    \"Report: the hostname, its length, the square, and the path you wrote.\"\n)\n\n\nasync def run_with(provider) -> dict:\n    pad = Scratchpad(root=Path(f\".scratchpad-{provider.name}\"))\n    catalog = ToolCatalog(tools=STANDARD_TOOLS + pad.as_tools())\n    accountant = ContextAccountant()\n    compactor = Compactor(accountant, provider)\n\n    tool_call_count = 0\n    compaction_count = 0\n\n    def on_snapshot(snap):\n        nonlocal compaction_count\n        if snap.state == \"red\":\n            compaction_count += 1\n\n    start = time.time()\n    result = await arun(\n        provider=provider,\n        catalog=catalog,\n        user_message=TASK,\n        accountant=accountant,\n        compactor=compactor,\n        on_snapshot=on_snapshot,\n    )\n    return {\n        \"provider\": provider.name,\n        \"duration_s\": round(time.time() - start, 2),\n        \"tokens_used\": result.tokens_used,\n        \"iterations_used\": result.iterations_used,\n        \"compactions\": compaction_count,\n        \"summary\": result.summary,\n    }\n\n\nasync def main() -> None:\n    setup_tracing()  # Ch 18 — spans per provider go through the same exporter\n\n    providers = [AnthropicProvider(), OpenAIProvider()]\n    if os.environ.get(\"LOCAL_ENDPOINT\"):\n        providers.append(LocalProvider(base_url=os.environ[\"LOCAL_ENDPOINT\"]))\n\n    results = await asyncio.gather(*(run_with(p) for p in providers))\n\n    # Comparison table — this is the adapter-seam payoff.\n    print(f\"\\n{'provider':\u003C12}  {'tokens':>8}  {'iters':>6}  {'compact':>8}  {'sec':>6}\")\n    for r in results:\n        print(f\"{r['provider']:\u003C12}  {r['tokens_used']:>8}  \"\n              f\"{r['iterations_used']:>6}  {r['compactions']:>8}  \"\n              f\"{r['duration_s']:>6}\")\n\n    for r in results:\n        print(f\"\\n=== {r['provider']} ===\")\n        print(r[\"summary\"])\n\n\nasyncio.run(main())\n","python","",[340,363,364,373,384,392,400,414,421,441,463,484,506,528,549,570,592,613,635,640,645,658,672,682,692,698,703,708,741,794,829,843,867,872,883,893,898,915,924,951,963,968,986,1003,1016,1029,1041,1053,1066,1079,1085,1094,1115,1155,1176,1196,1212,1232,1238,1243,1248,1268,1279,1284,1306,1336,1377,1382,1430,1435,1441,1528,1544,1597,1643,1672,1677,1690,1727,1747,1752,1757],{"__ignoreMap":361},[365,366,369],"span",{"class":367,"line":368},"line",1,[365,370,372],{"class":371},"sutJx","# examples\u002Fch22_multi_provider.py\n",[365,374,376,380],{"class":367,"line":375},2,[365,377,379],{"class":378},"sVHd0","import",[365,381,383],{"class":382},"su5hD"," asyncio\n",[365,385,387,389],{"class":367,"line":386},3,[365,388,379],{"class":378},[365,390,391],{"class":382}," os\n",[365,393,395,397],{"class":367,"line":394},4,[365,396,379],{"class":378},[365,398,399],{"class":382}," time\n",[365,401,403,406,409,411],{"class":367,"line":402},5,[365,404,405],{"class":378},"from",[365,407,408],{"class":382}," pathlib ",[365,410,379],{"class":378},[365,412,413],{"class":382}," Path\n",[365,415,417],{"class":367,"line":416},6,[365,418,420],{"emptyLinePlaceholder":419},true,"\n",[365,422,424,426,429,433,436,438],{"class":367,"line":423},7,[365,425,405],{"class":378},[365,427,428],{"class":382}," harness",[365,430,432],{"class":431},"sP7_E",".",[365,434,435],{"class":382},"agent ",[365,437,379],{"class":378},[365,439,440],{"class":382}," arun\n",[365,442,444,446,448,450,453,455,458,460],{"class":367,"line":443},8,[365,445,405],{"class":378},[365,447,428],{"class":382},[365,449,432],{"class":431},[365,451,452],{"class":382},"context",[365,454,432],{"class":431},[365,456,457],{"class":382},"accountant ",[365,459,379],{"class":378},[365,461,462],{"class":382}," ContextAccountant\n",[365,464,466,468,470,472,474,476,479,481],{"class":367,"line":465},9,[365,467,405],{"class":378},[365,469,428],{"class":382},[365,471,432],{"class":431},[365,473,452],{"class":382},[365,475,432],{"class":431},[365,477,478],{"class":382},"compactor ",[365,480,379],{"class":378},[365,482,483],{"class":382}," Compactor\n",[365,485,487,489,491,493,496,498,501,503],{"class":367,"line":486},10,[365,488,405],{"class":378},[365,490,428],{"class":382},[365,492,432],{"class":431},[365,494,495],{"class":382},"observability",[365,497,432],{"class":431},[365,499,500],{"class":382},"tracing ",[365,502,379],{"class":378},[365,504,505],{"class":382}," setup_tracing\n",[365,507,509,511,513,515,518,520,523,525],{"class":367,"line":508},11,[365,510,405],{"class":378},[365,512,428],{"class":382},[365,514,432],{"class":431},[365,516,517],{"class":382},"providers",[365,519,432],{"class":431},[365,521,522],{"class":382},"anthropic ",[365,524,379],{"class":378},[365,526,527],{"class":382}," AnthropicProvider\n",[365,529,531,533,535,537,539,541,544,546],{"class":367,"line":530},12,[365,532,405],{"class":378},[365,534,428],{"class":382},[365,536,432],{"class":431},[365,538,517],{"class":382},[365,540,432],{"class":431},[365,542,543],{"class":382},"openai ",[365,545,379],{"class":378},[365,547,548],{"class":382}," OpenAIProvider\n",[365,550,552,554,556,558,560,562,565,567],{"class":367,"line":551},13,[365,553,405],{"class":378},[365,555,428],{"class":382},[365,557,432],{"class":431},[365,559,517],{"class":382},[365,561,432],{"class":431},[365,563,564],{"class":382},"local ",[365,566,379],{"class":378},[365,568,569],{"class":382}," LocalProvider\n",[365,571,573,575,577,579,582,584,587,589],{"class":367,"line":572},14,[365,574,405],{"class":378},[365,576,428],{"class":382},[365,578,432],{"class":431},[365,580,581],{"class":382},"tools",[365,583,432],{"class":431},[365,585,586],{"class":382},"scratchpad ",[365,588,379],{"class":378},[365,590,591],{"class":382}," Scratchpad\n",[365,593,595,597,599,601,603,605,608,610],{"class":367,"line":594},15,[365,596,405],{"class":378},[365,598,428],{"class":382},[365,600,432],{"class":431},[365,602,581],{"class":382},[365,604,432],{"class":431},[365,606,607],{"class":382},"selector ",[365,609,379],{"class":378},[365,611,612],{"class":382}," ToolCatalog\n",[365,614,616,618,620,622,624,626,629,631],{"class":367,"line":615},16,[365,617,405],{"class":378},[365,619,428],{"class":382},[365,621,432],{"class":431},[365,623,581],{"class":382},[365,625,432],{"class":431},[365,627,628],{"class":382},"std ",[365,630,379],{"class":378},[365,632,634],{"class":633},"s_hVV"," STANDARD_TOOLS\n",[365,636,638],{"class":367,"line":637},17,[365,639,420],{"emptyLinePlaceholder":419},[365,641,643],{"class":367,"line":642},18,[365,644,420],{"emptyLinePlaceholder":419},[365,646,648,651,655],{"class":367,"line":647},19,[365,649,650],{"class":633},"TASK",[365,652,654],{"class":653},"smGrS"," =",[365,656,657],{"class":431}," (\n",[365,659,661,665,669],{"class":367,"line":660},20,[365,662,664],{"class":663},"sjJ54","    \"",[365,666,668],{"class":667},"s_sjI","Read the file \u002Fetc\u002Fhostname. Using the calculator, compute the length ",[365,670,671],{"class":663},"\"\n",[365,673,675,677,680],{"class":367,"line":674},21,[365,676,664],{"class":663},[365,678,679],{"class":667},"of its contents squared. Write the result to \u002Ftmp\u002Fhostname-square.txt. ",[365,681,671],{"class":663},[365,683,685,687,690],{"class":367,"line":684},22,[365,686,664],{"class":663},[365,688,689],{"class":667},"Report: the hostname, its length, the square, and the path you wrote.",[365,691,671],{"class":663},[365,693,695],{"class":367,"line":694},23,[365,696,697],{"class":431},")\n",[365,699,701],{"class":367,"line":700},24,[365,702,420],{"emptyLinePlaceholder":419},[365,704,706],{"class":367,"line":705},25,[365,707,420],{"emptyLinePlaceholder":419},[365,709,711,715,718,722,725,728,731,734,738],{"class":367,"line":710},26,[365,712,714],{"class":713},"sbsja","async",[365,716,717],{"class":713}," def",[365,719,721],{"class":720},"sGLFI"," run_with",[365,723,724],{"class":431},"(",[365,726,231],{"class":727},"sFwrP",[365,729,730],{"class":431},")",[365,732,733],{"class":431}," ->",[365,735,737],{"class":736},"sZMiF"," dict",[365,739,740],{"class":431},":\n",[365,742,744,747,750,754,756,760,762,765,767,770,773,777,779,781,785,788,791],{"class":367,"line":743},27,[365,745,746],{"class":382},"    pad ",[365,748,749],{"class":653},"=",[365,751,753],{"class":752},"slqww"," Scratchpad",[365,755,724],{"class":431},[365,757,759],{"class":758},"s99_P","root",[365,761,749],{"class":653},[365,763,764],{"class":752},"Path",[365,766,724],{"class":431},[365,768,769],{"class":713},"f",[365,771,772],{"class":667},"\".scratchpad-",[365,774,776],{"class":775},"srdBf","{",[365,778,231],{"class":752},[365,780,432],{"class":431},[365,782,784],{"class":783},"skxfh","name",[365,786,787],{"class":775},"}",[365,789,790],{"class":667},"\"",[365,792,793],{"class":431},"))\n",[365,795,797,800,802,805,807,809,811,815,818,821,823,826],{"class":367,"line":796},28,[365,798,799],{"class":382},"    catalog ",[365,801,749],{"class":653},[365,803,804],{"class":752}," ToolCatalog",[365,806,724],{"class":431},[365,808,581],{"class":758},[365,810,749],{"class":653},[365,812,814],{"class":813},"sptTA","STANDARD_TOOLS",[365,816,817],{"class":653}," +",[365,819,820],{"class":752}," pad",[365,822,432],{"class":431},[365,824,825],{"class":752},"as_tools",[365,827,828],{"class":431},"())\n",[365,830,832,835,837,840],{"class":367,"line":831},29,[365,833,834],{"class":382},"    accountant ",[365,836,749],{"class":653},[365,838,839],{"class":752}," ContextAccountant",[365,841,842],{"class":431},"()\n",[365,844,846,849,851,854,856,859,862,865],{"class":367,"line":845},30,[365,847,848],{"class":382},"    compactor ",[365,850,749],{"class":653},[365,852,853],{"class":752}," Compactor",[365,855,724],{"class":431},[365,857,858],{"class":752},"accountant",[365,860,861],{"class":431},",",[365,863,864],{"class":752}," provider",[365,866,697],{"class":431},[365,868,870],{"class":367,"line":869},31,[365,871,420],{"emptyLinePlaceholder":419},[365,873,875,878,880],{"class":367,"line":874},32,[365,876,877],{"class":382},"    tool_call_count ",[365,879,749],{"class":653},[365,881,882],{"class":775}," 0\n",[365,884,886,889,891],{"class":367,"line":885},33,[365,887,888],{"class":382},"    compaction_count ",[365,890,749],{"class":653},[365,892,882],{"class":775},[365,894,896],{"class":367,"line":895},34,[365,897,420],{"emptyLinePlaceholder":419},[365,899,901,904,907,909,912],{"class":367,"line":900},35,[365,902,903],{"class":713},"    def",[365,905,906],{"class":720}," on_snapshot",[365,908,724],{"class":431},[365,910,911],{"class":727},"snap",[365,913,914],{"class":431},"):\n",[365,916,918,921],{"class":367,"line":917},36,[365,919,920],{"class":713},"        nonlocal",[365,922,923],{"class":382}," compaction_count\n",[365,925,927,930,933,935,938,941,944,947,949],{"class":367,"line":926},37,[365,928,929],{"class":378},"        if",[365,931,932],{"class":382}," snap",[365,934,432],{"class":431},[365,936,937],{"class":783},"state",[365,939,940],{"class":653}," ==",[365,942,943],{"class":663}," \"",[365,945,946],{"class":667},"red",[365,948,790],{"class":663},[365,950,740],{"class":431},[365,952,954,957,960],{"class":367,"line":953},38,[365,955,956],{"class":382},"            compaction_count ",[365,958,959],{"class":653},"+=",[365,961,962],{"class":775}," 1\n",[365,964,966],{"class":367,"line":965},39,[365,967,420],{"emptyLinePlaceholder":419},[365,969,971,974,976,979,981,984],{"class":367,"line":970},40,[365,972,973],{"class":382},"    start ",[365,975,749],{"class":653},[365,977,978],{"class":382}," time",[365,980,432],{"class":431},[365,982,983],{"class":752},"time",[365,985,842],{"class":431},[365,987,989,992,994,997,1000],{"class":367,"line":988},41,[365,990,991],{"class":382},"    result ",[365,993,749],{"class":653},[365,995,996],{"class":378}," await",[365,998,999],{"class":752}," arun",[365,1001,1002],{"class":431},"(\n",[365,1004,1006,1009,1011,1013],{"class":367,"line":1005},42,[365,1007,1008],{"class":758},"        provider",[365,1010,749],{"class":653},[365,1012,231],{"class":752},[365,1014,1015],{"class":431},",\n",[365,1017,1019,1022,1024,1027],{"class":367,"line":1018},43,[365,1020,1021],{"class":758},"        catalog",[365,1023,749],{"class":653},[365,1025,1026],{"class":752},"catalog",[365,1028,1015],{"class":431},[365,1030,1032,1035,1037,1039],{"class":367,"line":1031},44,[365,1033,1034],{"class":758},"        user_message",[365,1036,749],{"class":653},[365,1038,650],{"class":813},[365,1040,1015],{"class":431},[365,1042,1044,1047,1049,1051],{"class":367,"line":1043},45,[365,1045,1046],{"class":758},"        accountant",[365,1048,749],{"class":653},[365,1050,858],{"class":752},[365,1052,1015],{"class":431},[365,1054,1056,1059,1061,1064],{"class":367,"line":1055},46,[365,1057,1058],{"class":758},"        compactor",[365,1060,749],{"class":653},[365,1062,1063],{"class":752},"compactor",[365,1065,1015],{"class":431},[365,1067,1069,1072,1074,1077],{"class":367,"line":1068},47,[365,1070,1071],{"class":758},"        on_snapshot",[365,1073,749],{"class":653},[365,1075,1076],{"class":752},"on_snapshot",[365,1078,1015],{"class":431},[365,1080,1082],{"class":367,"line":1081},48,[365,1083,1084],{"class":431},"    )\n",[365,1086,1088,1091],{"class":367,"line":1087},49,[365,1089,1090],{"class":378},"    return",[365,1092,1093],{"class":431}," {\n",[365,1095,1097,1100,1102,1104,1107,1109,1111,1113],{"class":367,"line":1096},50,[365,1098,1099],{"class":663},"        \"",[365,1101,231],{"class":667},[365,1103,790],{"class":663},[365,1105,1106],{"class":431},":",[365,1108,864],{"class":382},[365,1110,432],{"class":431},[365,1112,784],{"class":783},[365,1114,1015],{"class":431},[365,1116,1118,1120,1123,1125,1127,1130,1132,1134,1136,1138,1141,1144,1147,1149,1152],{"class":367,"line":1117},51,[365,1119,1099],{"class":663},[365,1121,1122],{"class":667},"duration_s",[365,1124,790],{"class":663},[365,1126,1106],{"class":431},[365,1128,1129],{"class":813}," round",[365,1131,724],{"class":431},[365,1133,983],{"class":752},[365,1135,432],{"class":431},[365,1137,983],{"class":752},[365,1139,1140],{"class":431},"()",[365,1142,1143],{"class":653}," -",[365,1145,1146],{"class":752}," start",[365,1148,861],{"class":431},[365,1150,1151],{"class":775}," 2",[365,1153,1154],{"class":431},"),\n",[365,1156,1158,1160,1163,1165,1167,1170,1172,1174],{"class":367,"line":1157},52,[365,1159,1099],{"class":663},[365,1161,1162],{"class":667},"tokens_used",[365,1164,790],{"class":663},[365,1166,1106],{"class":431},[365,1168,1169],{"class":382}," result",[365,1171,432],{"class":431},[365,1173,1162],{"class":783},[365,1175,1015],{"class":431},[365,1177,1179,1181,1184,1186,1188,1190,1192,1194],{"class":367,"line":1178},53,[365,1180,1099],{"class":663},[365,1182,1183],{"class":667},"iterations_used",[365,1185,790],{"class":663},[365,1187,1106],{"class":431},[365,1189,1169],{"class":382},[365,1191,432],{"class":431},[365,1193,1183],{"class":783},[365,1195,1015],{"class":431},[365,1197,1199,1201,1203,1205,1207,1210],{"class":367,"line":1198},54,[365,1200,1099],{"class":663},[365,1202,244],{"class":667},[365,1204,790],{"class":663},[365,1206,1106],{"class":431},[365,1208,1209],{"class":382}," compaction_count",[365,1211,1015],{"class":431},[365,1213,1215,1217,1220,1222,1224,1226,1228,1230],{"class":367,"line":1214},55,[365,1216,1099],{"class":663},[365,1218,1219],{"class":667},"summary",[365,1221,790],{"class":663},[365,1223,1106],{"class":431},[365,1225,1169],{"class":382},[365,1227,432],{"class":431},[365,1229,1219],{"class":783},[365,1231,1015],{"class":431},[365,1233,1235],{"class":367,"line":1234},56,[365,1236,1237],{"class":431},"    }\n",[365,1239,1241],{"class":367,"line":1240},57,[365,1242,420],{"emptyLinePlaceholder":419},[365,1244,1246],{"class":367,"line":1245},58,[365,1247,420],{"emptyLinePlaceholder":419},[365,1249,1251,1253,1255,1258,1260,1262,1266],{"class":367,"line":1250},59,[365,1252,714],{"class":713},[365,1254,717],{"class":713},[365,1256,1257],{"class":720}," main",[365,1259,1140],{"class":431},[365,1261,733],{"class":431},[365,1263,1265],{"class":1264},"s39Yj"," None",[365,1267,740],{"class":431},[365,1269,1271,1274,1276],{"class":367,"line":1270},60,[365,1272,1273],{"class":752},"    setup_tracing",[365,1275,1140],{"class":431},[365,1277,1278],{"class":371},"  # Ch 18 — spans per provider go through the same exporter\n",[365,1280,1282],{"class":367,"line":1281},61,[365,1283,420],{"emptyLinePlaceholder":419},[365,1285,1287,1290,1292,1295,1297,1300,1303],{"class":367,"line":1286},62,[365,1288,1289],{"class":382},"    providers ",[365,1291,749],{"class":653},[365,1293,1294],{"class":431}," [",[365,1296,345],{"class":752},[365,1298,1299],{"class":431},"(),",[365,1301,1302],{"class":752}," OpenAIProvider",[365,1304,1305],{"class":431},"()]\n",[365,1307,1309,1312,1315,1317,1320,1322,1325,1327,1329,1332,1334],{"class":367,"line":1308},63,[365,1310,1311],{"class":378},"    if",[365,1313,1314],{"class":382}," os",[365,1316,432],{"class":431},[365,1318,1319],{"class":783},"environ",[365,1321,432],{"class":431},[365,1323,1324],{"class":752},"get",[365,1326,724],{"class":431},[365,1328,790],{"class":663},[365,1330,1331],{"class":667},"LOCAL_ENDPOINT",[365,1333,790],{"class":663},[365,1335,914],{"class":431},[365,1337,1339,1342,1344,1347,1349,1351,1353,1356,1358,1361,1363,1365,1368,1370,1372,1374],{"class":367,"line":1338},64,[365,1340,1341],{"class":382},"        providers",[365,1343,432],{"class":431},[365,1345,1346],{"class":752},"append",[365,1348,724],{"class":431},[365,1350,353],{"class":752},[365,1352,724],{"class":431},[365,1354,1355],{"class":758},"base_url",[365,1357,749],{"class":653},[365,1359,1360],{"class":752},"os",[365,1362,432],{"class":431},[365,1364,1319],{"class":783},[365,1366,1367],{"class":431},"[",[365,1369,790],{"class":663},[365,1371,1331],{"class":667},[365,1373,790],{"class":663},[365,1375,1376],{"class":431},"]))\n",[365,1378,1380],{"class":367,"line":1379},65,[365,1381,420],{"emptyLinePlaceholder":419},[365,1383,1385,1388,1390,1392,1395,1397,1400,1402,1405,1407,1410,1412,1414,1416,1419,1422,1425,1428],{"class":367,"line":1384},66,[365,1386,1387],{"class":382},"    results ",[365,1389,749],{"class":653},[365,1391,996],{"class":378},[365,1393,1394],{"class":382}," asyncio",[365,1396,432],{"class":431},[365,1398,1399],{"class":752},"gather",[365,1401,724],{"class":431},[365,1403,1404],{"class":653},"*",[365,1406,724],{"class":431},[365,1408,1409],{"class":752},"run_with",[365,1411,724],{"class":431},[365,1413,112],{"class":752},[365,1415,730],{"class":431},[365,1417,1418],{"class":378}," for",[365,1420,1421],{"class":752}," p ",[365,1423,1424],{"class":378},"in",[365,1426,1427],{"class":752}," providers",[365,1429,793],{"class":431},[365,1431,1433],{"class":367,"line":1432},67,[365,1434,420],{"emptyLinePlaceholder":419},[365,1436,1438],{"class":367,"line":1437},68,[365,1439,1440],{"class":371},"    # Comparison table — this is the adapter-seam payoff.\n",[365,1442,1444,1447,1449,1451,1453,1456,1458,1461,1463,1465,1468,1470,1473,1475,1477,1479,1482,1484,1486,1488,1491,1493,1496,1498,1500,1502,1505,1507,1509,1511,1513,1515,1518,1520,1522,1524,1526],{"class":367,"line":1443},69,[365,1445,1446],{"class":813},"    print",[365,1448,724],{"class":431},[365,1450,769],{"class":713},[365,1452,790],{"class":667},[365,1454,1455],{"class":633},"\\n",[365,1457,776],{"class":775},[365,1459,1460],{"class":663},"'",[365,1462,231],{"class":667},[365,1464,1460],{"class":663},[365,1466,1467],{"class":713},":\u003C12",[365,1469,787],{"class":775},[365,1471,1472],{"class":775},"  {",[365,1474,1460],{"class":663},[365,1476,236],{"class":667},[365,1478,1460],{"class":663},[365,1480,1481],{"class":713},":>8",[365,1483,787],{"class":775},[365,1485,1472],{"class":775},[365,1487,1460],{"class":663},[365,1489,1490],{"class":667},"iters",[365,1492,1460],{"class":663},[365,1494,1495],{"class":713},":>6",[365,1497,787],{"class":775},[365,1499,1472],{"class":775},[365,1501,1460],{"class":663},[365,1503,1504],{"class":667},"compact",[365,1506,1460],{"class":663},[365,1508,1481],{"class":713},[365,1510,787],{"class":775},[365,1512,1472],{"class":775},[365,1514,1460],{"class":663},[365,1516,1517],{"class":667},"sec",[365,1519,1460],{"class":663},[365,1521,1495],{"class":713},[365,1523,787],{"class":775},[365,1525,790],{"class":667},[365,1527,697],{"class":431},[365,1529,1531,1534,1537,1539,1542],{"class":367,"line":1530},70,[365,1532,1533],{"class":378},"    for",[365,1535,1536],{"class":382}," r ",[365,1538,1424],{"class":378},[365,1540,1541],{"class":382}," results",[365,1543,740],{"class":431},[365,1545,1547,1550,1552,1554,1556,1558,1561,1563,1565,1567,1569,1572,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594],{"class":367,"line":1546},71,[365,1548,1549],{"class":813},"        print",[365,1551,724],{"class":431},[365,1553,769],{"class":713},[365,1555,790],{"class":667},[365,1557,776],{"class":775},[365,1559,1560],{"class":752},"r",[365,1562,1367],{"class":431},[365,1564,1460],{"class":663},[365,1566,231],{"class":667},[365,1568,1460],{"class":663},[365,1570,1571],{"class":431},"]",[365,1573,1467],{"class":713},[365,1575,787],{"class":775},[365,1577,1472],{"class":775},[365,1579,1560],{"class":752},[365,1581,1367],{"class":431},[365,1583,1460],{"class":663},[365,1585,1162],{"class":667},[365,1587,1460],{"class":663},[365,1589,1571],{"class":431},[365,1591,1481],{"class":713},[365,1593,787],{"class":775},[365,1595,1596],{"class":667},"  \"\n",[365,1598,1600,1603,1605,1607,1609,1611,1613,1615,1617,1619,1621,1623,1625,1627,1629,1631,1633,1635,1637,1639,1641],{"class":367,"line":1599},72,[365,1601,1602],{"class":713},"              f",[365,1604,790],{"class":667},[365,1606,776],{"class":775},[365,1608,1560],{"class":752},[365,1610,1367],{"class":431},[365,1612,1460],{"class":663},[365,1614,1183],{"class":667},[365,1616,1460],{"class":663},[365,1618,1571],{"class":431},[365,1620,1495],{"class":713},[365,1622,787],{"class":775},[365,1624,1472],{"class":775},[365,1626,1560],{"class":752},[365,1628,1367],{"class":431},[365,1630,1460],{"class":663},[365,1632,244],{"class":667},[365,1634,1460],{"class":663},[365,1636,1571],{"class":431},[365,1638,1481],{"class":713},[365,1640,787],{"class":775},[365,1642,1596],{"class":667},[365,1644,1646,1648,1650,1652,1654,1656,1658,1660,1662,1664,1666,1668,1670],{"class":367,"line":1645},73,[365,1647,1602],{"class":713},[365,1649,790],{"class":667},[365,1651,776],{"class":775},[365,1653,1560],{"class":752},[365,1655,1367],{"class":431},[365,1657,1460],{"class":663},[365,1659,1122],{"class":667},[365,1661,1460],{"class":663},[365,1663,1571],{"class":431},[365,1665,1495],{"class":713},[365,1667,787],{"class":775},[365,1669,790],{"class":667},[365,1671,697],{"class":431},[365,1673,1675],{"class":367,"line":1674},74,[365,1676,420],{"emptyLinePlaceholder":419},[365,1678,1680,1682,1684,1686,1688],{"class":367,"line":1679},75,[365,1681,1533],{"class":378},[365,1683,1536],{"class":382},[365,1685,1424],{"class":378},[365,1687,1541],{"class":382},[365,1689,740],{"class":431},[365,1691,1693,1695,1697,1699,1701,1703,1706,1708,1710,1712,1714,1716,1718,1720,1722,1725],{"class":367,"line":1692},76,[365,1694,1549],{"class":813},[365,1696,724],{"class":431},[365,1698,769],{"class":713},[365,1700,790],{"class":667},[365,1702,1455],{"class":633},[365,1704,1705],{"class":667},"=== ",[365,1707,776],{"class":775},[365,1709,1560],{"class":752},[365,1711,1367],{"class":431},[365,1713,1460],{"class":663},[365,1715,231],{"class":667},[365,1717,1460],{"class":663},[365,1719,1571],{"class":431},[365,1721,787],{"class":775},[365,1723,1724],{"class":667}," ===\"",[365,1726,697],{"class":431},[365,1728,1730,1732,1734,1736,1738,1740,1742,1744],{"class":367,"line":1729},77,[365,1731,1549],{"class":813},[365,1733,724],{"class":431},[365,1735,1560],{"class":752},[365,1737,1367],{"class":431},[365,1739,790],{"class":663},[365,1741,1219],{"class":667},[365,1743,790],{"class":663},[365,1745,1746],{"class":431},"])\n",[365,1748,1750],{"class":367,"line":1749},78,[365,1751,420],{"emptyLinePlaceholder":419},[365,1753,1755],{"class":367,"line":1754},79,[365,1756,420],{"emptyLinePlaceholder":419},[365,1758,1760,1763,1765,1768,1770,1773],{"class":367,"line":1759},80,[365,1761,1762],{"class":382},"asyncio",[365,1764,432],{"class":431},[365,1766,1767],{"class":752},"run",[365,1769,724],{"class":431},[365,1771,1772],{"class":752},"main",[365,1774,828],{"class":431},[112,1776,1777],{},"The same code, three providers. Three sets of output, plus a comparison table that makes the delta visible: tokens used, iterations taken, compactions triggered, wall-clock time. The hostname is the same across all three (deterministic tool); the phrasing varies with model style; the iteration count varies with how the model chose to decompose the task. The harness doesn't change — the numbers tell you how each provider drives it.",[112,1779,1780,1784],{},[1781,1782,1783],"strong",{},"This is the claim of the book, made operational."," Your agent logic, your tools, your context strategy, your evals — all reusable across providers. A model deprecation (they will happen), a price change (they will happen), a capability gap in a specific vendor (they will happen) — none of these force a rewrite of the agent. They force a configuration change.",[329,1786],{},[332,1788,1790],{"id":1789},"_222-what-the-harness-does-not-do","22.2 What The Harness Does Not Do",[112,1792,1793],{},"Honest list. Every one of these is a place a real production deployment might extend, and every one is a small to medium project on top of what we built — not a rewrite.",[112,1795,1796,1799],{},[1781,1797,1798],{},"No fine-tuning support."," Toolformer showed that tool-use behavior is learnable; we assume a capable RLHF-trained frontier model and don't try to improve it. If your tools are novel enough that the model misuses them systematically, fine-tuning is an option worth knowing about.",[112,1801,1802,1805],{},[1781,1803,1804],{},"No tree search \u002F best-of-N."," Tree of Thoughts, Self-Refine, Reflexion — all patterns where the harness generates multiple candidates and scores them. Useful for verifiable-answer tasks (code, math). Not in our harness; adding it is one chapter of work at the loop level.",[112,1807,1808,1811,1812,1815],{},[1781,1809,1810],{},"No embedding-based retrieval."," BM25 is our baseline. Swapping ",[340,1813,1814],{},"DocumentIndex"," for an embedding-backed version is a drop-in upgrade; we named the interface so it would be. When you cross paraphrase-heavy use cases, do it.",[112,1817,1818,1821,1822,1825],{},[1781,1819,1820],{},"No genuine Firecracker\u002FgVisor sandbox."," We defined the ",[340,1823,1824],{},"ToolSandbox"," interface (Chapter 14); we ship a subprocess-with-allowlist implementation. Production deployments hand this to E2B, Modal, or a self-hosted Firecracker setup.",[112,1827,1828,1831],{},[1781,1829,1830],{},"No first-class voice or multimodal support."," Text-only input and output. MCP has resource types for images; we didn't plumb them through. Add-on project.",[112,1833,1834,1837],{},[1781,1835,1836],{},"No UI."," CLI streaming works; there's no built-in TUI, web UI, or IDE extension. That's application-level work; the harness is a library.",[112,1839,1840,1843,1844,1847],{},[1781,1841,1842],{},"No team deployment."," Single-user assumed throughout. Multi-tenant deployments need per-user isolation, quota management, authentication — all of which the ",[340,1845,1846],{},"session_id"," threading already supports but which the book didn't formalize.",[112,1849,1850,1853,1854,1857],{},[1781,1851,1852],{},"No learned routing."," Chapter 20's ",[340,1855,1856],{},"ModelRouter"," is rules-based. Production routing often uses a learned classifier; the research on this is improving but not yet packaged. Worth watching.",[112,1859,1860],{},"Every one of these is a deliberate stop. The book's goal was a harness you understand end-to-end, not a harness that does everything.",[329,1862],{},[332,1864,1866],{"id":1865},"_223-the-danger-list-revisited","22.3 The Danger List, Revisited",[112,1868,1869],{},"The failure-mode literature we surveyed at the start of this book catalogued twenty-eight distinct failure modes — the danger list reproduced in the book's Research Brief 4 (Failure Mode Catalog). Look back at the cross-reference table: every one is addressed in this harness.",[112,1871,1872],{},"The Chapter 2 five-break itinerary was the narrow version. The twenty-eight-entry failure catalog was the exhaustive one. Between them, they gave every design decision in this book a specific motivation — a place in a real production post-mortem where someone wishes they'd had this exact thing. If any of your design choices don't trace back to one of those entries, it's worth asking whether they're earning their place.",[329,1874],{},[332,1876,1878],{"id":1877},"_224-a-scorecard-for-the-next-framework","22.4 A Scorecard for the Next Framework",[112,1880,1881],{},"A framework will ship tomorrow that claims to supersede LangGraph or the Agents SDK or Claude Code. The vocabulary of this book is what lets you evaluate it honestly. A scorecard, in the form of questions I ask:",[112,1883,1884],{},[1781,1885,1886],{},"On the loop.",[1888,1889,1890,1894,1897],"ul",{},[1891,1892,1893],"li",{},"What triggers the loop to stop — a tool-call-absent response, a final tool, an iteration cap, something else?",[1891,1895,1896],{},"Is the loop pluggable (can I insert a compaction step, an observability hook) or is it opaque?",[1891,1898,1899],{},"Can I see how long the loop is? Under 500 lines is a good sign.",[112,1901,1902],{},[1781,1903,1904],{},"On messages and transcripts.",[1888,1906,1907,1910,1913],{},[1891,1908,1909],{},"Are messages typed or dicts?",[1891,1911,1912],{},"Is the transcript a first-class object with its own accounting?",[1891,1914,1915],{},"How does the framework handle provider differences in message shape? Adapters? Coupling?",[112,1917,1918],{},[1781,1919,1920],{},"On tools.",[1888,1922,1923,1926,1929,1932],{},[1891,1924,1925],{},"Are tool schemas inferred from types or hand-written?",[1891,1927,1928],{},"Is there a registry with pre-dispatch validation?",[1891,1930,1931],{},"Is loop detection built in or my problem?",[1891,1933,1934],{},"How does the framework handle more than 20 tools?",[112,1936,1937],{},[1781,1938,1939],{},"On context.",[1888,1941,1942,1945,1948],{},[1891,1943,1944],{},"Is there automatic compaction? What does it compact first — tool outputs, middle turns, everything? Is the policy configurable?",[1891,1946,1947],{},"Is the context window tracked as a budgetable resource, or is it \"the model decides\"?",[1891,1949,1950],{},"Is there a scratchpad or external state pattern built in?",[112,1952,1953],{},[1781,1954,1955],{},"On sub-agents.",[1888,1957,1958,1961,1964],{},[1891,1959,1960],{},"Does the framework enforce that sub-agent results are compact summaries rather than full transcripts?",[1891,1962,1963],{},"Is there a spawn budget and justification requirement, or can the parent spawn unbounded?",[1891,1965,1966],{},"Can sub-agents spawn sub-agents? (If yes, has the framework noticed this is usually a mistake?)",[112,1968,1969],{},[1781,1970,1971],{},"On permissions.",[1888,1973,1974,1977,1980],{},[1891,1975,1976],{},"Is there a permission layer at all?",[1891,1978,1979],{},"Is it policy-composable, or a single \"allow\u002Fdeny\" list?",[1891,1981,1982],{},"Does it handle trust-labeled outputs for indirect prompt injection?",[112,1984,1985],{},[1781,1986,1987],{},"On cost.",[1888,1989,1990,1993,1996],{},[1891,1991,1992],{},"Are hard budgets enforced in-process, out-of-process, or only via alerts?",[1891,1994,1995],{},"Is there built-in support for prompt caching?",[1891,1997,1998],{},"Can I see per-agent cost attribution?",[112,2000,2001],{},[1781,2002,2003],{},"On observability.",[1888,2005,2006,2009],{},[1891,2007,2008],{},"Does the framework emit OpenTelemetry spans, proprietary traces, or just logs?",[1891,2010,2011],{},"Can I correlate across sub-agents, tools, and LLM calls via standard IDs?",[112,2013,2014],{},[1781,2015,2016],{},"On durability.",[1888,2018,2019,2022,2025],{},[1891,2020,2021],{},"Does the framework checkpoint at all?",[1891,2023,2024],{},"Does it handle side-effecting tool idempotency, or is that my problem?",[1891,2026,2027],{},"Can I resume across processes, or only within one?",[112,2029,2030],{},[1781,2031,2032],{},"On evaluation.",[1888,2034,2035,2038],{},[1891,2036,2037],{},"Is there a regression harness?",[1891,2039,2040],{},"Can I run golden trajectories with structural checks (required tools, forbidden tools) and outcome checks?",[112,2042,2043],{},"A framework that scores well on most of these is worth adopting. A framework that scores poorly is a tool you're going to outgrow — and the book you just read is the outline of what you'll end up building yourself anyway.",[329,2045],{},[332,2047,2049],{"id":2048},"_225-what-i-wish-id-known-when-i-started","22.5 What I Wish I'd Known When I Started",[112,2051,2052],{},"A short list, written as if to a reader about to start their own harness from scratch.",[112,2054,2055,2058],{},[1781,2056,2057],{},"The model is the easy part."," You'll spend 10% of your time on model choices and 90% on everything around them. This is a surprise if you came to the space as a prompt engineer. Adjust your budget.",[112,2060,2061,2067],{},[1781,2062,2063,2064,2066],{},"Build the ",[340,2065,181],{}," abstraction on day one."," The moment your loop imports a vendor SDK directly, migration costs compound. A one-file adapter is ten minutes of work and saves months.",[112,2069,2070,2073],{},[1781,2071,2072],{},"Types beat dicts, especially for messages."," The time you save by skipping type definitions you pay back the first time you ship to a new provider and something silently shapes wrong.",[112,2075,2076,2079],{},[1781,2077,2078],{},"Context is the real fight."," You will rebuild your compactor three times. The first version is naive. The second version is complicated. The third version is principled. Skip to the third version when you can.",[112,2081,2082,2085],{},[1781,2083,2084],{},"Tool design matters more than model choice."," A mediocre model with well-designed tools beats a flagship model with sloppy tools. Spend time on tool descriptions, viewport reads, truncation envelopes.",[112,2087,2088,2091],{},[1781,2089,2090],{},"Evals are non-optional."," You will not know if a change made the harness better without them. Getting even a small suite in place pays for itself the first time someone says \"I think this got worse.\"",[112,2093,2094,2097],{},[1781,2095,2096],{},"Alerts are not enforcement."," The $47K lesson. Budget caps run in their own path or they don't run at all.",[112,2099,2100,2103],{},[1781,2101,2102],{},"Compaction can fail silently."," If your compactor loses something the agent needed, the agent won't tell you; it'll just produce wrong answers. Instrument compaction events explicitly; treat each one as a data point.",[112,2105,2106,2109],{},[1781,2107,2108],{},"Trust labels are necessary but not sufficient."," You will not solve prompt injection with clever prompting. Defense in depth: permission layer, trust labels, network allowlists, behavioral monitoring.",[112,2111,2112,2115],{},[1781,2113,2114],{},"Ship the boring version first."," The fancy version of every feature — learned routing, tree search, semantic tool selection, hybrid retrieval — comes later. The non-fancy version of each, shipped and measured, is always the right first step.",[329,2117],{},[332,2119,2121],{"id":2120},"_226-what-to-read-next","22.6 What to Read Next",[112,2123,2124],{},"Not exhaustive; curated.",[112,2126,2127,2130],{},[1781,2128,2129],{},"If you want to go deeper on context."," Anthropic's \"Effective Context Engineering for AI Agents\" (Sep 2025) is the canonical current treatment. The Chroma \"Context Rot\" study (2025) is the empirical basis for most of what Chapter 7 builds on.",[112,2132,2133,2136],{},[1781,2134,2135],{},"If you want to go deeper on multi-agent."," Anthropic's \"How We Built Our Multi-Agent Research System\" is the clearest production case study. The MAST paper (Cemri et al., 2025) is the systematic failure taxonomy.",[112,2138,2139,2142],{},[1781,2140,2141],{},"If you want to go deeper on ACI \u002F tool design."," The SWE-agent paper (Yang et al., 2024) and the mini-SWE-agent code (100 lines) together teach the complete arc: custom tools help, then models catch up, then simpler tools suffice.",[112,2144,2145,2148,2149,2152,2153,2156],{},[1781,2146,2147],{},"If you want to evaluate harnesses."," Read the ",[340,2150,2151],{},"smolagents"," source (~1000 lines). Read ",[340,2154,2155],{},"mini-swe-agent",". Skim Claude Code's public docs. You'll find the ideas in this book instantiated in each, with different tradeoffs. Recognizing those tradeoffs is the skill.",[112,2158,2159,2162],{},[1781,2160,2161],{},"If you want to stay current."," Anthropic's engineering blog. OpenAI's cookbook. The Modal and E2B blogs (for sandboxing). Simon Willison on prompt injection. Hamel Husain on evals.",[329,2164],{},[332,2166,2168],{"id":2167},"_227-the-last-commit","22.7 The Last Commit",[356,2170,2174],{"className":2171,"code":2172,"language":2173,"meta":361,"style":361},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","git add -A && git commit -m \"ch22: multi-provider demonstration and closing\"\ngit tag ch22-final\n","bash",[340,2175,2176,2208],{"__ignoreMap":361},[365,2177,2178,2182,2185,2189,2192,2195,2198,2201,2203,2206],{"class":367,"line":368},[365,2179,2181],{"class":2180},"sbgvK","git",[365,2183,2184],{"class":667}," add",[365,2186,2188],{"class":2187},"stzsN"," -A",[365,2190,2191],{"class":431}," &&",[365,2193,2194],{"class":2180}," git",[365,2196,2197],{"class":667}," commit",[365,2199,2200],{"class":2187}," -m",[365,2202,943],{"class":663},[365,2204,2205],{"class":667},"ch22: multi-provider demonstration and closing",[365,2207,671],{"class":663},[365,2209,2210,2212,2215],{"class":367,"line":375},[365,2211,2181],{"class":2180},[365,2213,2214],{"class":667}," tag",[365,2216,2217],{"class":667}," ch22-final\n",[332,2219,2221],{"id":2220},"_228-try-it-yourself","22.8 Try It Yourself",[2223,2224,2225,2231,2237],"ol",{},[1891,2226,2227,2230],{},[1781,2228,2229],{},"Score your own harness."," Take whatever agent system you currently work on — or plan to build — and run it through the scorecard from Section 22.4. Write down the gaps. Prioritize the top three.",[1891,2232,2233,2236],{},[1781,2234,2235],{},"Write the missing chapter."," Pick one of the \"what the harness doesn't do\" items from Section 22.2 and add it. Embedding-based retrieval, tree search, a fine-tuned tool model — pick one. How long does it take? Does it fit the interfaces the book established, or does it want to break them?",[1891,2238,2239,2242,2243,346,2245,2247],{},[1781,2240,2241],{},"Evaluate one more harness."," Clone ",[340,2244,2151],{},[340,2246,2155],{},", or the OpenAI Agents SDK. Read the core loop. Map it onto the vocabulary of this book. Where does it agree with the design choices we made? Where does it differ, and why?",[329,2249],{},[2251,2252,2253,2256,2259],"what-you-understand",{},[112,2254,2255],{},"You built an agent harness. All 22 chapters of it. A minimum viable loop, a provider abstraction, typed transcripts, a tool registry with validation and loop detection, streaming, interruption, retry, a context accountant, compaction, a scratchpad, retrieval, viewport tools, dynamic tool loading, MCP integration, permissions and sandboxing, sub-agents, structured plans, parallel coordination with leases, OpenTelemetry observability, an eval harness, cost control with caching and routing and hard budgets, and SQLite-backed durability. Every piece has a specific failure mode it prevents, cited from the literature catalogued in Research Brief 4. Every piece plugs into the others through seams that were established before they were needed.",[112,2257,2258],{},"More importantly: you have the vocabulary and the judgment. When the next model generation drops, you know what might transfer and what won't. When the next framework ships, you know what questions to ask. When the next postmortem lands on your desk, you know where in the system the failure lives. The machine is yours, and you built it.",[112,2260,2261],{},"The harness is not the book's hero. The reader is. Go make something.",[2263,2264,2265],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sFwrP, html code.shiki .sFwrP{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":361,"searchDepth":375,"depth":375,"links":2267},[2268,2269,2270,2271,2272,2273,2274,2275],{"id":334,"depth":375,"text":335},{"id":1789,"depth":375,"text":1790},{"id":1865,"depth":375,"text":1866},{"id":1877,"depth":375,"text":1878},{"id":2048,"depth":375,"text":2049},{"id":2120,"depth":375,"text":2121},{"id":2167,"depth":375,"text":2168},{"id":2220,"depth":375,"text":2221},"md",{},null,{"title":98,"description":117},"SPPv4u06walSWXHgnFhUFEF2fQmsiEZT9CM1QBIiU0w",[2282,2284],{"title":94,"path":95,"stem":96,"description":2283,"children":-1},"Previously: cost control. A budget-enforced harness can't run away. What it still can't do is survive a crash. The machine reboots, the process is killed, the laptop lid closes — and the session is gone.",{"title":5,"path":6,"stem":7,"description":2285,"children":-1},"A book for Python engineers who want to understand the loop around the model.",1776848986904]