Skip to content

Contract: serve the Swift declarations, and generate /tools from them (#237) - #253

Merged
iamnbutler merged 3 commits into
mainfrom
contract-swift-source
Nov 13, 2026
Merged

iamnbutler merged 3 commits into
mainfrom
contract-swift-source

Conversation

@iamnbutler

Copy link
Copy Markdown
Contributor

Step 2 of the plan in #237 (#237 (comment)). The tool contract's source moves from src/tools.ts into Swift.

Swift

  • Contract reads the declarations in ContractTools.swift (from Contract: declare the tools in Swift, checked against the generated contract (#237) #252). ContractText.swift is deleted.
  • Contract.actions, which the MCP server's queue, Admission and Hooks use, comes from each tool's action flag.
  • Tools.expectTools becomes Contract.expecting: the tools whose schema takes expect. Adding expect to a tool is now one change.
  • Tools.actionTools (bad argument → refused action) stays hand-written. It deliberately differs from Contract.actions, and a comment now names how.
  • desktop-tools-mcp --contract prints the declarations as JSON, with {{place}} and {{app}} marking what embedders name.

npm package

  • scripts/contract.mjs (npm run contract) builds desktop-tools-mcp, runs it with --contract, and writes src/contract.ts. --check fails when the file is stale. CI moves that check to the macOS job, since it needs Swift.
  • src/tools.ts is now a thin wrapper over contract.ts, with the same exports. /protocol's DESKTOP_KEYS, DESKTOP_SYSTEM_KEYS, DESKTOP_WAIT_CONDITIONS, DESKTOP_EXPECT_OPS and isDesktopAction come from it too.
  • Type-level checks make tsc fail if the hand-written DesktopRequest ops or DesktopAction ops drift from the declared tools. Checked by removing "dock" from DesktopAction.
  • desktopRequest no longer checks the exclusive forms of desktop_clipboard_write and desktop_dialog_answer. The host refuses them with the same text (TextClipboard.swift, Dialogs.swift). The user approved this in Remove Node from the MCP path: make the app's Swift server the only server and the contract's source #237.

Verified to be the same as before

  • The built server's initialize instructions and tools/list equal main's ContractText.swift exactly.
  • Everything /tools and /protocol export (desktopTools for this Mac/Desktop Tools and for Ace's place and app, desktopToolRules, every constant, isDesktopAction and isDesktopManagement for every op) is identical to main's dist output. The one exception is that DESKTOP_EXPECT_OPS now lists its ops in tool order.

Checks run: swift test --package-path native2 (all pass), npm run check, npm test, node scripts/contract.mjs --check.

Docs: AGENTS.md, native2/README.md, docs/tools.md, docs/mcp.md, CHANGELOG (Unreleased). Lane notes on src/tools.ts and src/mcp.ts are replaced or retired.

🤖 Generated with Claude Code

iamnbutler and others added 3 commits November 12, 2026 20:12
…#237)

The tool contract's source moves from src/tools.ts into native2's ContractTools.swift. The MCP server, the
host's action and expect sets read the declarations; ContractText.swift and the Node-to-Swift generation go.
desktop-tools-mcp --contract exports the declarations with {{place}} and {{app}} marking what embedders name,
and scripts/contract.mjs (npm run contract) writes that into src/contract.ts, which /tools and /protocol's key
and wait-condition lists read. CI checks it on the macOS job. The /tools and /protocol exports are the same values
as before, except DESKTOP_EXPECT_OPS's order; desktopRequest leaves the exclusive argument forms to the host, which
refuses them with the same text. Type assertions keep the hand-written request types' ops and actions equal to
the declared tools'.

Why: native2/Sources/DesktopProtocol/ContractTools.swift | src/contract.ts is generated from this file by npm run contract; CI's native job fails when it is stale, so regenerate after every change here
Why: src/protocol.ts | DesktopRequest and DesktopAction are hand-written but must name exactly the declared tools' ops and actions; the Assert types make tsc fail when they drift

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@iamnbutler
iamnbutler merged commit efcdb93 into main Nov 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant