[{"data":1,"prerenderedAt":4128},["ShallowReactive",2],{"writing-mcp-di-balik-layar-en":3,"writing-en":1920,"hidden-projects-engineering-design":4127},{"id":4,"title":5,"body":6,"cover":1906,"date":1162,"description":1907,"draft":1908,"extension":1909,"lab":1908,"meta":1910,"navigation":1549,"original":1477,"path":1911,"seo":1912,"stem":1913,"tags":1914,"__hash__":1918,"lang":1919},"writing_en\u002Fwriting\u002Fmcp-di-balik-layar.md","Behind the scenes of MCP: what does the AI actually read?",{"type":7,"value":8,"toc":1890},"minimark",[9,24,59,62,67,70,80,159,166,170,177,182,204,207,211,214,679,682,685,738,753,757,760,906,917,921,940,947,954,1202,1221,1236,1240,1246,1277,1280,1312,1316,1329,1336,1353,1367,1384,1398,1402,1408,1500,1506,1510,1522,1818,1836,1843,1847,1886],[10,11,12,13,18,19,23],"p",{},"A while ago I built a ",[14,15,17],"a",{"href":16},"\u002Fwriting\u002Fmcp-server-asrama","small MCP server for boarding-school student data"," as an experiment. The server worked, and Claude could answer ",[20,21,22],"em",{},"\"which students in class 7A are on leave today?\"",". But afterwards I had questions that were more interesting than the code itself:",[25,26,27,36,47],"ul",{},[28,29,30,31,35],"li",{},"What does the model actually ",[32,33,34],"strong",{},"read","?",[28,37,38,39,42,43,46],{},"Does it read ",[32,40,41],{},"all"," tool definitions and all data every time, or is there some kind of ",[32,44,45],{},"glossary\u002Findex"," it opens only when needed?",[28,48,49,50,54,55,58],{},"If the model never sees my code, how does it know to call ",[51,52,53],"code",{},"cari_anak"," (find student) first, and ",[51,56,57],{},"absensi_harian"," (daily attendance) after?",[10,60,61],{},"This article isn't about building the server (that's in the lab note above), but about what happens behind it.",[63,64,66],"h2",{"id":65},"three-players-not-two","Three players, not two",[10,68,69],{},"The most common misconception: \"the AI is connected to the MCP server\". There are actually three parties, and the model is the most \"blind\" of them:",[71,72,77],"pre",{"className":73,"code":75,"language":76},[74],"language-text","┌──────────────┐  text\u002Ftokens  ┌──────────────┐   JSON-RPC    ┌──────────────┐\n│ Model        │ ◄───────────► │ Host         │ ◄───────────► │ MCP server   │\n│ (Claude)     │  (Messages    │ (Claude      │  (stdio \u002F     │ (server.py)  │\n│              │   API)        │  Desktop etc)│   HTTP)       │              │\n└──────────────┘               └──────────────┘               └──────────────┘\n","text",[51,78,75],{"__ignoreMap":79},"",[81,82,83,103],"table",{},[84,85,86],"thead",{},[87,88,89,93,96],"tr",{},[90,91,92],"th",{},"Party",[90,94,95],{},"What it does",[90,97,98,99,102],{},"What it does ",[32,100,101],{},"not"," do",[104,105,106,128,146],"tbody",{},[87,107,108,114,125],{},[109,110,111],"td",{},[32,112,113],{},"MCP server",[109,115,116,117,120,121,124],{},"Answers ",[51,118,119],{},"tools\u002Flist",", runs ",[51,122,123],{},"tools\u002Fcall",", calls your API",[109,126,127],{},"Never talks to the model",[87,129,130,136,143],{},[109,131,132,135],{},[32,133,134],{},"Host"," (Claude Desktop, Claude Code, Cursor, …)",[109,137,138,139,142],{},"Speaks MCP to the server ",[20,140,141],{},"and"," the API to the model, translating between them",[109,144,145],{},"Doesn't decide which tool to call",[87,147,148,153,156],{},[109,149,150],{},[32,151,152],{},"Model",[109,154,155],{},"Reads text, then writes text: an answer, or a \"request to call a tool\"",[109,157,158],{},"Opens no connections, runs no code, doesn't know the word \"MCP\"",[10,160,161,162,165],{},"The model receives exactly one thing: ",[32,163,164],{},"a request containing text",", and it returns text. All the \"intelligent tool use\" happens because the host assembles that text in a particular way.",[63,167,169],{"id":168},"the-journey-of-one-question","The journey of one question",[10,171,172,173,176],{},"Let's follow what happens when a staff member asks ",[20,174,175],{},"\"Which students in class 7A are on leave today?\"",".",[178,179,181],"h3",{"id":180},"_0-before-any-question","0. Before any question",[10,183,184,185,188,189,192,193,195,196,199,200,203],{},"When the host starts, it runs ",[51,186,187],{},"python server.py",", does the ",[51,190,191],{},"initialize"," handshake, then calls ",[51,194,119],{},". This list of tools is ",[32,197,198],{},"stored by the host",", not by the model. The host only asks again if the server sends a ",[51,201,202],{},"notifications\u002Ftools\u002Flist_changed"," notification.",[10,205,206],{},"So before the user types anything, the model has seen nothing. It isn't even \"in\" this conversation yet.",[178,208,210],{"id":209},"_1-the-host-builds-the-first-request","1. The host builds the first request",[10,212,213],{},"As soon as the user presses Enter, the host builds a request to the model. It looks roughly like this (an illustration in the Claude Messages API format; the exact contents depend on the host):",[71,215,219],{"className":216,"code":217,"language":218,"meta":79,"style":79},"language-json shiki shiki-themes github-light github-dark","{\n  \"model\": \"claude-opus-5-5\",\n  \"system\": \"Kamu adalah asisten ... Hari ini 2026-10-06.\\n\\n# MCP Server Instructions\\n## asrama\\nAkses read-only ke data anak asrama: pencarian anak, detail, kamar, dan absensi.\",\n  \"tools\": [\n    {\n      \"name\": \"mcp__asrama__cari_anak\",\n      \"description\": \"Cari anak asrama berdasarkan nama (sebagian), kelas (mis. '7A'), atau nama kamar.\\n    Semua filter opsional. Mengembalikan daftar ringkas anak beserta id-nya.\",\n      \"input_schema\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"nama\":  { \"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"null\" }], \"default\": null },\n          \"kelas\": { \"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"null\" }], \"default\": null },\n          \"kamar\": { \"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"null\" }], \"default\": null },\n          \"limit\": { \"type\": \"integer\", \"default\": 20 }\n        }\n      }\n    },\n    { \"name\": \"mcp__asrama__detail_anak\", \"description\": \"...\", \"input_schema\": { \"...\": \"...\" } },\n    { \"name\": \"mcp__asrama__daftar_kamar\", \"description\": \"...\", \"input_schema\": { \"...\": \"...\" } },\n    { \"name\": \"mcp__asrama__absensi_harian\", \"description\": \"...\", \"input_schema\": { \"...\": \"...\" } }\n  ],\n  \"messages\": [\n    { \"role\": \"user\", \"content\": \"Siapa saja anak kelas 7A yang izin hari ini?\" }\n  ]\n}\n","json",[51,220,221,230,247,277,286,292,305,323,332,345,353,400,437,473,501,507,513,519,559,593,628,634,642,667,673],{"__ignoreMap":79},[222,223,226],"span",{"class":224,"line":225},"line",1,[222,227,229],{"class":228},"sVt8B","{\n",[222,231,233,237,240,244],{"class":224,"line":232},2,[222,234,236],{"class":235},"sj4cs","  \"model\"",[222,238,239],{"class":228},": ",[222,241,243],{"class":242},"sZZnC","\"claude-opus-5-5\"",[222,245,246],{"class":228},",\n",[222,248,250,253,255,258,261,264,267,270,272,275],{"class":224,"line":249},3,[222,251,252],{"class":235},"  \"system\"",[222,254,239],{"class":228},[222,256,257],{"class":242},"\"Kamu adalah asisten ... Hari ini 2026-10-06.",[222,259,260],{"class":235},"\\n\\n",[222,262,263],{"class":242},"# MCP Server Instructions",[222,265,266],{"class":235},"\\n",[222,268,269],{"class":242},"## asrama",[222,271,266],{"class":235},[222,273,274],{"class":242},"Akses read-only ke data anak asrama: pencarian anak, detail, kamar, dan absensi.\"",[222,276,246],{"class":228},[222,278,280,283],{"class":224,"line":279},4,[222,281,282],{"class":235},"  \"tools\"",[222,284,285],{"class":228},": [\n",[222,287,289],{"class":224,"line":288},5,[222,290,291],{"class":228},"    {\n",[222,293,295,298,300,303],{"class":224,"line":294},6,[222,296,297],{"class":235},"      \"name\"",[222,299,239],{"class":228},[222,301,302],{"class":242},"\"mcp__asrama__cari_anak\"",[222,304,246],{"class":228},[222,306,308,311,313,316,318,321],{"class":224,"line":307},7,[222,309,310],{"class":235},"      \"description\"",[222,312,239],{"class":228},[222,314,315],{"class":242},"\"Cari anak asrama berdasarkan nama (sebagian), kelas (mis. '7A'), atau nama kamar.",[222,317,266],{"class":235},[222,319,320],{"class":242},"    Semua filter opsional. Mengembalikan daftar ringkas anak beserta id-nya.\"",[222,322,246],{"class":228},[222,324,326,329],{"class":224,"line":325},8,[222,327,328],{"class":235},"      \"input_schema\"",[222,330,331],{"class":228},": {\n",[222,333,335,338,340,343],{"class":224,"line":334},9,[222,336,337],{"class":235},"        \"type\"",[222,339,239],{"class":228},[222,341,342],{"class":242},"\"object\"",[222,344,246],{"class":228},[222,346,348,351],{"class":224,"line":347},10,[222,349,350],{"class":235},"        \"properties\"",[222,352,331],{"class":228},[222,354,356,359,362,365,368,371,373,376,379,381,383,386,389,392,394,397],{"class":224,"line":355},11,[222,357,358],{"class":235},"          \"nama\"",[222,360,361],{"class":228},":  { ",[222,363,364],{"class":235},"\"anyOf\"",[222,366,367],{"class":228},": [{ ",[222,369,370],{"class":235},"\"type\"",[222,372,239],{"class":228},[222,374,375],{"class":242},"\"string\"",[222,377,378],{"class":228}," }, { ",[222,380,370],{"class":235},[222,382,239],{"class":228},[222,384,385],{"class":242},"\"null\"",[222,387,388],{"class":228}," }], ",[222,390,391],{"class":235},"\"default\"",[222,393,239],{"class":228},[222,395,396],{"class":235},"null",[222,398,399],{"class":228}," },\n",[222,401,403,406,409,411,413,415,417,419,421,423,425,427,429,431,433,435],{"class":224,"line":402},12,[222,404,405],{"class":235},"          \"kelas\"",[222,407,408],{"class":228},": { ",[222,410,364],{"class":235},[222,412,367],{"class":228},[222,414,370],{"class":235},[222,416,239],{"class":228},[222,418,375],{"class":242},[222,420,378],{"class":228},[222,422,370],{"class":235},[222,424,239],{"class":228},[222,426,385],{"class":242},[222,428,388],{"class":228},[222,430,391],{"class":235},[222,432,239],{"class":228},[222,434,396],{"class":235},[222,436,399],{"class":228},[222,438,440,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471],{"class":224,"line":439},13,[222,441,442],{"class":235},"          \"kamar\"",[222,444,408],{"class":228},[222,446,364],{"class":235},[222,448,367],{"class":228},[222,450,370],{"class":235},[222,452,239],{"class":228},[222,454,375],{"class":242},[222,456,378],{"class":228},[222,458,370],{"class":235},[222,460,239],{"class":228},[222,462,385],{"class":242},[222,464,388],{"class":228},[222,466,391],{"class":235},[222,468,239],{"class":228},[222,470,396],{"class":235},[222,472,399],{"class":228},[222,474,476,479,481,483,485,488,491,493,495,498],{"class":224,"line":475},14,[222,477,478],{"class":235},"          \"limit\"",[222,480,408],{"class":228},[222,482,370],{"class":235},[222,484,239],{"class":228},[222,486,487],{"class":242},"\"integer\"",[222,489,490],{"class":228},", ",[222,492,391],{"class":235},[222,494,239],{"class":228},[222,496,497],{"class":235},"20",[222,499,500],{"class":228}," }\n",[222,502,504],{"class":224,"line":503},15,[222,505,506],{"class":228},"        }\n",[222,508,510],{"class":224,"line":509},16,[222,511,512],{"class":228},"      }\n",[222,514,516],{"class":224,"line":515},17,[222,517,518],{"class":228},"    },\n",[222,520,522,525,528,530,533,535,538,540,543,545,548,550,552,554,556],{"class":224,"line":521},18,[222,523,524],{"class":228},"    { ",[222,526,527],{"class":235},"\"name\"",[222,529,239],{"class":228},[222,531,532],{"class":242},"\"mcp__asrama__detail_anak\"",[222,534,490],{"class":228},[222,536,537],{"class":235},"\"description\"",[222,539,239],{"class":228},[222,541,542],{"class":242},"\"...\"",[222,544,490],{"class":228},[222,546,547],{"class":235},"\"input_schema\"",[222,549,408],{"class":228},[222,551,542],{"class":235},[222,553,239],{"class":228},[222,555,542],{"class":242},[222,557,558],{"class":228}," } },\n",[222,560,562,564,566,568,571,573,575,577,579,581,583,585,587,589,591],{"class":224,"line":561},19,[222,563,524],{"class":228},[222,565,527],{"class":235},[222,567,239],{"class":228},[222,569,570],{"class":242},"\"mcp__asrama__daftar_kamar\"",[222,572,490],{"class":228},[222,574,537],{"class":235},[222,576,239],{"class":228},[222,578,542],{"class":242},[222,580,490],{"class":228},[222,582,547],{"class":235},[222,584,408],{"class":228},[222,586,542],{"class":235},[222,588,239],{"class":228},[222,590,542],{"class":242},[222,592,558],{"class":228},[222,594,596,598,600,602,605,607,609,611,613,615,617,619,621,623,625],{"class":224,"line":595},20,[222,597,524],{"class":228},[222,599,527],{"class":235},[222,601,239],{"class":228},[222,603,604],{"class":242},"\"mcp__asrama__absensi_harian\"",[222,606,490],{"class":228},[222,608,537],{"class":235},[222,610,239],{"class":228},[222,612,542],{"class":242},[222,614,490],{"class":228},[222,616,547],{"class":235},[222,618,408],{"class":228},[222,620,542],{"class":235},[222,622,239],{"class":228},[222,624,542],{"class":242},[222,626,627],{"class":228}," } }\n",[222,629,631],{"class":224,"line":630},21,[222,632,633],{"class":228},"  ],\n",[222,635,637,640],{"class":224,"line":636},22,[222,638,639],{"class":235},"  \"messages\"",[222,641,285],{"class":228},[222,643,645,647,650,652,655,657,660,662,665],{"class":224,"line":644},23,[222,646,524],{"class":228},[222,648,649],{"class":235},"\"role\"",[222,651,239],{"class":228},[222,653,654],{"class":242},"\"user\"",[222,656,490],{"class":228},[222,658,659],{"class":235},"\"content\"",[222,661,239],{"class":228},[222,663,664],{"class":242},"\"Siapa saja anak kelas 7A yang izin hari ini?\"",[222,666,500],{"class":228},[222,668,670],{"class":224,"line":669},24,[222,671,672],{"class":228},"  ]\n",[222,674,676],{"class":224,"line":675},25,[222,677,678],{"class":228},"}\n",[10,680,681],{},"(The server and its data are in Indonesian, so the prompt and the user's question are too. \"Hari ini\" means \"today\".)",[10,683,684],{},"A few things to notice:",[25,686,687,712,722,732],{},[28,688,689,699,700,703,704,707,708,711],{},[32,690,691,692,695,696],{},"MCP's ",[51,693,694],{},"inputSchema"," becomes ",[51,697,698],{},"input_schema"," in the API. The host just moves the contents across. The ",[51,701,702],{},"name"," and the ",[51,705,706],{},"description"," from your docstring come along verbatim, including the ",[51,709,710],{},"\\n    "," indentation.",[28,713,714,717,718,721],{},[32,715,716],{},"The host may prefix tool names."," Claude Code, for example, names it ",[51,719,720],{},"mcp__asrama__cari_anak"," so it doesn't clash with tools from other servers. The model doesn't know it is an \"MCP tool\"; to the model it is an ordinary tool with a long name.",[28,723,724,731],{},[32,725,726,727,730],{},"The server's ",[51,728,729],{},"instructions"," go into the system prompt",", but that's the host's choice. Some hosts include them, some don't.",[28,733,734,737],{},[32,735,736],{},"Today's date"," comes from the host. The model has no clock. If the host doesn't put the date in the system prompt, the model has no idea what \"today\" means and has to guess or ask.",[10,739,740,741,744,745,748,749,752],{},"So is the JSON above what the model reads? Not exactly. The API turns the tool definitions, the system prompt and the messages into one sequence of ",[32,742,743],{},"tokens"," in a fixed order: ",[20,746,747],{},"tools → system → messages",". Anthropic's documentation describes the tool definitions as being assembled into a special part of the system prompt. So to the model, your docstring is ",[32,750,751],{},"text at the start of the prompt",", side by side with the other instructions.",[178,754,756],{"id":755},"_2-the-model-calls-a-tool-but-only-writes-text","2. The model \"calls\" a tool, but only writes text",[10,758,759],{},"The model reads all of it and replies:",[71,761,763],{"className":216,"code":762,"language":218,"meta":79,"style":79},"{\n  \"stop_reason\": \"tool_use\",\n  \"content\": [\n    { \"type\": \"text\", \"text\": \"Saya cek dulu daftar anak kelas 7A dan absensi hari ini.\" },\n    { \"type\": \"tool_use\", \"id\": \"toolu_01\", \"name\": \"mcp__asrama__cari_anak\", \"input\": { \"kelas\": \"7A\" } },\n    { \"type\": \"tool_use\", \"id\": \"toolu_02\", \"name\": \"mcp__asrama__absensi_harian\", \"input\": { \"tanggal\": \"2026-10-06\" } }\n  ]\n}\n",[51,764,765,769,781,788,810,855,898,902],{"__ignoreMap":79},[222,766,767],{"class":224,"line":225},[222,768,229],{"class":228},[222,770,771,774,776,779],{"class":224,"line":232},[222,772,773],{"class":235},"  \"stop_reason\"",[222,775,239],{"class":228},[222,777,778],{"class":242},"\"tool_use\"",[222,780,246],{"class":228},[222,782,783,786],{"class":224,"line":249},[222,784,785],{"class":235},"  \"content\"",[222,787,285],{"class":228},[222,789,790,792,794,796,799,801,803,805,808],{"class":224,"line":279},[222,791,524],{"class":228},[222,793,370],{"class":235},[222,795,239],{"class":228},[222,797,798],{"class":242},"\"text\"",[222,800,490],{"class":228},[222,802,798],{"class":235},[222,804,239],{"class":228},[222,806,807],{"class":242},"\"Saya cek dulu daftar anak kelas 7A dan absensi hari ini.\"",[222,809,399],{"class":228},[222,811,812,814,816,818,820,822,825,827,830,832,834,836,838,840,843,845,848,850,853],{"class":224,"line":288},[222,813,524],{"class":228},[222,815,370],{"class":235},[222,817,239],{"class":228},[222,819,778],{"class":242},[222,821,490],{"class":228},[222,823,824],{"class":235},"\"id\"",[222,826,239],{"class":228},[222,828,829],{"class":242},"\"toolu_01\"",[222,831,490],{"class":228},[222,833,527],{"class":235},[222,835,239],{"class":228},[222,837,302],{"class":242},[222,839,490],{"class":228},[222,841,842],{"class":235},"\"input\"",[222,844,408],{"class":228},[222,846,847],{"class":235},"\"kelas\"",[222,849,239],{"class":228},[222,851,852],{"class":242},"\"7A\"",[222,854,558],{"class":228},[222,856,857,859,861,863,865,867,869,871,874,876,878,880,882,884,886,888,891,893,896],{"class":224,"line":294},[222,858,524],{"class":228},[222,860,370],{"class":235},[222,862,239],{"class":228},[222,864,778],{"class":242},[222,866,490],{"class":228},[222,868,824],{"class":235},[222,870,239],{"class":228},[222,872,873],{"class":242},"\"toolu_02\"",[222,875,490],{"class":228},[222,877,527],{"class":235},[222,879,239],{"class":228},[222,881,604],{"class":242},[222,883,490],{"class":228},[222,885,842],{"class":235},[222,887,408],{"class":228},[222,889,890],{"class":235},"\"tanggal\"",[222,892,239],{"class":228},[222,894,895],{"class":242},"\"2026-10-06\"",[222,897,627],{"class":228},[222,899,900],{"class":224,"line":307},[222,901,672],{"class":228},[222,903,904],{"class":224,"line":325},[222,905,678],{"class":228},[10,907,908,909,912,913,916],{},"The model runs nothing. It only produces structured blocks that say \"please run this\", and stops with ",[51,910,911],{},"stop_reason: \"tool_use\"",". Here it asks for ",[32,914,915],{},"two tools at once"," (parallel tool use) because they don't depend on each other. It took the date from the system prompt.",[178,918,920],{"id":919},"_3-the-host-translates-to-json-rpc","3. The host translates to JSON-RPC",[10,922,923,924,926,927,930,931,933,934,936,937,176],{},"The host sees the name ",[51,925,720],{},", knows it belongs to the ",[51,928,929],{},"asrama"," server, and sends a ",[51,932,123],{}," with the original name ",[51,935,53],{},", exactly as dissected in the lab note. The server calls the REST API, filters out the sensitive fields and replies with JSON in ",[51,938,939],{},"content[].text",[178,941,943,944],{"id":942},"_4-tool-results-join-the-conversation-and-everything-is-sent-again","4. Tool results join the conversation, and ",[32,945,946],{},"everything is sent again",[10,948,949,950,953],{},"This is the part people most often miss. The host appends two messages to the history, then sends a ",[32,951,952],{},"complete new request"," to the model:",[71,955,957],{"className":216,"code":956,"language":218,"meta":79,"style":79},"{\n  \"system\": \"... (same as before) ...\",\n  \"tools\": [ \"... (all four tools, in full, same as before) ...\" ],\n  \"messages\": [\n    { \"role\": \"user\", \"content\": \"Siapa saja anak kelas 7A yang izin hari ini?\" },\n    { \"role\": \"assistant\", \"content\": [ \"... the text block + the two tool_use blocks above ...\" ] },\n    {\n      \"role\": \"user\",\n      \"content\": [\n        { \"type\": \"tool_result\", \"tool_use_id\": \"toolu_01\", \"content\": \"{\\n  \\\"total\\\": 2,\\n  \\\"data\\\": [ ... ]\\n}\" },\n        { \"type\": \"tool_result\", \"tool_use_id\": \"toolu_02\", \"content\": \"{\\n  \\\"tanggal\\\": \\\"2026-10-06\\\",\\n  \\\"data\\\": [ ... ]\\n}\" }\n      ]\n    }\n  ]\n}\n",[51,958,959,963,974,987,993,1013,1036,1040,1051,1058,1121,1184,1189,1194,1198],{"__ignoreMap":79},[222,960,961],{"class":224,"line":225},[222,962,229],{"class":228},[222,964,965,967,969,972],{"class":224,"line":232},[222,966,252],{"class":235},[222,968,239],{"class":228},[222,970,971],{"class":242},"\"... (same as before) ...\"",[222,973,246],{"class":228},[222,975,976,978,981,984],{"class":224,"line":249},[222,977,282],{"class":235},[222,979,980],{"class":228},": [ ",[222,982,983],{"class":242},"\"... (all four tools, in full, same as before) ...\"",[222,985,986],{"class":228}," ],\n",[222,988,989,991],{"class":224,"line":279},[222,990,639],{"class":235},[222,992,285],{"class":228},[222,994,995,997,999,1001,1003,1005,1007,1009,1011],{"class":224,"line":288},[222,996,524],{"class":228},[222,998,649],{"class":235},[222,1000,239],{"class":228},[222,1002,654],{"class":242},[222,1004,490],{"class":228},[222,1006,659],{"class":235},[222,1008,239],{"class":228},[222,1010,664],{"class":242},[222,1012,399],{"class":228},[222,1014,1015,1017,1019,1021,1024,1026,1028,1030,1033],{"class":224,"line":294},[222,1016,524],{"class":228},[222,1018,649],{"class":235},[222,1020,239],{"class":228},[222,1022,1023],{"class":242},"\"assistant\"",[222,1025,490],{"class":228},[222,1027,659],{"class":235},[222,1029,980],{"class":228},[222,1031,1032],{"class":242},"\"... the text block + the two tool_use blocks above ...\"",[222,1034,1035],{"class":228}," ] },\n",[222,1037,1038],{"class":224,"line":307},[222,1039,291],{"class":228},[222,1041,1042,1045,1047,1049],{"class":224,"line":325},[222,1043,1044],{"class":235},"      \"role\"",[222,1046,239],{"class":228},[222,1048,654],{"class":242},[222,1050,246],{"class":228},[222,1052,1053,1056],{"class":224,"line":334},[222,1054,1055],{"class":235},"      \"content\"",[222,1057,285],{"class":228},[222,1059,1060,1063,1065,1067,1070,1072,1075,1077,1079,1081,1083,1085,1088,1090,1093,1096,1099,1102,1104,1106,1109,1111,1114,1116,1119],{"class":224,"line":347},[222,1061,1062],{"class":228},"        { ",[222,1064,370],{"class":235},[222,1066,239],{"class":228},[222,1068,1069],{"class":242},"\"tool_result\"",[222,1071,490],{"class":228},[222,1073,1074],{"class":235},"\"tool_use_id\"",[222,1076,239],{"class":228},[222,1078,829],{"class":242},[222,1080,490],{"class":228},[222,1082,659],{"class":235},[222,1084,239],{"class":228},[222,1086,1087],{"class":242},"\"{",[222,1089,266],{"class":235},[222,1091,1092],{"class":235},"  \\\"",[222,1094,1095],{"class":242},"total",[222,1097,1098],{"class":235},"\\\"",[222,1100,1101],{"class":242},": 2,",[222,1103,266],{"class":235},[222,1105,1092],{"class":235},[222,1107,1108],{"class":242},"data",[222,1110,1098],{"class":235},[222,1112,1113],{"class":242},": [ ... ]",[222,1115,266],{"class":235},[222,1117,1118],{"class":242},"}\"",[222,1120,399],{"class":228},[222,1122,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141,1143,1145,1147,1149,1151,1154,1156,1158,1160,1163,1165,1168,1170,1172,1174,1176,1178,1180,1182],{"class":224,"line":355},[222,1124,1062],{"class":228},[222,1126,370],{"class":235},[222,1128,239],{"class":228},[222,1130,1069],{"class":242},[222,1132,490],{"class":228},[222,1134,1074],{"class":235},[222,1136,239],{"class":228},[222,1138,873],{"class":242},[222,1140,490],{"class":228},[222,1142,659],{"class":235},[222,1144,239],{"class":228},[222,1146,1087],{"class":242},[222,1148,266],{"class":235},[222,1150,1092],{"class":235},[222,1152,1153],{"class":242},"tanggal",[222,1155,1098],{"class":235},[222,1157,239],{"class":242},[222,1159,1098],{"class":235},[222,1161,1162],{"class":242},"2026-10-06",[222,1164,1098],{"class":235},[222,1166,1167],{"class":242},",",[222,1169,266],{"class":235},[222,1171,1092],{"class":235},[222,1173,1108],{"class":242},[222,1175,1098],{"class":235},[222,1177,1113],{"class":242},[222,1179,266],{"class":235},[222,1181,1118],{"class":242},[222,1183,500],{"class":228},[222,1185,1186],{"class":224,"line":402},[222,1187,1188],{"class":228},"      ]\n",[222,1190,1191],{"class":224,"line":439},[222,1192,1193],{"class":228},"    }\n",[222,1195,1196],{"class":224,"line":475},[222,1197,672],{"class":228},[222,1199,1200],{"class":224,"line":503},[222,1201,678],{"class":228},[10,1203,1204,1205,1208,1209,1212,1213,1216,1217,1220],{},"Tool results are sent as a ",[51,1206,1207],{},"role: \"user\""," message, paired by ",[51,1210,1211],{},"tool_use_id",". If the MCP server replied with ",[51,1214,1215],{},"isError: true",", the host usually passes it on as ",[51,1218,1219],{},"is_error: true",". That's why an error \"hidden\" as a plain dict (covered in the lab note) still reads as a success.",[10,1222,1223,1224,1227,1228,1231,1232,1235],{},"The model rereads everything from the start, matches the two results and answers: ",[20,1225,1226],{},"\"Of the two students in class 7A, the one on leave today is Citra Lestari (gone home for a family event).\""," This time the ",[51,1229,1230],{},"stop_reason"," is ",[51,1233,1234],{},"end_turn",", and the host shows the answer.",[63,1237,1239],{"id":1238},"so-is-everything-read","So, is everything read?",[10,1241,1242,1245],{},[32,1243,1244],{},"Yes. On every request, all of it."," That's the answer to the main question:",[1247,1248,1249,1259,1265,1271],"ol",{},[28,1250,1251,1254,1255,1258],{},[32,1252,1253],{},"The model has no memory between requests."," The API is ",[20,1256,1257],{},"stateless",". A conversation's \"memory\" is just the history the host sends again every time. In step 4 the model didn't \"continue\"; it reread the whole conversation from the start.",[28,1260,1261,1264],{},[32,1262,1263],{},"Every tool definition rides along on every request."," All four tools, with docstrings and schemas, are sent again on the second, third and every later request, even if only one is used.",[28,1266,1267,1270],{},[32,1268,1269],{},"Old tool results ride along too."," The student-list JSON from step 3 stays in the history and is read again on every following turn, until the host trims or summarises the history.",[28,1272,1273,1276],{},[32,1274,1275],{},"\"Reading\" means all tokens are in context at once."," The model doesn't flip through pages. All tokens come in together and the model attends to all of them while producing each word. Nothing is skipped on purpose. But in a very long context, attention to small details in the middle can get less sharp. That's a good reason to keep the context lean.",[10,1278,1279],{},"The practical consequences:",[25,1281,1282,1288,1306],{},[28,1283,1284,1287],{},[32,1285,1286],{},"Every tool pays \"rent\" in tokens on every turn."," Four small tools are barely noticeable. But ten servers with twenty tools each means thousands of tokens of tool definitions are spent before the user types anything.",[28,1289,1290,1293,1294,1297,1298,1301,1302,1305],{},[32,1291,1292],{},"A bulky tool result is paid for again and again."," JSON with ",[51,1295,1296],{},"indent=2"," and irrelevant fields is read again on every turn after it. Filtering fields (like ",[51,1299,1300],{},"sembunyikan_sensitif()",") and capping ",[51,1303,1304],{},"limit"," isn't only about privacy, it's about context too.",[28,1307,1308,1311],{},[32,1309,1310],{},"Prompt caching helps the cost, not the content."," Because the beginning (tools, system) is the same from request to request, the API can cache it so it's cheaper and faster. But it is still in the context and still \"read\" by the model.",[63,1313,1315],{"id":1314},"is-there-some-kind-of-glossary","Is there some kind of glossary?",[10,1317,1318,1321,1322,1324,1325,1328],{},[32,1319,1320],{},"By default, no."," There is no index, table of contents or summary that gets opened on demand. The host sends the full definitions of every active tool. The MCP protocol itself has no glossary concept either. ",[51,1323,119],{}," does support pagination (",[51,1326,1327],{},"cursor","), but that's only between host and server; the host still fetches everything and passes it to the model.",[10,1330,1331,1332,1335],{},"But precisely because \"everything is read\" is expensive, there are a few ",[32,1333,1334],{},"glossary-like"," patterns:",[10,1337,1338,1341,1342,1345,1346,1349,1350,176],{},[32,1339,1340],{},"1. Tool search \u002F deferred loading (on the host or API side)."," When there are very many tools, the host can hold back the full definitions and give the model only a search tool. In the Claude API this is called the ",[20,1343,1344],{},"tool search tool",": other tools are marked ",[51,1347,1348],{},"defer_loading: true",", the model initially sees only the search tool, then searches for the relevant tools. The schemas of the tools it finds are added to the context only at that moment. Claude Code uses a similar pattern for large numbers of MCP tools: the model only sees a list of names, then loads the full schema through a search before calling a tool. This is the closest thing to a \"glossary\": ",[32,1351,1352],{},"names first, details later",[10,1354,1355,1358,1359,1362,1363,1366],{},[32,1356,1357],{},"2. Resources aren't read unless attached."," ",[51,1360,1361],{},"resources\u002Flist"," contains only metadata (uri, name, description), and even that is for the host, not automatically for the model. A resource's contents enter the context only when the user or the host attaches it, and once they do, ",[32,1364,1365],{},"all of it"," goes in (unless the host truncates it). There is no automatic search for the relevant part.",[10,1368,1369,1372,1373,1376,1377,1379,1380,1383],{},[32,1370,1371],{},"3. A glossary you build yourself: a search tool."," If the data is large, say thousands of students or a long document of boarding-school rules, don't make it a giant resource. Build a tool that filters on the server side, like ",[51,1374,1375],{},"cari_anak(kelas=...)"," with a ",[51,1378,1304],{},", or a ",[51,1381,1382],{},"cari_peraturan(kata_kunci=...)"," (search rules by keyword) that returns only the relevant passages. The server does the \"opening the glossary\", and the model receives only the page it needs. This pattern is what's usually called RAG; MCP doesn't provide it automatically, but it is very easy to wrap as a tool.",[10,1385,1386,1389,1390,1393,1394,1397],{},[32,1387,1388],{},"4. Docstrings as hints about order."," The sentence ",[20,1391,1392],{},"\"Gunakan cari_anak dulu jika id belum diketahui\""," (\"use cari_anak first if the id is not known yet\") in the ",[51,1395,1396],{},"detail_anak"," docstring is a kind of mini map. The model has no other documentation about your server; the docstring is the only manual it reads.",[63,1399,1401],{"id":1400},"what-never-reaches-the-model","What never reaches the model",[10,1403,1404,1405,1407],{},"Just as important as what is read is what is ",[32,1406,101],{},":",[81,1409,1410,1420],{},[84,1411,1412],{},[87,1413,1414,1417],{},[90,1415,1416],{},"Not read by the model",[90,1418,1419],{},"Why",[104,1421,1422,1430,1441,1459,1467,1492],{},[87,1423,1424,1427],{},[109,1425,1426],{},"Your Python code",[109,1428,1429],{},"Only the function name, docstring and the schema generated from type hints are sent",[87,1431,1432,1438],{},[109,1433,1434,1435],{},"The API URL and the ",[51,1436,1437],{},"ASRAMA_API_TOKEN",[109,1439,1440],{},"They live in the server's environment and are never sent to the host",[87,1442,1443,1456],{},[109,1444,1445,1446,490,1449,490,1452,1455],{},"Filtered fields (",[51,1447,1448],{},"nik",[51,1450,1451],{},"no_hp_wali",[51,1453,1454],{},"alamat",")",[109,1457,1458],{},"Dropped by the server before sending",[87,1460,1461,1464],{},[109,1462,1463],{},"Logs on stderr",[109,1465,1466],{},"Only stdout carries the protocol, and the host doesn't pass logs to the model",[87,1468,1469,1481],{},[109,1470,1471,1472,490,1475,490,1478,1455],{},"The JSON-RPC envelope (",[51,1473,1474],{},"jsonrpc",[51,1476,1477],{},"id",[51,1479,1480],{},"method",[109,1482,1483,1484,1487,1488,1491],{},"Translated by the host into ",[51,1485,1486],{},"tool_use"," \u002F ",[51,1489,1490],{},"tool_result"," blocks",[87,1493,1494,1497],{},[109,1495,1496],{},"Tools from servers that aren't enabled",[109,1498,1499],{},"The host only sends tools the user currently has switched on",[10,1501,1502,1503,1505],{},"This boundary is also your security boundary. Whatever a tool returns is read by the model ",[32,1504,141],{}," stays in the conversation history. So filter on the server; don't count on the model \"not paying attention\".",[63,1507,1509],{"id":1508},"measure-it-yourself","Measure it yourself",[10,1511,1512,1513,1515,1516,1518,1519,1521],{},"The most honest way to feel the \"rent\" of tool definitions is to count their tokens. Take the ",[51,1514,119],{}," result from your server, rename ",[51,1517,694],{}," to ",[51,1520,698],{},", then compare the token count with and without tools using the token-counting endpoint:",[71,1523,1527],{"className":1524,"code":1525,"language":1526,"meta":79,"style":79},"language-python shiki shiki-themes github-light github-dark","import json\nimport anthropic\n\nclient = anthropic.Anthropic()\n\n# the MCP server's tools\u002Flist result, saved to a file\nmcp_tools = json.load(open(\"tools_list.json\"))[\"result\"][\"tools\"]\ntools = [\n    {\"name\": t[\"name\"], \"description\": t.get(\"description\", \"\"), \"input_schema\": t[\"inputSchema\"]}\n    for t in mcp_tools\n]\nmessages = [{\"role\": \"user\", \"content\": \"Siapa saja anak kelas 7A yang izin hari ini?\"}]\n\ntanpa = client.messages.count_tokens(model=\"claude-opus-5-5\", messages=messages)\ndengan = client.messages.count_tokens(model=\"claude-opus-5-5\", messages=messages, tools=tools)\n\nprint(\"tanpa tools :\", tanpa.input_tokens)\nprint(\"dengan tools:\", dengan.input_tokens)\nprint(\"biaya sewa  :\", dengan.input_tokens - tanpa.input_tokens, \"token per giliran\")\n","python",[51,1528,1529,1538,1545,1551,1562,1566,1572,1606,1616,1656,1670,1674,1701,1705,1733,1765,1769,1782,1794],{"__ignoreMap":79},[222,1530,1531,1535],{"class":224,"line":225},[222,1532,1534],{"class":1533},"szBVR","import",[222,1536,1537],{"class":228}," json\n",[222,1539,1540,1542],{"class":224,"line":232},[222,1541,1534],{"class":1533},[222,1543,1544],{"class":228}," anthropic\n",[222,1546,1547],{"class":224,"line":249},[222,1548,1550],{"emptyLinePlaceholder":1549},true,"\n",[222,1552,1553,1556,1559],{"class":224,"line":279},[222,1554,1555],{"class":228},"client ",[222,1557,1558],{"class":1533},"=",[222,1560,1561],{"class":228}," anthropic.Anthropic()\n",[222,1563,1564],{"class":224,"line":288},[222,1565,1550],{"emptyLinePlaceholder":1549},[222,1567,1568],{"class":224,"line":294},[222,1569,1571],{"class":1570},"sJ8bj","# the MCP server's tools\u002Flist result, saved to a file\n",[222,1573,1574,1577,1579,1582,1585,1588,1591,1594,1597,1600,1603],{"class":224,"line":307},[222,1575,1576],{"class":228},"mcp_tools ",[222,1578,1558],{"class":1533},[222,1580,1581],{"class":228}," json.load(",[222,1583,1584],{"class":235},"open",[222,1586,1587],{"class":228},"(",[222,1589,1590],{"class":242},"\"tools_list.json\"",[222,1592,1593],{"class":228},"))[",[222,1595,1596],{"class":242},"\"result\"",[222,1598,1599],{"class":228},"][",[222,1601,1602],{"class":242},"\"tools\"",[222,1604,1605],{"class":228},"]\n",[222,1607,1608,1611,1613],{"class":224,"line":325},[222,1609,1610],{"class":228},"tools ",[222,1612,1558],{"class":1533},[222,1614,1615],{"class":228}," [\n",[222,1617,1618,1621,1623,1626,1628,1631,1633,1636,1638,1640,1643,1646,1648,1650,1653],{"class":224,"line":334},[222,1619,1620],{"class":228},"    {",[222,1622,527],{"class":242},[222,1624,1625],{"class":228},": t[",[222,1627,527],{"class":242},[222,1629,1630],{"class":228},"], ",[222,1632,537],{"class":242},[222,1634,1635],{"class":228},": t.get(",[222,1637,537],{"class":242},[222,1639,490],{"class":228},[222,1641,1642],{"class":242},"\"\"",[222,1644,1645],{"class":228},"), ",[222,1647,547],{"class":242},[222,1649,1625],{"class":228},[222,1651,1652],{"class":242},"\"inputSchema\"",[222,1654,1655],{"class":228},"]}\n",[222,1657,1658,1661,1664,1667],{"class":224,"line":347},[222,1659,1660],{"class":1533},"    for",[222,1662,1663],{"class":228}," t ",[222,1665,1666],{"class":1533},"in",[222,1668,1669],{"class":228}," mcp_tools\n",[222,1671,1672],{"class":224,"line":355},[222,1673,1605],{"class":228},[222,1675,1676,1679,1681,1684,1686,1688,1690,1692,1694,1696,1698],{"class":224,"line":402},[222,1677,1678],{"class":228},"messages ",[222,1680,1558],{"class":1533},[222,1682,1683],{"class":228}," [{",[222,1685,649],{"class":242},[222,1687,239],{"class":228},[222,1689,654],{"class":242},[222,1691,490],{"class":228},[222,1693,659],{"class":242},[222,1695,239],{"class":228},[222,1697,664],{"class":242},[222,1699,1700],{"class":228},"}]\n",[222,1702,1703],{"class":224,"line":439},[222,1704,1550],{"emptyLinePlaceholder":1549},[222,1706,1707,1710,1712,1715,1719,1721,1723,1725,1728,1730],{"class":224,"line":475},[222,1708,1709],{"class":228},"tanpa ",[222,1711,1558],{"class":1533},[222,1713,1714],{"class":228}," client.messages.count_tokens(",[222,1716,1718],{"class":1717},"s4XuR","model",[222,1720,1558],{"class":1533},[222,1722,243],{"class":242},[222,1724,490],{"class":228},[222,1726,1727],{"class":1717},"messages",[222,1729,1558],{"class":1533},[222,1731,1732],{"class":228},"messages)\n",[222,1734,1735,1738,1740,1742,1744,1746,1748,1750,1752,1754,1757,1760,1762],{"class":224,"line":503},[222,1736,1737],{"class":228},"dengan ",[222,1739,1558],{"class":1533},[222,1741,1714],{"class":228},[222,1743,1718],{"class":1717},[222,1745,1558],{"class":1533},[222,1747,243],{"class":242},[222,1749,490],{"class":228},[222,1751,1727],{"class":1717},[222,1753,1558],{"class":1533},[222,1755,1756],{"class":228},"messages, ",[222,1758,1759],{"class":1717},"tools",[222,1761,1558],{"class":1533},[222,1763,1764],{"class":228},"tools)\n",[222,1766,1767],{"class":224,"line":509},[222,1768,1550],{"emptyLinePlaceholder":1549},[222,1770,1771,1774,1776,1779],{"class":224,"line":515},[222,1772,1773],{"class":235},"print",[222,1775,1587],{"class":228},[222,1777,1778],{"class":242},"\"tanpa tools :\"",[222,1780,1781],{"class":228},", tanpa.input_tokens)\n",[222,1783,1784,1786,1788,1791],{"class":224,"line":521},[222,1785,1773],{"class":235},[222,1787,1587],{"class":228},[222,1789,1790],{"class":242},"\"dengan tools:\"",[222,1792,1793],{"class":228},", dengan.input_tokens)\n",[222,1795,1796,1798,1800,1803,1806,1809,1812,1815],{"class":224,"line":561},[222,1797,1773],{"class":235},[222,1799,1587],{"class":228},[222,1801,1802],{"class":242},"\"biaya sewa  :\"",[222,1804,1805],{"class":228},", dengan.input_tokens ",[222,1807,1808],{"class":1533},"-",[222,1810,1811],{"class":228}," tanpa.input_tokens, ",[222,1813,1814],{"class":242},"\"token per giliran\"",[222,1816,1817],{"class":228},")\n",[10,1819,1587,1820,1823,1824,1827,1828,1831,1832,1835],{},[51,1821,1822],{},"tanpa"," = without, ",[51,1825,1826],{},"dengan"," = with, ",[51,1829,1830],{},"biaya sewa"," = rent, ",[51,1833,1834],{},"token per giliran"," = tokens per turn.)",[10,1837,1838,1839,1842],{},"The difference is what the model reads ",[32,1840,1841],{},"on every turn"," just to get to know your tools. Try tidying the docstrings too (remove the indentation, sharpen the sentences) and see how the number changes.",[63,1844,1846],{"id":1845},"summary","Summary",[25,1848,1849,1856,1866,1872,1883],{},[28,1850,1851,1852,1855],{},"The model isn't connected to the MCP server. The ",[32,1853,1854],{},"host"," talks to both and translates between them.",[28,1857,1858,1859,1861,1862,1865],{},"What the model reads: the system prompt (including the server's ",[51,1860,729],{},", if the host adds them), each tool's ",[32,1863,1864],{},"name + docstring + schema",", and the entire conversation history, including every tool result.",[28,1867,1868,1869,1871],{},"The model is ",[32,1870,1257],{},": everything is sent again and read again on every request. There is no built-in glossary.",[28,1873,1874,1875,1878,1879,1882],{},"Glossary-like patterns exist, but they have to be built: ",[32,1876,1877],{},"tool search \u002F deferred loading"," in the host, and ",[32,1880,1881],{},"search tools"," in your own server.",[28,1884,1885],{},"So the three things that most determine an agent's quality stay the same: clear tool names, informative docstrings, and short tool results. Now the reason is clearer: all of it is text the model reads, again and again, on every turn.",[1887,1888,1889],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":79,"searchDepth":232,"depth":232,"links":1891},[1892,1893,1901,1902,1903,1904,1905],{"id":65,"depth":232,"text":66},{"id":168,"depth":232,"text":169,"children":1894},[1895,1896,1897,1898,1899],{"id":180,"depth":249,"text":181},{"id":209,"depth":249,"text":210},{"id":755,"depth":249,"text":756},{"id":919,"depth":249,"text":920},{"id":942,"depth":249,"text":1900},"4. Tool results join the conversation, and everything is sent again",{"id":1238,"depth":232,"text":1239},{"id":1314,"depth":232,"text":1315},{"id":1400,"depth":232,"text":1401},{"id":1508,"depth":232,"text":1509},{"id":1845,"depth":232,"text":1846},null,"The model never sees your code, doesn't speak JSON-RPC, and has no memory. So how does it know which tool to call? Following one question from host to model, and answering: is everything read every time, or is there some kind of glossary?",false,"md",{},"\u002Fwriting\u002Fmcp-di-balik-layar",{"title":5,"description":1907},"writing\u002Fmcp-di-balik-layar",[1915,1916,1917],"Engineering","AI","MCP","qDVK1S-PHUC6zP5HOD8gdL8gewtlrh_5jktyKV6kmAw","en",[1921,3333,3831,4098],{"id":4,"title":5,"body":1922,"cover":1906,"date":1162,"description":1907,"draft":1908,"extension":1909,"lab":1908,"meta":3330,"navigation":1549,"original":1477,"path":1911,"seo":3331,"stem":1913,"tags":3332,"__hash__":1918},{"type":7,"value":1923,"toc":3315},[1924,1930,1948,1950,1952,1954,1959,2011,2015,2017,2021,2023,2035,2037,2039,2041,2407,2409,2411,2443,2451,2453,2455,2587,2593,2595,2607,2611,2615,2837,2847,2855,2857,2861,2881,2883,2903,2905,2913,2917,2927,2935,2945,2953,2955,2959,3025,3029,3031,3039,3273,3283,3287,3289,3313],[10,1925,12,1926,18,1928,23],{},[14,1927,17],{"href":16},[20,1929,22],{},[25,1931,1932,1936,1942],{},[28,1933,30,1934,35],{},[32,1935,34],{},[28,1937,38,1938,42,1940,46],{},[32,1939,41],{},[32,1941,45],{},[28,1943,49,1944,54,1946,58],{},[51,1945,53],{},[51,1947,57],{},[10,1949,61],{},[63,1951,66],{"id":65},[10,1953,69],{},[71,1955,1957],{"className":1956,"code":75,"language":76},[74],[51,1958,75],{"__ignoreMap":79},[81,1960,1961,1973],{},[84,1962,1963],{},[87,1964,1965,1967,1969],{},[90,1966,92],{},[90,1968,95],{},[90,1970,98,1971,102],{},[32,1972,101],{},[104,1974,1975,1989,2001],{},[87,1976,1977,1981,1987],{},[109,1978,1979],{},[32,1980,113],{},[109,1982,116,1983,120,1985,124],{},[51,1984,119],{},[51,1986,123],{},[109,1988,127],{},[87,1990,1991,1995,1999],{},[109,1992,1993,135],{},[32,1994,134],{},[109,1996,138,1997,142],{},[20,1998,141],{},[109,2000,145],{},[87,2002,2003,2007,2009],{},[109,2004,2005],{},[32,2006,152],{},[109,2008,155],{},[109,2010,158],{},[10,2012,161,2013,165],{},[32,2014,164],{},[63,2016,169],{"id":168},[10,2018,172,2019,176],{},[20,2020,175],{},[178,2022,181],{"id":180},[10,2024,184,2025,188,2027,192,2029,195,2031,199,2033,203],{},[51,2026,187],{},[51,2028,191],{},[51,2030,119],{},[32,2032,198],{},[51,2034,202],{},[10,2036,206],{},[178,2038,210],{"id":209},[10,2040,213],{},[71,2042,2043],{"className":216,"code":217,"language":218,"meta":79,"style":79},[51,2044,2045,2049,2059,2081,2087,2091,2101,2115,2121,2131,2137,2171,2205,2239,2261,2265,2269,2273,2305,2337,2369,2373,2379,2399,2403],{"__ignoreMap":79},[222,2046,2047],{"class":224,"line":225},[222,2048,229],{"class":228},[222,2050,2051,2053,2055,2057],{"class":224,"line":232},[222,2052,236],{"class":235},[222,2054,239],{"class":228},[222,2056,243],{"class":242},[222,2058,246],{"class":228},[222,2060,2061,2063,2065,2067,2069,2071,2073,2075,2077,2079],{"class":224,"line":249},[222,2062,252],{"class":235},[222,2064,239],{"class":228},[222,2066,257],{"class":242},[222,2068,260],{"class":235},[222,2070,263],{"class":242},[222,2072,266],{"class":235},[222,2074,269],{"class":242},[222,2076,266],{"class":235},[222,2078,274],{"class":242},[222,2080,246],{"class":228},[222,2082,2083,2085],{"class":224,"line":279},[222,2084,282],{"class":235},[222,2086,285],{"class":228},[222,2088,2089],{"class":224,"line":288},[222,2090,291],{"class":228},[222,2092,2093,2095,2097,2099],{"class":224,"line":294},[222,2094,297],{"class":235},[222,2096,239],{"class":228},[222,2098,302],{"class":242},[222,2100,246],{"class":228},[222,2102,2103,2105,2107,2109,2111,2113],{"class":224,"line":307},[222,2104,310],{"class":235},[222,2106,239],{"class":228},[222,2108,315],{"class":242},[222,2110,266],{"class":235},[222,2112,320],{"class":242},[222,2114,246],{"class":228},[222,2116,2117,2119],{"class":224,"line":325},[222,2118,328],{"class":235},[222,2120,331],{"class":228},[222,2122,2123,2125,2127,2129],{"class":224,"line":334},[222,2124,337],{"class":235},[222,2126,239],{"class":228},[222,2128,342],{"class":242},[222,2130,246],{"class":228},[222,2132,2133,2135],{"class":224,"line":347},[222,2134,350],{"class":235},[222,2136,331],{"class":228},[222,2138,2139,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161,2163,2165,2167,2169],{"class":224,"line":355},[222,2140,358],{"class":235},[222,2142,361],{"class":228},[222,2144,364],{"class":235},[222,2146,367],{"class":228},[222,2148,370],{"class":235},[222,2150,239],{"class":228},[222,2152,375],{"class":242},[222,2154,378],{"class":228},[222,2156,370],{"class":235},[222,2158,239],{"class":228},[222,2160,385],{"class":242},[222,2162,388],{"class":228},[222,2164,391],{"class":235},[222,2166,239],{"class":228},[222,2168,396],{"class":235},[222,2170,399],{"class":228},[222,2172,2173,2175,2177,2179,2181,2183,2185,2187,2189,2191,2193,2195,2197,2199,2201,2203],{"class":224,"line":402},[222,2174,405],{"class":235},[222,2176,408],{"class":228},[222,2178,364],{"class":235},[222,2180,367],{"class":228},[222,2182,370],{"class":235},[222,2184,239],{"class":228},[222,2186,375],{"class":242},[222,2188,378],{"class":228},[222,2190,370],{"class":235},[222,2192,239],{"class":228},[222,2194,385],{"class":242},[222,2196,388],{"class":228},[222,2198,391],{"class":235},[222,2200,239],{"class":228},[222,2202,396],{"class":235},[222,2204,399],{"class":228},[222,2206,2207,2209,2211,2213,2215,2217,2219,2221,2223,2225,2227,2229,2231,2233,2235,2237],{"class":224,"line":439},[222,2208,442],{"class":235},[222,2210,408],{"class":228},[222,2212,364],{"class":235},[222,2214,367],{"class":228},[222,2216,370],{"class":235},[222,2218,239],{"class":228},[222,2220,375],{"class":242},[222,2222,378],{"class":228},[222,2224,370],{"class":235},[222,2226,239],{"class":228},[222,2228,385],{"class":242},[222,2230,388],{"class":228},[222,2232,391],{"class":235},[222,2234,239],{"class":228},[222,2236,396],{"class":235},[222,2238,399],{"class":228},[222,2240,2241,2243,2245,2247,2249,2251,2253,2255,2257,2259],{"class":224,"line":475},[222,2242,478],{"class":235},[222,2244,408],{"class":228},[222,2246,370],{"class":235},[222,2248,239],{"class":228},[222,2250,487],{"class":242},[222,2252,490],{"class":228},[222,2254,391],{"class":235},[222,2256,239],{"class":228},[222,2258,497],{"class":235},[222,2260,500],{"class":228},[222,2262,2263],{"class":224,"line":503},[222,2264,506],{"class":228},[222,2266,2267],{"class":224,"line":509},[222,2268,512],{"class":228},[222,2270,2271],{"class":224,"line":515},[222,2272,518],{"class":228},[222,2274,2275,2277,2279,2281,2283,2285,2287,2289,2291,2293,2295,2297,2299,2301,2303],{"class":224,"line":521},[222,2276,524],{"class":228},[222,2278,527],{"class":235},[222,2280,239],{"class":228},[222,2282,532],{"class":242},[222,2284,490],{"class":228},[222,2286,537],{"class":235},[222,2288,239],{"class":228},[222,2290,542],{"class":242},[222,2292,490],{"class":228},[222,2294,547],{"class":235},[222,2296,408],{"class":228},[222,2298,542],{"class":235},[222,2300,239],{"class":228},[222,2302,542],{"class":242},[222,2304,558],{"class":228},[222,2306,2307,2309,2311,2313,2315,2317,2319,2321,2323,2325,2327,2329,2331,2333,2335],{"class":224,"line":561},[222,2308,524],{"class":228},[222,2310,527],{"class":235},[222,2312,239],{"class":228},[222,2314,570],{"class":242},[222,2316,490],{"class":228},[222,2318,537],{"class":235},[222,2320,239],{"class":228},[222,2322,542],{"class":242},[222,2324,490],{"class":228},[222,2326,547],{"class":235},[222,2328,408],{"class":228},[222,2330,542],{"class":235},[222,2332,239],{"class":228},[222,2334,542],{"class":242},[222,2336,558],{"class":228},[222,2338,2339,2341,2343,2345,2347,2349,2351,2353,2355,2357,2359,2361,2363,2365,2367],{"class":224,"line":595},[222,2340,524],{"class":228},[222,2342,527],{"class":235},[222,2344,239],{"class":228},[222,2346,604],{"class":242},[222,2348,490],{"class":228},[222,2350,537],{"class":235},[222,2352,239],{"class":228},[222,2354,542],{"class":242},[222,2356,490],{"class":228},[222,2358,547],{"class":235},[222,2360,408],{"class":228},[222,2362,542],{"class":235},[222,2364,239],{"class":228},[222,2366,542],{"class":242},[222,2368,627],{"class":228},[222,2370,2371],{"class":224,"line":630},[222,2372,633],{"class":228},[222,2374,2375,2377],{"class":224,"line":636},[222,2376,639],{"class":235},[222,2378,285],{"class":228},[222,2380,2381,2383,2385,2387,2389,2391,2393,2395,2397],{"class":224,"line":644},[222,2382,524],{"class":228},[222,2384,649],{"class":235},[222,2386,239],{"class":228},[222,2388,654],{"class":242},[222,2390,490],{"class":228},[222,2392,659],{"class":235},[222,2394,239],{"class":228},[222,2396,664],{"class":242},[222,2398,500],{"class":228},[222,2400,2401],{"class":224,"line":669},[222,2402,672],{"class":228},[222,2404,2405],{"class":224,"line":675},[222,2406,678],{"class":228},[10,2408,681],{},[10,2410,684],{},[25,2412,2413,2427,2433,2439],{},[28,2414,2415,699,2421,703,2423,707,2425,711],{},[32,2416,691,2417,695,2419],{},[51,2418,694],{},[51,2420,698],{},[51,2422,702],{},[51,2424,706],{},[51,2426,710],{},[28,2428,2429,717,2431,721],{},[32,2430,716],{},[51,2432,720],{},[28,2434,2435,731],{},[32,2436,726,2437,730],{},[51,2438,729],{},[28,2440,2441,737],{},[32,2442,736],{},[10,2444,740,2445,744,2447,748,2449,752],{},[32,2446,743],{},[20,2448,747],{},[32,2450,751],{},[178,2452,756],{"id":755},[10,2454,759],{},[71,2456,2457],{"className":216,"code":762,"language":218,"meta":79,"style":79},[51,2458,2459,2463,2473,2479,2499,2539,2579,2583],{"__ignoreMap":79},[222,2460,2461],{"class":224,"line":225},[222,2462,229],{"class":228},[222,2464,2465,2467,2469,2471],{"class":224,"line":232},[222,2466,773],{"class":235},[222,2468,239],{"class":228},[222,2470,778],{"class":242},[222,2472,246],{"class":228},[222,2474,2475,2477],{"class":224,"line":249},[222,2476,785],{"class":235},[222,2478,285],{"class":228},[222,2480,2481,2483,2485,2487,2489,2491,2493,2495,2497],{"class":224,"line":279},[222,2482,524],{"class":228},[222,2484,370],{"class":235},[222,2486,239],{"class":228},[222,2488,798],{"class":242},[222,2490,490],{"class":228},[222,2492,798],{"class":235},[222,2494,239],{"class":228},[222,2496,807],{"class":242},[222,2498,399],{"class":228},[222,2500,2501,2503,2505,2507,2509,2511,2513,2515,2517,2519,2521,2523,2525,2527,2529,2531,2533,2535,2537],{"class":224,"line":288},[222,2502,524],{"class":228},[222,2504,370],{"class":235},[222,2506,239],{"class":228},[222,2508,778],{"class":242},[222,2510,490],{"class":228},[222,2512,824],{"class":235},[222,2514,239],{"class":228},[222,2516,829],{"class":242},[222,2518,490],{"class":228},[222,2520,527],{"class":235},[222,2522,239],{"class":228},[222,2524,302],{"class":242},[222,2526,490],{"class":228},[222,2528,842],{"class":235},[222,2530,408],{"class":228},[222,2532,847],{"class":235},[222,2534,239],{"class":228},[222,2536,852],{"class":242},[222,2538,558],{"class":228},[222,2540,2541,2543,2545,2547,2549,2551,2553,2555,2557,2559,2561,2563,2565,2567,2569,2571,2573,2575,2577],{"class":224,"line":294},[222,2542,524],{"class":228},[222,2544,370],{"class":235},[222,2546,239],{"class":228},[222,2548,778],{"class":242},[222,2550,490],{"class":228},[222,2552,824],{"class":235},[222,2554,239],{"class":228},[222,2556,873],{"class":242},[222,2558,490],{"class":228},[222,2560,527],{"class":235},[222,2562,239],{"class":228},[222,2564,604],{"class":242},[222,2566,490],{"class":228},[222,2568,842],{"class":235},[222,2570,408],{"class":228},[222,2572,890],{"class":235},[222,2574,239],{"class":228},[222,2576,895],{"class":242},[222,2578,627],{"class":228},[222,2580,2581],{"class":224,"line":307},[222,2582,672],{"class":228},[222,2584,2585],{"class":224,"line":325},[222,2586,678],{"class":228},[10,2588,908,2589,912,2591,916],{},[51,2590,911],{},[32,2592,915],{},[178,2594,920],{"id":919},[10,2596,923,2597,926,2599,930,2601,933,2603,936,2605,176],{},[51,2598,720],{},[51,2600,929],{},[51,2602,123],{},[51,2604,53],{},[51,2606,939],{},[178,2608,943,2609],{"id":942},[32,2610,946],{},[10,2612,949,2613,953],{},[32,2614,952],{},[71,2616,2617],{"className":216,"code":956,"language":218,"meta":79,"style":79},[51,2618,2619,2623,2633,2643,2649,2669,2689,2693,2703,2709,2761,2821,2825,2829,2833],{"__ignoreMap":79},[222,2620,2621],{"class":224,"line":225},[222,2622,229],{"class":228},[222,2624,2625,2627,2629,2631],{"class":224,"line":232},[222,2626,252],{"class":235},[222,2628,239],{"class":228},[222,2630,971],{"class":242},[222,2632,246],{"class":228},[222,2634,2635,2637,2639,2641],{"class":224,"line":249},[222,2636,282],{"class":235},[222,2638,980],{"class":228},[222,2640,983],{"class":242},[222,2642,986],{"class":228},[222,2644,2645,2647],{"class":224,"line":279},[222,2646,639],{"class":235},[222,2648,285],{"class":228},[222,2650,2651,2653,2655,2657,2659,2661,2663,2665,2667],{"class":224,"line":288},[222,2652,524],{"class":228},[222,2654,649],{"class":235},[222,2656,239],{"class":228},[222,2658,654],{"class":242},[222,2660,490],{"class":228},[222,2662,659],{"class":235},[222,2664,239],{"class":228},[222,2666,664],{"class":242},[222,2668,399],{"class":228},[222,2670,2671,2673,2675,2677,2679,2681,2683,2685,2687],{"class":224,"line":294},[222,2672,524],{"class":228},[222,2674,649],{"class":235},[222,2676,239],{"class":228},[222,2678,1023],{"class":242},[222,2680,490],{"class":228},[222,2682,659],{"class":235},[222,2684,980],{"class":228},[222,2686,1032],{"class":242},[222,2688,1035],{"class":228},[222,2690,2691],{"class":224,"line":307},[222,2692,291],{"class":228},[222,2694,2695,2697,2699,2701],{"class":224,"line":325},[222,2696,1044],{"class":235},[222,2698,239],{"class":228},[222,2700,654],{"class":242},[222,2702,246],{"class":228},[222,2704,2705,2707],{"class":224,"line":334},[222,2706,1055],{"class":235},[222,2708,285],{"class":228},[222,2710,2711,2713,2715,2717,2719,2721,2723,2725,2727,2729,2731,2733,2735,2737,2739,2741,2743,2745,2747,2749,2751,2753,2755,2757,2759],{"class":224,"line":347},[222,2712,1062],{"class":228},[222,2714,370],{"class":235},[222,2716,239],{"class":228},[222,2718,1069],{"class":242},[222,2720,490],{"class":228},[222,2722,1074],{"class":235},[222,2724,239],{"class":228},[222,2726,829],{"class":242},[222,2728,490],{"class":228},[222,2730,659],{"class":235},[222,2732,239],{"class":228},[222,2734,1087],{"class":242},[222,2736,266],{"class":235},[222,2738,1092],{"class":235},[222,2740,1095],{"class":242},[222,2742,1098],{"class":235},[222,2744,1101],{"class":242},[222,2746,266],{"class":235},[222,2748,1092],{"class":235},[222,2750,1108],{"class":242},[222,2752,1098],{"class":235},[222,2754,1113],{"class":242},[222,2756,266],{"class":235},[222,2758,1118],{"class":242},[222,2760,399],{"class":228},[222,2762,2763,2765,2767,2769,2771,2773,2775,2777,2779,2781,2783,2785,2787,2789,2791,2793,2795,2797,2799,2801,2803,2805,2807,2809,2811,2813,2815,2817,2819],{"class":224,"line":355},[222,2764,1062],{"class":228},[222,2766,370],{"class":235},[222,2768,239],{"class":228},[222,2770,1069],{"class":242},[222,2772,490],{"class":228},[222,2774,1074],{"class":235},[222,2776,239],{"class":228},[222,2778,873],{"class":242},[222,2780,490],{"class":228},[222,2782,659],{"class":235},[222,2784,239],{"class":228},[222,2786,1087],{"class":242},[222,2788,266],{"class":235},[222,2790,1092],{"class":235},[222,2792,1153],{"class":242},[222,2794,1098],{"class":235},[222,2796,239],{"class":242},[222,2798,1098],{"class":235},[222,2800,1162],{"class":242},[222,2802,1098],{"class":235},[222,2804,1167],{"class":242},[222,2806,266],{"class":235},[222,2808,1092],{"class":235},[222,2810,1108],{"class":242},[222,2812,1098],{"class":235},[222,2814,1113],{"class":242},[222,2816,266],{"class":235},[222,2818,1118],{"class":242},[222,2820,500],{"class":228},[222,2822,2823],{"class":224,"line":402},[222,2824,1188],{"class":228},[222,2826,2827],{"class":224,"line":439},[222,2828,1193],{"class":228},[222,2830,2831],{"class":224,"line":475},[222,2832,672],{"class":228},[222,2834,2835],{"class":224,"line":503},[222,2836,678],{"class":228},[10,2838,1204,2839,1208,2841,1212,2843,1216,2845,1220],{},[51,2840,1207],{},[51,2842,1211],{},[51,2844,1215],{},[51,2846,1219],{},[10,2848,1223,2849,1227,2851,1231,2853,1235],{},[20,2850,1226],{},[51,2852,1230],{},[51,2854,1234],{},[63,2856,1239],{"id":1238},[10,2858,2859,1245],{},[32,2860,1244],{},[1247,2862,2863,2869,2873,2877],{},[28,2864,2865,1254,2867,1258],{},[32,2866,1253],{},[20,2868,1257],{},[28,2870,2871,1264],{},[32,2872,1263],{},[28,2874,2875,1270],{},[32,2876,1269],{},[28,2878,2879,1276],{},[32,2880,1275],{},[10,2882,1279],{},[25,2884,2885,2889,2899],{},[28,2886,2887,1287],{},[32,2888,1286],{},[28,2890,2891,1293,2893,1297,2895,1301,2897,1305],{},[32,2892,1292],{},[51,2894,1296],{},[51,2896,1300],{},[51,2898,1304],{},[28,2900,2901,1311],{},[32,2902,1310],{},[63,2904,1315],{"id":1314},[10,2906,2907,1321,2909,1324,2911,1328],{},[32,2908,1320],{},[51,2910,119],{},[51,2912,1327],{},[10,2914,1331,2915,1335],{},[32,2916,1334],{},[10,2918,2919,1341,2921,1345,2923,1349,2925,176],{},[32,2920,1340],{},[20,2922,1344],{},[51,2924,1348],{},[32,2926,1352],{},[10,2928,2929,1358,2931,1362,2933,1366],{},[32,2930,1357],{},[51,2932,1361],{},[32,2934,1365],{},[10,2936,2937,1372,2939,1376,2941,1379,2943,1383],{},[32,2938,1371],{},[51,2940,1375],{},[51,2942,1304],{},[51,2944,1382],{},[10,2946,2947,1389,2949,1393,2951,1397],{},[32,2948,1388],{},[20,2950,1392],{},[51,2952,1396],{},[63,2954,1401],{"id":1400},[10,2956,1404,2957,1407],{},[32,2958,101],{},[81,2960,2961,2969],{},[84,2962,2963],{},[87,2964,2965,2967],{},[90,2966,1416],{},[90,2968,1419],{},[104,2970,2971,2977,2985,2997,3003,3019],{},[87,2972,2973,2975],{},[109,2974,1426],{},[109,2976,1429],{},[87,2978,2979,2983],{},[109,2980,1434,2981],{},[51,2982,1437],{},[109,2984,1440],{},[87,2986,2987,2995],{},[109,2988,1445,2989,490,2991,490,2993,1455],{},[51,2990,1448],{},[51,2992,1451],{},[51,2994,1454],{},[109,2996,1458],{},[87,2998,2999,3001],{},[109,3000,1463],{},[109,3002,1466],{},[87,3004,3005,3013],{},[109,3006,1471,3007,490,3009,490,3011,1455],{},[51,3008,1474],{},[51,3010,1477],{},[51,3012,1480],{},[109,3014,1483,3015,1487,3017,1491],{},[51,3016,1486],{},[51,3018,1490],{},[87,3020,3021,3023],{},[109,3022,1496],{},[109,3024,1499],{},[10,3026,1502,3027,1505],{},[32,3028,141],{},[63,3030,1509],{"id":1508},[10,3032,1512,3033,1515,3035,1518,3037,1521],{},[51,3034,119],{},[51,3036,694],{},[51,3038,698],{},[71,3040,3041],{"className":1524,"code":1525,"language":1526,"meta":79,"style":79},[51,3042,3043,3049,3055,3059,3067,3071,3075,3099,3107,3139,3149,3153,3177,3181,3203,3231,3235,3245,3255],{"__ignoreMap":79},[222,3044,3045,3047],{"class":224,"line":225},[222,3046,1534],{"class":1533},[222,3048,1537],{"class":228},[222,3050,3051,3053],{"class":224,"line":232},[222,3052,1534],{"class":1533},[222,3054,1544],{"class":228},[222,3056,3057],{"class":224,"line":249},[222,3058,1550],{"emptyLinePlaceholder":1549},[222,3060,3061,3063,3065],{"class":224,"line":279},[222,3062,1555],{"class":228},[222,3064,1558],{"class":1533},[222,3066,1561],{"class":228},[222,3068,3069],{"class":224,"line":288},[222,3070,1550],{"emptyLinePlaceholder":1549},[222,3072,3073],{"class":224,"line":294},[222,3074,1571],{"class":1570},[222,3076,3077,3079,3081,3083,3085,3087,3089,3091,3093,3095,3097],{"class":224,"line":307},[222,3078,1576],{"class":228},[222,3080,1558],{"class":1533},[222,3082,1581],{"class":228},[222,3084,1584],{"class":235},[222,3086,1587],{"class":228},[222,3088,1590],{"class":242},[222,3090,1593],{"class":228},[222,3092,1596],{"class":242},[222,3094,1599],{"class":228},[222,3096,1602],{"class":242},[222,3098,1605],{"class":228},[222,3100,3101,3103,3105],{"class":224,"line":325},[222,3102,1610],{"class":228},[222,3104,1558],{"class":1533},[222,3106,1615],{"class":228},[222,3108,3109,3111,3113,3115,3117,3119,3121,3123,3125,3127,3129,3131,3133,3135,3137],{"class":224,"line":334},[222,3110,1620],{"class":228},[222,3112,527],{"class":242},[222,3114,1625],{"class":228},[222,3116,527],{"class":242},[222,3118,1630],{"class":228},[222,3120,537],{"class":242},[222,3122,1635],{"class":228},[222,3124,537],{"class":242},[222,3126,490],{"class":228},[222,3128,1642],{"class":242},[222,3130,1645],{"class":228},[222,3132,547],{"class":242},[222,3134,1625],{"class":228},[222,3136,1652],{"class":242},[222,3138,1655],{"class":228},[222,3140,3141,3143,3145,3147],{"class":224,"line":347},[222,3142,1660],{"class":1533},[222,3144,1663],{"class":228},[222,3146,1666],{"class":1533},[222,3148,1669],{"class":228},[222,3150,3151],{"class":224,"line":355},[222,3152,1605],{"class":228},[222,3154,3155,3157,3159,3161,3163,3165,3167,3169,3171,3173,3175],{"class":224,"line":402},[222,3156,1678],{"class":228},[222,3158,1558],{"class":1533},[222,3160,1683],{"class":228},[222,3162,649],{"class":242},[222,3164,239],{"class":228},[222,3166,654],{"class":242},[222,3168,490],{"class":228},[222,3170,659],{"class":242},[222,3172,239],{"class":228},[222,3174,664],{"class":242},[222,3176,1700],{"class":228},[222,3178,3179],{"class":224,"line":439},[222,3180,1550],{"emptyLinePlaceholder":1549},[222,3182,3183,3185,3187,3189,3191,3193,3195,3197,3199,3201],{"class":224,"line":475},[222,3184,1709],{"class":228},[222,3186,1558],{"class":1533},[222,3188,1714],{"class":228},[222,3190,1718],{"class":1717},[222,3192,1558],{"class":1533},[222,3194,243],{"class":242},[222,3196,490],{"class":228},[222,3198,1727],{"class":1717},[222,3200,1558],{"class":1533},[222,3202,1732],{"class":228},[222,3204,3205,3207,3209,3211,3213,3215,3217,3219,3221,3223,3225,3227,3229],{"class":224,"line":503},[222,3206,1737],{"class":228},[222,3208,1558],{"class":1533},[222,3210,1714],{"class":228},[222,3212,1718],{"class":1717},[222,3214,1558],{"class":1533},[222,3216,243],{"class":242},[222,3218,490],{"class":228},[222,3220,1727],{"class":1717},[222,3222,1558],{"class":1533},[222,3224,1756],{"class":228},[222,3226,1759],{"class":1717},[222,3228,1558],{"class":1533},[222,3230,1764],{"class":228},[222,3232,3233],{"class":224,"line":509},[222,3234,1550],{"emptyLinePlaceholder":1549},[222,3236,3237,3239,3241,3243],{"class":224,"line":515},[222,3238,1773],{"class":235},[222,3240,1587],{"class":228},[222,3242,1778],{"class":242},[222,3244,1781],{"class":228},[222,3246,3247,3249,3251,3253],{"class":224,"line":521},[222,3248,1773],{"class":235},[222,3250,1587],{"class":228},[222,3252,1790],{"class":242},[222,3254,1793],{"class":228},[222,3256,3257,3259,3261,3263,3265,3267,3269,3271],{"class":224,"line":561},[222,3258,1773],{"class":235},[222,3260,1587],{"class":228},[222,3262,1802],{"class":242},[222,3264,1805],{"class":228},[222,3266,1808],{"class":1533},[222,3268,1811],{"class":228},[222,3270,1814],{"class":242},[222,3272,1817],{"class":228},[10,3274,1587,3275,1823,3277,1827,3279,1831,3281,1835],{},[51,3276,1822],{},[51,3278,1826],{},[51,3280,1830],{},[51,3282,1834],{},[10,3284,1838,3285,1842],{},[32,3286,1841],{},[63,3288,1846],{"id":1845},[25,3290,3291,3295,3301,3305,3311],{},[28,3292,1851,3293,1855],{},[32,3294,1854],{},[28,3296,1858,3297,1861,3299,1865],{},[51,3298,729],{},[32,3300,1864],{},[28,3302,1868,3303,1871],{},[32,3304,1257],{},[28,3306,1874,3307,1878,3309,1882],{},[32,3308,1877],{},[32,3310,1881],{},[28,3312,1885],{},[1887,3314,1889],{},{"title":79,"searchDepth":232,"depth":232,"links":3316},[3317,3318,3325,3326,3327,3328,3329],{"id":65,"depth":232,"text":66},{"id":168,"depth":232,"text":169,"children":3319},[3320,3321,3322,3323,3324],{"id":180,"depth":249,"text":181},{"id":209,"depth":249,"text":210},{"id":755,"depth":249,"text":756},{"id":919,"depth":249,"text":920},{"id":942,"depth":249,"text":1900},{"id":1238,"depth":232,"text":1239},{"id":1314,"depth":232,"text":1315},{"id":1400,"depth":232,"text":1401},{"id":1508,"depth":232,"text":1509},{"id":1845,"depth":232,"text":1846},{},{"title":5,"description":1907},[1915,1916,1917],{"id":3334,"title":3335,"body":3336,"cover":3412,"date":3821,"description":3822,"draft":1908,"extension":1909,"lab":1908,"meta":3823,"navigation":1549,"original":1906,"path":3824,"seo":3825,"stem":3826,"tags":3827,"__hash__":3830},"writing_en\u002Fwriting\u002Fclaude-code-content-plan.md","Turning a 30-day content plan into draft articles with Claude Code",{"type":7,"value":3337,"toc":3809},[3338,3347,3350,3354,3357,3377,3384,3388,3395,3406,3413,3417,3428,3495,3498,3519,3523,3537,3607,3610,3614,3621,3627,3634,3637,3643,3647,3650,3653,3681,3685,3688,3691,3702,3713,3732,3735,3738,3763,3767,3787,3791,3794,3800,3806],[10,3339,3340,3346],{},[14,3341,3345],{"href":3342,"rel":3343},"https:\u002F\u002Fkatili.dev",[3344],"nofollow","katili.dev"," — my hosting and web-development studio — runs a bilingual blog. Each month I plan about 30 articles in a spreadsheet (title, description, category, language, reference links, and a ready-made prompt), import it into the Laravel admin panel, and work through it day by day.",[10,3348,3349],{},"Writing the articles was the slow part, and not because of the writing.",[63,3351,3353],{"id":3352},"the-copy-paste-loop","The copy-paste loop",[10,3355,3356],{},"The routine for every single article looked like this:",[1247,3358,3359,3362,3368,3371,3374],{},[28,3360,3361],{},"Open a Claude project whose instructions hold my writing guide (structure, tone, SEO fields, and the exact JSON shape my importer expects).",[28,3363,3364,3365,176],{},"Go back to the admin panel, find the day, press ",[32,3366,3367],{},"Copy Prompt",[28,3369,3370],{},"Switch tabs, open a new chat in the project, paste, wait.",[28,3372,3373],{},"Copy the JSON answer, go to the import page, paste it, import.",[28,3375,3376],{},"Go back to the plan and mark the day as done, then link it to the new post.",[10,3378,3379,3380,3383],{},"Five context switches per article, thirty articles a month. None of it was hard; all of it was friction. I wanted to type one thing and come back to drafts — ",[32,3381,3382],{},"without"," adding an AI API key to the server and paying per token on top of the subscription I already use every day.",[63,3385,3387],{"id":3386},"the-idea-let-claude-code-drive-keep-the-server-dumb","The idea: let Claude Code drive, keep the server dumb",[10,3389,3390,3391,3394],{},"Claude Code already runs in my terminal, inside the repository. It can run shell commands, fetch web pages, write files, and start subagents with a chosen model. So the server doesn't need to ",[20,3392,3393],{},"generate"," anything. It only needs to:",[25,3396,3397,3400,3403],{},[28,3398,3399],{},"tell Claude what is in the plan,",[28,3401,3402],{},"hand over one item's prompt,",[28,3404,3405],{},"accept the finished JSON and import it.",[10,3407,3408],{},[3409,3410],"img",{"alt":3411,"src":3412},"The flow: Claude Code calls a small API through a bash script; one subagent per article","\u002Fimages\u002Fwriting\u002Fclaude-code-content-plan\u002Fflow.svg",[178,3414,3416],{"id":3415},"_1-a-small-boring-api","1. A small, boring API",[10,3418,3419,3420,3423,3424,3427],{},"Five routes in ",[51,3421,3422],{},"routes\u002Fapi.php",", behind one middleware that compares a Bearer token with an environment variable using ",[51,3425,3426],{},"hash_equals",". No Sanctum, no users — it is a tool for one person.",[81,3429,3430,3440],{},[84,3431,3432],{},[87,3433,3434,3437],{},[90,3435,3436],{},"Endpoint",[90,3438,3439],{},"Purpose",[104,3441,3442,3452,3465,3475,3485],{},[87,3443,3444,3449],{},[109,3445,3446],{},[51,3447,3448],{},"GET \u002Fapi\u002Fcontent-plans",[109,3450,3451],{},"plans with done \u002F in progress \u002F to-do counts",[87,3453,3454,3459],{},[109,3455,3456],{},[51,3457,3458],{},"GET \u002Fapi\u002Fcontent-plans\u002F{plan}\u002Fitems",[109,3460,3461,3462,3464],{},"items ",[32,3463,3382],{}," their prompts",[87,3466,3467,3472],{},[109,3468,3469],{},[51,3470,3471],{},"GET \u002Fapi\u002Fcontent-plan-items\u002F{item}",[109,3473,3474],{},"one item with its full prompt and references",[87,3476,3477,3482],{},[109,3478,3479],{},[51,3480,3481],{},"PATCH \u002Fapi\u002Fcontent-plan-items\u002F{item}",[109,3483,3484],{},"change status",[87,3486,3487,3492],{},[109,3488,3489],{},[51,3490,3491],{},"POST \u002Fapi\u002Fcontent-plan-items\u002F{item}\u002Fimport",[109,3493,3494],{},"import the generated articles",[10,3496,3497],{},"Two decisions mattered more than the routes themselves:",[25,3499,3500,3506],{},[28,3501,3502,3505],{},[32,3503,3504],{},"An empty token switches the API off"," (403) instead of leaving it open. Forgetting to set an env var should never publish an import endpoint to the world.",[28,3507,3508,3515,3516,176],{},[32,3509,3510,3511,3514],{},"The import reuses the existing ",[51,3512,3513],{},"blog:import-json"," command"," — the same code path the admin page uses. The endpoint stores the JSON on the same disk, calls the command, then reads back the post IDs it wrote. There is still only one way an article enters the database, and every new post lands as a ",[32,3517,3518],{},"draft",[178,3520,3522],{"id":3521},"_2-a-bash-client-instead-of-a-smart-one","2. A bash client instead of a smart one",[10,3524,3525,3528,3529,3532,3533,3536],{},[51,3526,3527],{},"bin\u002Fcontent-plan"," is plain bash and ",[51,3530,3531],{},"curl"," — no ",[51,3534,3535],{},"jq",", nothing to install:",[71,3538,3542],{"className":3539,"code":3540,"language":3541,"meta":79,"style":79},"language-bash shiki shiki-themes github-light github-dark","bin\u002Fcontent-plan plans\nbin\u002Fcontent-plan items 1          # what is still to do\nbin\u002Fcontent-plan show 42          # the full prompt\nbin\u002Fcontent-plan check 42 a.json  # validate only (dry run)\nbin\u002Fcontent-plan import 42 a.json # draft posts, item marked done\n","bash",[51,3543,3544,3552,3565,3578,3593],{"__ignoreMap":79},[222,3545,3546,3549],{"class":224,"line":225},[222,3547,3527],{"class":3548},"sScJk",[222,3550,3551],{"class":242}," plans\n",[222,3553,3554,3556,3559,3562],{"class":224,"line":232},[222,3555,3527],{"class":3548},[222,3557,3558],{"class":242}," items",[222,3560,3561],{"class":235}," 1",[222,3563,3564],{"class":1570},"          # what is still to do\n",[222,3566,3567,3569,3572,3575],{"class":224,"line":249},[222,3568,3527],{"class":3548},[222,3570,3571],{"class":242}," show",[222,3573,3574],{"class":235}," 42",[222,3576,3577],{"class":1570},"          # the full prompt\n",[222,3579,3580,3582,3585,3587,3590],{"class":224,"line":279},[222,3581,3527],{"class":3548},[222,3583,3584],{"class":242}," check",[222,3586,3574],{"class":235},[222,3588,3589],{"class":242}," a.json",[222,3591,3592],{"class":1570},"  # validate only (dry run)\n",[222,3594,3595,3597,3600,3602,3604],{"class":224,"line":288},[222,3596,3527],{"class":3548},[222,3598,3599],{"class":242}," import",[222,3601,3574],{"class":235},[222,3603,3589],{"class":242},[222,3605,3606],{"class":1570}," # draft posts, item marked done\n",[10,3608,3609],{},"It is just as useful by hand as it is to Claude, which is a good sign the interface is right.",[178,3611,3613],{"id":3612},"_3-a-skill-and-one-subagent-per-article","3. A skill, and one subagent per article",[10,3615,3616,3617,3620],{},"A project skill (",[51,3618,3619],{},".claude\u002Fskills\u002Fgenerate-blog\u002FSKILL.md",") turns the whole loop into:",[71,3622,3625],{"className":3623,"code":3624,"language":76,"meta":79},[74],"\u002Fgenerate-blog 1 3,5,7-9 sonnet\n",[51,3626,3624],{"__ignoreMap":79},[10,3628,3629,3630,3633],{},"Plan 1, items 3, 5, 7, 8 and 9, written by Sonnet (the default is Opus). For each item the main session starts ",[32,3631,3632],{},"one subagent"," with the chosen model. The subagent reads the writing guide straight from the repository, asks the API for that item's prompt, fetches the reference links, writes the bilingual JSON, validates it with a dry run, fixes what the server complains about, and imports it.",[10,3635,3636],{},"Then it answers with a single line:",[71,3638,3641],{"className":3639,"code":3640,"language":76,"meta":79},[74],"OK 42 | Apa Itu Harness dalam AI Agent? | #101 (id), #102 (en) · draft\n",[51,3642,3640],{"__ignoreMap":79},[63,3644,3646],{"id":3645},"designing-for-tokens-not-just-for-features","Designing for tokens, not just for features",[10,3648,3649],{},"The interesting constraint wasn't functionality — it was context size. A naïve version would pull the 7.6 KB guide, thirty prompts, a dozen fetched web pages, and every finished article into one conversation. By article five the session would be slow and expensive; by article ten it would be forgetting the guide.",[10,3651,3652],{},"Three choices keep it lean:",[25,3654,3655,3669,3675],{},[28,3656,3657,3660,3661,3664,3665,3668],{},[32,3658,3659],{},"Text, not JSON, for anything a model reads."," Every ",[51,3662,3663],{},"GET"," accepts ",[51,3666,3667],{},"?format=text"," and returns a compact pipe-separated table. JSON repeats every key on every row; a model pays for each repetition.",[28,3670,3671,3674],{},[32,3672,3673],{},"Prompts only on demand."," The item list never includes prompts. Only the item being written fetches its prompt.",[28,3676,3677,3680],{},[32,3678,3679],{},"Subagents as a context firewall."," The guide, the references and the article itself live only inside the subagent's context and disappear when it finishes. The main session sees a table going in and one line per article coming out — so the tenth article costs about as much as the first.",[63,3682,3684],{"id":3683},"making-it-work-from-the-browser-too","Making it work from the browser too",[10,3686,3687],{},"I wanted the same command to work from Claude Code on the web, so I could start a batch from my phone. A cloud session has three differences from my laptop: the repository is a fresh clone (my local config file isn't there), outbound traffic goes through a network policy, and nobody is around to approve each command.",[10,3689,3690],{},"Configuration was easy — the script now reads environment variables first and the local file second, so the token can live in the cloud environment's settings.",[10,3692,3693,3694,3697,3698,3701],{},"The network part was more interesting. When I tried it, the session's proxy refused the connection to my domain with a ",[32,3695,3696],{},"403",". My API ",[20,3699,3700],{},"also"," answers 403 when it is switched off, and 401 for a wrong token. From the script's point of view, \"your token is wrong\" and \"you are not allowed to leave this sandbox\" looked the same, and the fixes are completely different.",[10,3703,3704,3705,3708,3709,3712],{},"The fix is a single response header. The middleware stamps ",[51,3706,3707],{},"X-Content-Plan-Api: 1"," on ",[32,3710,3711],{},"every"," response, including its own 401 and 403. The script checks for it:",[25,3714,3715,3722],{},[28,3716,3717,3718,3721],{},"header present → the API answered; exit code ",[32,3719,3720],{},"1"," with the API's own message;",[28,3723,3724,3725,1376,3728,3731],{},"header missing → something else answered (a proxy, the wrong host, a server that hasn't deployed the route yet); exit code ",[32,3726,3727],{},"2",[51,3729,3730],{},"NETWORK:"," prefix and a hint to allow the domain.",[10,3733,3734],{},"The skill reads those exit codes and tells me exactly which setting to change — and never asks me to paste a token into the chat.",[10,3736,3737],{},"Two smaller guards came from the same \"what if two of me run this?\" question:",[25,3739,3740,3754],{},[28,3741,3742,3745,3746,3749,3750,3753],{},[32,3743,3744],{},"A per-item lock on import."," A laptop session and a web session (or two parallel subagents) could both pass the \"does this item already have a post?\" check before either finishes. The import now takes a cache lock per item, re-reads the item inside it, and answers ",[32,3747,3748],{},"423"," to the loser. An item that already has a post gets ",[32,3751,3752],{},"409"," unless I explicitly force a re-import.",[28,3755,3756,1358,3759,3762],{},[32,3757,3758],{},"A non-interactive mode.",[51,3760,3761],{},"\u002Fgenerate-blog next 2"," takes the next two unfinished items without asking anything, so it can run on a schedule. The output is still drafts; publishing stays a human decision.",[63,3764,3766],{"id":3765},"what-i-deliberately-left-out","What I deliberately left out",[25,3768,3769,3775,3781],{},[28,3770,3771,3774],{},[32,3772,3773],{},"No AI calls on the server."," The server stores and imports; the writing happens in a tool I already pay for.",[28,3776,3777,3780],{},[32,3778,3779],{},"No auto-publishing."," Generated articles are drafts. I still read, edit and schedule each one.",[28,3782,3783,3786],{},[32,3784,3785],{},"No permission changes committed for me."," The allow-list that lets a cloud session run unattended is documented, not committed — that is a decision for the repository owner, not for the agent that wrote the feature.",[63,3788,3790],{"id":3789},"result","Result",[10,3792,3793],{},"The routine went from five tab switches per article to one line for a whole batch:",[71,3795,3798],{"className":3796,"code":3797,"language":76,"meta":79},[74],"\u002Fgenerate-blog next 3\n",[51,3799,3797],{"__ignoreMap":79},[10,3801,3802,3803,3805],{},"A few minutes later there are three bilingual drafts in the admin panel, linked to their days in the content-plan calendar, with the source JSON kept next to every other import. The whole feature is roughly 550 lines of PHP and bash plus one Markdown skill, covered by 14 feature tests — and most of the thinking went into what the model should ",[20,3804,101],{}," have to read.",[1887,3807,3808],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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);}",{"title":79,"searchDepth":232,"depth":232,"links":3810},[3811,3812,3817,3818,3819,3820],{"id":3352,"depth":232,"text":3353},{"id":3386,"depth":232,"text":3387,"children":3813},[3814,3815,3816],{"id":3415,"depth":249,"text":3416},{"id":3521,"depth":249,"text":3522},{"id":3612,"depth":249,"text":3613},{"id":3645,"depth":232,"text":3646},{"id":3683,"depth":232,"text":3684},{"id":3765,"depth":232,"text":3766},{"id":3789,"depth":232,"text":3790},"2026-10-03","How I replaced a copy-paste loop between browser tabs with one slash command — a tiny token-protected API, a bash client, and one subagent per article to keep the context small.",{},"\u002Fwriting\u002Fclaude-code-content-plan",{"title":3335,"description":3822},"writing\u002Fclaude-code-content-plan",[1915,1916,3828,3829],"Laravel","Claude Code","m3f9-6JomtmjiQ4j8g-SyMVe10IZIzla8LcMRx3RND4",{"id":3832,"title":3833,"body":3834,"cover":1906,"date":4088,"description":4089,"draft":1908,"extension":1909,"lab":1908,"meta":4090,"navigation":1549,"original":1906,"path":4091,"seo":4092,"stem":4093,"tags":4094,"__hash__":4097},"writing_en\u002Fwriting\u002Fbuilding-this-portfolio.md","Rebuilding my portfolio with Nuxt 4 and Nuxt Content",{"type":7,"value":3835,"toc":4082},[3836,3843,3850,3854,3857,4014,4025,4029,4032,4061,4065,4072,4076,4079],[10,3837,3838,3839,3842],{},"My old site was a Hugo theme with Bootstrap, a few inline scripts and a lot of ",[51,3840,3841],{},"!important"," for dark mode. It worked, but adding a project meant copying Markdown tables of images and hoping the layout held.",[10,3844,3845,3846,3849],{},"The goal of the rebuild: ",[32,3847,3848],{},"content separated from presentation",", and a site that is itself a portfolio piece.",[63,3851,3853],{"id":3852},"content-is-the-source-of-truth","Content is the source of truth",[10,3855,3856],{},"Every project is one Markdown file. Front-matter is validated with a schema, so a missing field fails the build instead of breaking a page.",[71,3858,3862],{"className":3859,"code":3860,"language":3861,"meta":79,"style":79},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F content.config.ts\nprojects: defineCollection({\n  type: 'page',\n  source: 'projects\u002F*.md',\n  schema: z.object({\n    category: z.string(),\n    year: z.number(),\n    role: z.string(),\n    featured: z.boolean().default(false),\n    metrics: z.array(z.object({ value: z.string(), label: z.string() })).default([]),\n    cover: z.string(),\n  }),\n}),\n","ts",[51,3863,3864,3869,3882,3892,3902,3912,3923,3933,3942,3964,3995,4004,4009],{"__ignoreMap":79},[222,3865,3866],{"class":224,"line":225},[222,3867,3868],{"class":1570},"\u002F\u002F content.config.ts\n",[222,3870,3871,3874,3876,3879],{"class":224,"line":232},[222,3872,3873],{"class":3548},"projects",[222,3875,239],{"class":228},[222,3877,3878],{"class":3548},"defineCollection",[222,3880,3881],{"class":228},"({\n",[222,3883,3884,3887,3890],{"class":224,"line":249},[222,3885,3886],{"class":228},"  type: ",[222,3888,3889],{"class":242},"'page'",[222,3891,246],{"class":228},[222,3893,3894,3897,3900],{"class":224,"line":279},[222,3895,3896],{"class":228},"  source: ",[222,3898,3899],{"class":242},"'projects\u002F*.md'",[222,3901,246],{"class":228},[222,3903,3904,3907,3910],{"class":224,"line":288},[222,3905,3906],{"class":228},"  schema: z.",[222,3908,3909],{"class":3548},"object",[222,3911,3881],{"class":228},[222,3913,3914,3917,3920],{"class":224,"line":294},[222,3915,3916],{"class":228},"    category: z.",[222,3918,3919],{"class":3548},"string",[222,3921,3922],{"class":228},"(),\n",[222,3924,3925,3928,3931],{"class":224,"line":307},[222,3926,3927],{"class":228},"    year: z.",[222,3929,3930],{"class":3548},"number",[222,3932,3922],{"class":228},[222,3934,3935,3938,3940],{"class":224,"line":325},[222,3936,3937],{"class":228},"    role: z.",[222,3939,3919],{"class":3548},[222,3941,3922],{"class":228},[222,3943,3944,3947,3950,3953,3956,3958,3961],{"class":224,"line":334},[222,3945,3946],{"class":228},"    featured: z.",[222,3948,3949],{"class":3548},"boolean",[222,3951,3952],{"class":228},"().",[222,3954,3955],{"class":3548},"default",[222,3957,1587],{"class":228},[222,3959,3960],{"class":235},"false",[222,3962,3963],{"class":228},"),\n",[222,3965,3966,3969,3972,3975,3977,3980,3982,3985,3987,3990,3992],{"class":224,"line":347},[222,3967,3968],{"class":228},"    metrics: z.",[222,3970,3971],{"class":3548},"array",[222,3973,3974],{"class":228},"(z.",[222,3976,3909],{"class":3548},[222,3978,3979],{"class":228},"({ value: z.",[222,3981,3919],{"class":3548},[222,3983,3984],{"class":228},"(), label: z.",[222,3986,3919],{"class":3548},[222,3988,3989],{"class":228},"() })).",[222,3991,3955],{"class":3548},[222,3993,3994],{"class":228},"([]),\n",[222,3996,3997,4000,4002],{"class":224,"line":355},[222,3998,3999],{"class":228},"    cover: z.",[222,4001,3919],{"class":3548},[222,4003,3922],{"class":228},[222,4005,4006],{"class":224,"line":402},[222,4007,4008],{"class":228},"  }),\n",[222,4010,4011],{"class":224,"line":439},[222,4012,4013],{"class":228},"}),\n",[10,4015,4016,4017,4020,4021,4024],{},"Adding ",[51,4018,4019],{},"content\u002Fprojects\u002Fmy-project.md"," creates ",[51,4022,4023],{},"\u002Fwork\u002Fmy-project"," — no component changes.",[63,4026,4028],{"id":4027},"components-inside-markdown","Components inside Markdown",[10,4030,4031],{},"Case studies use a few components directly from Markdown, for example an architecture explorer and animated metrics:",[71,4033,4036],{"className":4034,"code":4035,"language":1909,"meta":79,"style":79},"language-md shiki shiki-themes github-light github-dark","::architecture-explorer{:nodes=\"architecture\"}\n::\n\n::metric-grid{:metrics=\"metrics\"}\n::\n",[51,4037,4038,4043,4048,4052,4057],{"__ignoreMap":79},[222,4039,4040],{"class":224,"line":225},[222,4041,4042],{},"::architecture-explorer{:nodes=\"architecture\"}\n",[222,4044,4045],{"class":224,"line":232},[222,4046,4047],{},"::\n",[222,4049,4050],{"class":224,"line":249},[222,4051,1550],{"emptyLinePlaceholder":1549},[222,4053,4054],{"class":224,"line":279},[222,4055,4056],{},"::metric-grid{:metrics=\"metrics\"}\n",[222,4058,4059],{"class":224,"line":288},[222,4060,4047],{},[63,4062,4064],{"id":4063},"motion-but-only-when-it-helps","Motion, but only when it helps",[10,4066,4067,4068,4071],{},"One animation library (GSAP), loaded on the client only. Scroll reveals and counters respect ",[51,4069,4070],{},"prefers-reduced-motion","; when it is set, everything is simply visible.",[63,4073,4075],{"id":4074},"static-by-default","Static by default",[10,4077,4078],{},"Every page is prerendered, images are optimised at build time, and the whole site deploys to GitHub Pages as static files.",[1887,4080,4081],{},"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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":79,"searchDepth":232,"depth":232,"links":4083},[4084,4085,4086,4087],{"id":3852,"depth":232,"text":3853},{"id":4027,"depth":232,"text":4028},{"id":4063,"depth":232,"text":4064},{"id":4074,"depth":232,"text":4075},"2026-09-29","Why I moved from a Hugo theme to Nuxt, and how content, images and motion are organised so adding a project is one Markdown file.",{},"\u002Fwriting\u002Fbuilding-this-portfolio",{"title":3833,"description":4089},"writing\u002Fbuilding-this-portfolio",[1915,4095,4096],"Nuxt","Design","Ezw17Ahqaoov-kQxpTfD84HPEd-JfG7WtYWnCBOnsSo",{"id":4099,"title":4100,"body":4101,"cover":4108,"date":4117,"description":4118,"draft":1908,"extension":1909,"lab":1908,"meta":4119,"navigation":1549,"original":1477,"path":4120,"seo":4121,"stem":4122,"tags":4123,"__hash__":4126},"writing_en\u002Fwriting\u002Fanak-anak-masjid.md","The children of Umar Bin Khattab Bypass Mosque",{"type":7,"value":4102,"toc":4115},[4103,4109,4112],[10,4104,4105],{},[3409,4106],{"alt":4107,"src":4108},"Children at the mosque","\u002Fimages\u002Fwriting\u002Fanak-anak-masjid\u002Fcover.png",[10,4110,4111],{},"We had just finished Friday prayers at the Umar Bin Khattab mosque on the Bypass road. We sat for a while to rest, waiting for a cloud to drift across the sky and shield us from the Gorontalo sun — so hot that, as people here like to say, this town has two suns, haha.",[10,4113,4114],{},"Then the children around us caught our attention. At first I thought they were playing, but they were actually helping to tidy up the mosque's carpets after the congregation had finished praying. I saw their small faces light up when the mosque caretaker handed each of them 2,000 rupiah. Their innocent smiles spread happiness all around. It's a sight you rarely see, so I decided to capture the moment.",{"title":79,"searchDepth":232,"depth":232,"links":4116},[],"2022-05-24","A small note after Friday prayers — about the smiles of the children who tidy up the mosque's carpets.",{},"\u002Fwriting\u002Fanak-anak-masjid",{"title":4100,"description":4118},"writing\u002Fanak-anak-masjid",[4124,4125],"Personal","Story","Y5xmNiK3kFwWnoLhtAfxl1ivtLbEcH4iq2K-HogYU1M",[],1791260767582]