Wayland Core ships a built-in tool registry of ~60+ tools. A universal core is always present (Read/Write/Edit, Bash, Grep/Glob, plus orchestration: Delegate, ToolSearch, Spawn) alongside around 40 more covering git, SQL, web fetch, cloud CLI wrappers, API integrations, media, scheduling, and memory. Around 15 integration tools are availability-gated under a NO-STUBS contract: they appear only when their key, binary, or feature is present.
The 8 tools the old docs listed (Read/Write/Edit/Bash/Grep/Glob/Delegate/ToolSearch) are the primary file, shell, search, and orchestration core. They are never the total.
Structured single-task or batch delegation; up to 5 tasks, 50 turns each; produces structured JSON output; accepts per-task toolsets allowlist.
Spawn
spawn_tool.rs
Multi-agent fan-out with registry-resolved named agents; OutputSink relay back to parent; FleetDispatcher used when agent count exceeds DEFAULT_SHARD_SIZE.
Workflow
workflow_tool.rs
Run an inline RON-format ForgeFlow workflow; parses RON → GraphConfig IR → WorkflowRunner; Agent/Pipeline/Parallel steps.
ToolSearch
tool_search.rs
Load full schemas for deferred tools (MCP tools are name-only by default); substring match on name+description; no result cap.
All tools below are registered unconditionally at bootstrap.rs:437-714 unless noted. Tools with a backend seam degrade gracefully on missing credentials.
Plain HTTP GET with readability extraction for HTML; zero runtime dependencies; SSRF-safe via url_safety::is_safe_url. Works on every install without a sidecar.
web
web_tools.rs
Web search, extract, and crawl. Backend selected at boot: Tavily (TAVILY_API_KEY) → Brave (BRAVE_SEARCH_API_KEY) → DuckDuckGo HTML scrape (no key required).
Cross-channel message dispatch; registered with a fail-loud null transport by default; a real transport (Telegram, Discord, Slack, etc.) must be wired by the host.
Tools without their required credential, binary, or device return Tool::is_available() == false at boot. The LLM never sees a tool it cannot call. Every tool with a backend seam ships a NullXxxBackend that fails loudly (not silently) when called without wiring.
Evidence: bootstrap.rs:557-711 - every env-gated registration is wrapped in if let Some(b) = build_xxx_backend() { registry.register(...) }. A missing env var means the tool is absent from the registry entirely, not present and broken.
These tools are registered by the wayland-browser and wayland-cua plugins, not directly from wcore-tools. They appear in the registry when the plugins are discovered and loaded at boot.
When builtin_tools.script.enabled = true, a Script tool is registered. It runs against a mini-registry containing a curated subset of the built-in tools (no Spawn, no Script, no MCP) to avoid an Arc cycle. Steps with approval_required: true route through the same approval bridge as the host.
Each tool that needs a backend implement a resolver function (build_xxx_backend()). The resolver checks for the required env var or binary and returns Some(backend) or None. The if let Some(b) = build_xxx_backend() pattern in bootstrap.rs means the registry call is never reached on a None return. The tool is absent from registry.tool_names() and from the system prompt. There is no stub version the model can accidentally call.
This is distinct from MCP tools, which are registered by name and defer schema loading until ToolSearch is called.