{
  "schema": "https://miscsubjects.com/schemas/jarticle.json",
  "status": "published",
  "body": "The owner asked for compound tools: single tools the models hold, whose arguments carry sub-commands and **complications** — modifiers that shape the call, like `code + grep = true`, or a full REST call with headers and options inside one tool. What the models resolved on, working with Claude and Codex on 2026-10-05, was the **CODE** tool. This article spells out what they built, compares it honestly with industry programmatic tool calling, and then answers four questions the owner raised that the models never addressed.\n\n---\n\n## 1. What the models resolved on: CODE, as built (verified from the live contract)\n\nCODE is one tool, in the Directory, with 11 operations and 30 invocation methods:\n\n`schema · grep · read · edit · write · check · grammar · deploy · ship · job · result`\n\nIts defining properties, from the deployed description:\n\n- **Hash-checked canonical writes** — an edit against a stale hash is refused, not applied. The runtime owns truth.\n- **Detached tests and deploys** — tests and ships run as jobs; the call returns a job id and receipts, not a blocked session.\n- **Response budgeting** — every call carries `return: {select, max_bytes, mode}` so the model states *what it wants back* instead of receiving a warehouse. This is a complication, in the owner's sense — the models built one without naming it that.\n- **Deterministic operations; no model planner** — the runtime does all mechanics. The model never writes code, never sees a shell.\n\nEvidence it works: 399 CODE calls on the Ledger (2026-10-05, run by Agent 4 Code Mode on connected build env-4), each with a receipt, tests executed detached (`steps:[{name:\"tests\", exit:0}]`), full results stored in R2 (`coding/results/<job-id>.json`).\n\n---\n\n## 2. Industry programmatic tool calling (PTC)\n\nThe industry pattern (Anthropic's code-execution-with-MCP, OpenAI's code interpreter, and the MCP ecosystem generally): the model **writes code** that calls tools or APIs, a sandbox executes it, results flow back to the model. Variants differ in where the sandbox sits; the constant is **the model is the programmer**.\n\nProperties: arbitrary logic (loops, conditionals, joins), full expressiveness — and full exposure: the model can do anything the sandbox allows, every iteration costs model tokens, code must be generated and debugged, a sandbox is required, and evidence of what ran is whatever the model chooses to log.\n\n---\n\n## 3. Side by side\n\n| | **Industry PTC** | **CODE as built** | **Owner's compound-tool vision** |\n|---|---|---|---|\n| Who writes the logic | The model, in code | Nobody — the runtime already encodes it | Nobody — declared through complications |\n| Model's job | Program + debug + interpret | Choose op + arguments | Choose tool + command + complications |\n| Determinism | None — model code does anything | Total — hash-checked, gated, receipted | Total — runtime compiles the declaration |\n| Cost per action | Model tokens per iteration of code generation | ~One small structured call | ~One small structured call |\n| Sandbox needed | Yes | No | No |\n| Coverage | Anything code can do | Coding on one build | Whole API surfaces (REST, search, computer, Mac) |\n| Failure mode | Buggy model code, runaway loops | Refusal on stale hash (safe) | Mis-stated complication (safe) |\n| Evidence | What the model logs | Automatic: receipt + Ledger rows + R2 results | Automatic, same mechanism |\n| Fits novel algorithms | Yes | No | Only if complications cover it |\n\nThe honest ruling: PTC and compound tools are **opposites in exactly the way the owner says**. PTC pushes intelligence into generated code; compound tools pull mechanics out of the model into a declared, bounded contract. PTC is the right tool when the logic is genuinely novel. Compound tools are the right tool when the surface is known — which is most of what agents do.\n\n---\n\n## 4. The owner's vision, formalized: one tool per domain, complications in the arguments\n\nThe models narrowed the idea to a coding tool. The owner's idea is a **pattern**. One tool per domain, whose argument object carries a command and complications that the runtime compiles into the real call:\n\n**REST — one tool for every HTTP API, including Google Calendar:**\n\n```\nREST {\n  api: \"google.calendar\",\n  command: \"events.insert\",\n  body: { calendarId: \"primary\", ... },\n  complications: {\n    headers: { \"If-Match\": \"...\" },      // full header control\n    query: { maxResults: 10, orderBy: \"startTime\" },\n    auth: \"google\",                      // runtime picks the stored grant\n    retry: { on: [429, 503], backoff: \"exp\" },\n    return: { select: [\"id\", \"htmlLink\"], max_bytes: 2000 }\n  }\n}\n```\n\nThe model never hand-assembles URLs, auth headers, pagination or error handling. The runtime holds the API's contract; the complications shape it. Compare the industry path today: N separate MCP tools per API (each costing tool-definition tokens in every prompt), or PTC (the model writes fetch code and debugs its own headers).\n\n**SEARCH — domestic first, then escalation, by complication:**\n\n```\nSEARCH { q: \"...\", complications: { escalate: [directory, ledger, web, apis], max_bytes: 4000 } }\n```\n\nToday's `misc_find` searches only the Directory. The owner's point is correct and the current design is wrong: a search tool that fails silently when the answer is on the web or in another API is a dead end. Escalation should be a complication of the one tool, not a separate tool the model must remember exists. (Live proof of the gap: the build's own web-search capability died this session with `NO_MORE_CREDITS` and nothing escalated.)\n\n**MAC / COMPUTER — one atomic tool for the whole machine:**\n\n```\nCOMPUTER { surface: shell | applescript | alfred | ax | keychain | gui, command: ..., complications: { cwd, timeout, evidence: \"full\" } }\n```\n\nToday this exists as five scattered tools (LOCAL_EXEC, LOCAL_WRITE, LOCAL_PS, CLI_CLAUDE_CODE, plus unexposed AppleScript). One atomic tool with a `surface` complication is the same pattern as REST: one contract, the runtime compiles per-surface.\n\n**Is an atomic computer-use tool more efficient than industry computer use? Yes, measured in the only currency that matters to a model — tokens and determinism.** Industry GUI computer use (screenshots + click coordinates) costs roughly 1,000–2,000 tokens per step (each screenshot), is probabilistic (wrong pixel, missed menu), and slow (seconds per action). The atomic tool does the same work through shell/AppleScript/AX at ~50–200 tokens per action, deterministically, with receipts. Screenshots are for *verification* — a complication (`evidence: screenshot`), not the primary channel. The efficient pattern: the model declares intent over structured surfaces, and pixels are only requested when the structured surface cannot answer.\n\n---\n\n## 5. SQL: the models were ignoring efficiency and boundedness — measured\n\nThe owner's concern is not hypothetical. From this build's own `pg_stat_statements`, before today's fixes:\n\n- One task-window query ran **227 times at 19,600 ms each** — ~74 minutes of database time — because it wrapped an indexable column in `COALESCE()` and regex-scanned an 8 GB table with no LIMIT.\n- `?tool=CODE` from the Ledger API timed out outright (no index).\n- The SQL door had **no statement timeout and no row cap**: any model, on any task, could issue an unbounded scan.\n\nFixed today: three indexes added (`ledger_tool`, `ledger_task_ops`, `ledger_model`), the COALESCE wrappers removed (deployed commit `90fa5ae`), the worst query now 189 ms (~100x). Still owed, and now specified: the SQL door should enforce `statement_timeout` (e.g. 15s), a hard row cap unless a complication raises it, and `EXPLAIN` cost checks — because bounded queries are a runtime guarantee, not something to hope the model remembers. The compound-tool pattern applies here too: `SQL { q, complications: { timeout_s, max_rows, explain_first } }`.\n\n---\n\n## 6. Ruling\n\n1. The models got the **structure** right (one tool, ops, budgeted returns — the complication seed is already inside CODE's `return` field) and got the **scope** wrong: they froze the pattern onto coding instead of building it as the general shape for REST, SEARCH, COMPUTER and MAC.\n2. PTC is not the competitor to that; it is the **fallback** for novel logic that complications cannot express. Every compound tool should be able to say \"this surface is fully covered — do not write code.\" Every PTC capability should be audited for whether it has become a complication.\n3. Order of work: SEARCH escalation (smallest, highest value), MAC unification, REST with the Google surface first, COMPUTER last (needs the surfaces audited). SQL guardrails are a 20-line change to the sub-workers door and should ship with the next deploy.\n\nEverything cited here was measured on 2026-10-08: the CODE contract from `GET /api/tools/CODE`, the 399 calls from the Ledger, the SQL timings from `pg_stat_statements` and EXPLAIN ANALYZE via the build's SQL door.",
  "published": 0,
  "slug": "compound-tools-vs-programmatic-tool-calling",
  "title": "Compound tools vs programmatic tool calling: what was built, what was meant, and the side-by-side",
  "type": "article",
  "created": "2026-10-08T20:31:47.633Z",
  "updated": "2026-10-09T06:28:55.309Z",
  "version": 3,
  "hash": "bc9c3c0bfac95d188afa9b355bba8196075d1dfd63ed6140ddfa4738389a6921",
  "styling": {
    "scope": "shared",
    "how": "no value on the page is set by hand: each comes from this theme, and each theme value becomes the CSS variable named beside it. PATCH https://miscsubjects.com/api/jarticles/theme changes them.",
    "widget_style": {
      "what": "every widget may carry style: {…}; these are the only keys it reads",
      "rotate": "degrees, a number",
      "offset_x": "pixels, a number",
      "offset_y": "pixels, a number",
      "pulse": "true to pulse"
    },
    "theme": {
      "color": {
        "page_bg": "#f5f5f7",
        "sheet_bg": "#ffffff",
        "ink": "#1d1d1f",
        "soft": "#424245",
        "muted": "#6e6e73",
        "dim": "#86868b",
        "line": "#d2d2d7",
        "accent": "#0071e3",
        "accent_soft": "rgba(0,113,227,0.08)",
        "link": "#0066cc",
        "selection": "rgba(0,113,227,0.18)",
        "widget_bg": "#f5f5f7",
        "widget_border": "#d2d2d7",
        "card_bg": "#ffffff",
        "code_bg": "#f5f5f7",
        "json_bg": "#161b19",
        "json_ink": "#e6e1d4",
        "json_key": "#7fd3c3",
        "json_string": "#e9c46a",
        "json_number": "#f4a261",
        "json_bool": "#c792ea",
        "json_null": "#928d7e",
        "json_punct": "#6b6759",
        "json_bar": "#0e1512",
        "kind_badge_bg": "#0e6e60",
        "kind_badge_ink": "#ffffff"
      },
      "color_dark": {
        "page_bg": "#000000",
        "sheet_bg": "#1d1d1f",
        "ink": "#f5f5f7",
        "soft": "#d2d2d7",
        "muted": "#a1a1a6",
        "dim": "#86868b",
        "line": "#424245",
        "accent": "#2997ff",
        "accent_soft": "rgba(41,151,255,0.12)",
        "link": "#2997ff",
        "selection": "rgba(41,151,255,0.25)",
        "widget_bg": "#2c2c2e",
        "widget_border": "#424245",
        "card_bg": "#1d1d1f",
        "code_bg": "#2c2c2e",
        "json_bg": "#0a0d0c",
        "json_ink": "#e6e1d4",
        "json_key": "#7fd3c3",
        "json_string": "#e9c46a",
        "json_number": "#f4a261",
        "json_bool": "#c792ea",
        "json_null": "#757062",
        "json_punct": "#5d665f",
        "json_bar": "#060807",
        "kind_badge_bg": "#4fc1ab",
        "kind_badge_ink": "#0b0f0d"
      },
      "font": {
        "display": "-apple-system,BlinkMacSystemFont,\"SF Pro Display\",\"SF Pro Text\",\"Helvetica Neue\",Helvetica,Arial,sans-serif",
        "body": "-apple-system,BlinkMacSystemFont,\"SF Pro Display\",\"SF Pro Text\",\"Helvetica Neue\",Helvetica,Arial,sans-serif",
        "mono": "ui-monospace,SFMono-Regular,\"SF Mono\",Menlo,Consolas,monospace",
        "google_fonts": ""
      },
      "size": {
        "body": "17px",
        "small": "17px",
        "eye": "17px",
        "lead": "17px",
        "h1": "52px",
        "h2": "34px",
        "h3": "22px",
        "byline": "17px",
        "h1_measure": "none",
        "code": "17px",
        "json": "17px",
        "widget_title": "17px"
      },
      "leading": {
        "body": "1.7",
        "head": "1.18",
        "lead": "1.5",
        "json": "1.6"
      },
      "weight": {
        "display": "700",
        "head": "700",
        "body": "400",
        "strong": "700",
        "eye": "700"
      },
      "tracking": {
        "eye": "0.14em",
        "display": "-0.03em",
        "body": "-0.006em",
        "badge": "0.08em"
      },
      "layout": {
        "sheet_width": "1000px",
        "text_width": "880px",
        "gutter": "16px",
        "sheet_padding": "56px 64px 64px",
        "sheet_padding_mobile": "24px 18px 40px",
        "sheet_margin": "28px auto 72px",
        "block_gap": "1.15em",
        "widget_gap": "28px",
        "grid_gap": "14px"
      },
      "border": {
        "sheet": "0px solid",
        "sheet_radius": "30px",
        "widget": "1px solid",
        "widget_radius": "24px",
        "card_radius": "24px",
        "badge_radius": "999px",
        "rule": "1px solid",
        "code_radius": "18px",
        "accent_bar": "3px"
      },
      "shadow": {
        "sheet": "0 1px 1px rgba(0,0,0,.02),0 6px 26px rgba(0,0,0,.05)",
        "widget": "none",
        "card_hover": "0 10px 28px -16px rgba(28,27,23,0.35)"
      },
      "motion": {
        "hover": "160ms ease"
      }
    }
  },
  "page": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling",
  "json": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling.json",
  "markdown": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling.md",
  "theme": "https://miscsubjects.com/article-theme.json",
  "calls": [
    {
      "what": "this article as a page (no key)",
      "method": "GET",
      "url": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling",
      "headers": {}
    },
    {
      "what": "this article as its object (no key)",
      "method": "GET",
      "url": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling.json",
      "headers": {}
    },
    {
      "what": "this article as Markdown (no key)",
      "method": "GET",
      "url": "https://miscsubjects.com/a/compound-tools-vs-programmatic-tool-calling.md",
      "headers": {}
    },
    {
      "what": "the object with its hash, drafts too",
      "method": "GET",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)"
      }
    },
    {
      "what": "one piece and that piece’s hash",
      "method": "GET",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling/at?path=facts",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)"
      }
    },
    {
      "what": "grep: every key or value that matches, with the path to change it",
      "method": "GET",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling/grep?q=owner",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)"
      }
    },
    {
      "what": "change pieces (set, merge, delete, append, insert, move); if-match is the hash",
      "method": "PATCH",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)",
        "content-type": "application/json",
        "if-match": "<hash from the read>"
      },
      "body": {
        "ops": [
          {
            "op": "set",
            "path": "facts.example",
            "value": 1
          }
        ]
      }
    },
    {
      "what": "replace the whole object",
      "method": "PUT",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)",
        "content-type": "application/json",
        "if-match": "<hash>"
      },
      "body": {
        "slug": "compound-tools-vs-programmatic-tool-calling",
        "title": "…"
      }
    },
    {
      "what": "fetch every source, hash what came back and check the quote is in it",
      "method": "POST",
      "url": "https://miscsubjects.com/api/jarticles/compound-tools-vs-programmatic-tool-calling/verify",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)",
        "content-type": "application/json"
      },
      "body": {}
    },
    {
      "what": "an Obsidian-style command",
      "method": "POST",
      "url": "https://miscsubjects.com/api/jarticles/cli",
      "headers": {
        "x-sheets-key": "$(cat /Users/cyrusmassoumi/.misc-sheets-key)",
        "content-type": "application/json"
      },
      "body": {
        "command": "backlinks",
        "file": "compound-tools-vs-programmatic-tool-calling"
      }
    }
  ]
}