agentleFS
pdparchitectpdparchitect/noodle/Tools/AGENTS.md

noodle / Tools

AGENTS.md259 starsChanged 35 days agoApache-2.0View on GitHub

The tools Noodle gives its bots. Each folder here is one bundled ExtensionKit extension that Noodle discovers at launch; nothing in the app names them. Tools/Calendar and Tools/Reminders are the exceptions: they have no extension. macOS grants this access to the app a person sees and never to a background extension, which was measured before the tools were written, so their providers are ToolProviderKind.builtIn and run inside Noodle. Build a tool this way only when a permission makes an extension…

The file

We split this AGENTS.md into the rules it gives an agent

6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before an action that cannot be undone, call context.authorize.

    line 63
  2. Very specific:

    Create Tools/NAME in the layout above.

    line 72
  3. Very specific:

    Add tool("NAME") at the end of Package.swift.

    line 73
  4. Very specific:

    If it follows an assignment, publish that assignment from NoodleStore with toolAssignments.replace(KIND, with:).

    line 76
  5. Distinctive:

    Write the test first and see it fail.

    line 86
  6. Very specific:

    Before calling a change done, run all of swift test, then scripts/build-and-launch.sh and scripts/verify-tool-extensions.sh on the bundle.

    line 87

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Tools

The tools Noodle gives its bots. Each folder here is one bundled ExtensionKit extension that Noodle discovers at launch; nothing in the app names them.

Tools/Calendar and Tools/Reminders are the exceptions: they have no extension. macOS grants this access to the app a person sees and never to a background extension, which was measured before the tools were written, so their providers are ToolProviderKind.builtIn and run inside Noodle. Build a tool this way only when a permission makes an extension impossible; the extension is the default, and the provider contract is the same. Both share EventKitAssignments in NoodleCore and one EventKitController in Sources/Noodle, so a third EventKit tool adds a kind, not a copy.

Tools/Applet is built in too: Noodle Applet trusts only Noodle's and Noodle Hub's signed identities to name the bot a request is for, so its provider runs inside them and reaches Applet through AppletController. Noodle grants it to every bot while Applet is installed.

Tools/Browser and Tools/Computer are the bot-facing tools. The apps they drive live in /Browser and /Computer and are separate products with their own versions and changelogs. A change here ships with Noodle and goes in the root CHANGELOG.md.

Layout

Tools/NAME/
  Sources/NoodleNAMETools/            the provider: tools, schemas, guidance
  Sources/NoodleNAMEToolsExtension/   the .appex shell, a few lines
  Tests/NoodleNAMEToolsTests/
  Info.plist                          the .appex Info.plist
  Extension.entitlements              what the .appex is signed with; App Sandbox alone unless there is a reason

A built-in tool has only Sources/NoodleNAMETools and Tests/NoodleNAMEToolsTests, registered with builtInTool("NAME") in Package.swift. Its EventKit-style access to the Mac, and the entitlement and usage string that go with it, belong to the app, and its controller lives in Sources/Noodle like the other assignment controllers.

Where the framework is

The contract and the host are in Sources/NoodleCore, not here:

  • ToolProviders.swift: ToolProvider, ToolProviderManifest, ToolActivation and the schema conventions below. Read its doc comments first.
  • ToolExtension.swift: ToolExtensionService, which an extension hands its provider to.
  • ToolBroker.swift: every check made around a call.
  • ToolProviderSkills.swift: writes each bot's skill from the manifest and the tool list.
  • Sources/Noodle/ToolExtensionDiscovery.swift: finds the bundled extensions.

Bots reach every tool through messenger tool PROVIDER TOOL. There is no per-tool CLI and there must not be one.

Rules

  • A provider returns MCP-shaped JSON: a tools/list result and tools/call results.
  • The provider never authorizes. It declares, the broker enforces:
    • "format": "noodle-resource" with "noodle/kind" on a parameter that names a browser, computer or other assigned thing. The broker refuses values the bot was not assigned.
    • "format": "noodle-file" with "noodle/access" read or write for a workspace path. The provider gets an open handle, never a path. folder opens an existing folder, for an app that reads it where it is.
    • "format": "noodle-conversation" for a conversation the bot must belong to. A call that names one is withheld if the bot leaves it before the result.
    • "format": "noodle-conversation-link" for a link someone sent in that conversation. The broker refuses any other.
    • _meta["noodle/resource-list"] on a tool whose result lists resources, so the broker can remove unassigned ones.
    • _meta["noodle/post"] in a result to post into the verified conversation.
    • List every parameter a check depends on in the schema's required.
  • Before an action that cannot be undone, call context.authorize. It fails if the assignment was removed while the call was running.
  • Activation is .always, .whenAssigned(KIND) when the tool only makes sense with an assigned resource, or .whenGranted(KIND, id:) when the provider itself is what Noodle grants.
  • Everything a bot reads about a tool comes from the extension: manifest.summary, manifest.instructions and the tool descriptions. Do not add tool text to MessengerDocumentation, WorkspaceRepository.swift or docs/.
  • An extension gets the App Sandbox only. Browser and Computer also hold their companion's app group, and only that. scripts/verify-tool-extensions.sh pins this; a new entitlement needs a change there and a reason.
  • Bundled extensions only. Do not add loading of third-party extensions.
  • Extensions are background processes: keep LSBackgroundOnly in Info.plist.

Adding a tool

  1. Create Tools/NAME in the layout above. Copy Tools/Vision; it is the smallest.
  2. Add tool("NAME") at the end of Package.swift.
  3. In Project.swift, add toolExtension("NAME") to the targets and a dependency on it from the Noodle target, next to the existing three. The bundle identifier is <noodle id>.tools.NAME.
  4. scripts/verify-tool-extensions.sh checks every bundled extension and needs no change for a tool whose Extension.entitlements holds the sandbox alone. Anything more needs a case there.
  5. If it follows an assignment, publish that assignment from NoodleStore with toolAssignments.replace(KIND, with:).

For a built-in tool, replace steps 2–4 with builtInTool("NAME") in Package.swift, a dependency on the provider from the Noodle target, toolProviders.register(...) in NoodleStore, and whatever entitlement and Info.plist usage string the access needs in Support/.

Tests

  • Provider tests run without the extension, a companion app, a network or an account. They must pass in CI.
  • Write the test first and see it fail.
  • Before calling a change done, run all of swift test, then scripts/build-and-launch.sh and scripts/verify-tool-extensions.sh on the bundle.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.