Skip to content

Scope catalog

Scopes gate ctx.tools.call(...) access. Declare every scope your app needs in manifest.required_scopes; the tenant must grant them on install. The platform enforces scope at every call site — your code only runs against tenants where the grant exists.

The list below is the single source of truth from packages/core/src/apps/scope_registry.py. Tool names are case-sensitive and must match exactly when you call them via ctx.tools.call("name", ...).

ScopeTools
mail.reademail_search, email_read, email_check_inbox, email_get_attachments, email_triage_run
mail.sendemail_send, email_reply, email_draft_create, email_draft_reply, email_draft_send
mail.managereserved — no tools wired today
ScopeTools
calendar.readcalendar_list_events, calendar_get_event
calendar.writecalendar_create_event, calendar_update_event, calendar_delete_event
ScopeTools
files.readdeliver_file, linkworld_file_download
files.writeuser_app_dashboard_create
files.sharecreate_public_share_link

Note: deliver_file is a platform built-in (handled in tool_handlers.py, not the skill bridge). It’s listed here so the scope check still applies the day it migrates through the bridge.

read_app_records, write_app_records, and update_app_record exist only for the chat-built no-code apps (linkworld_user_apps — created in chat, persisted as a UI schema + records table per app). They look up the app in linkworld_user_apps; calling them from a deployed marketplace app returns {"code": "marketplace_app_wrong_tool", "use_instead": "ctx.kv"} and never writes anything.

Marketplace apps must use ctx.kv for app-private state — see the KV reference. Records keyed as {record_type}:{uuid} with ctx.kv.list(prefix="record_type:", ...) gives back the same shape read_app_records would have returned for the chat-built case. The inbox-manager example is the canonical ~900-LOC reference.

linkworld lint rule LWP006 flags any ctx.tools.call("read_app_records"|"write_app_records"|"update_app_record") in a marketplace-app codebase (manifest with app_id not declared as user_app: true) and points at ctx.kv as the fix.

ScopeTools
whatsapp.sendwhatsapp_send, whatsapp_send_document

Posts and sends use the tenant’s delegated M365 OAuth — messages appear as the authenticated user (no bot identity). An app that needs to broadcast to a channel should declare teams.send and document the public-visibility risk to the installing tenant.

ScopeTools
teams.readteams_list_teams, teams_list_channels, teams_list_chats, teams_list_chat_messages, teams_find_user
teams.sendteams_send_chat_message, teams_post_channel_message, teams_reply_to_channel_message

Platform-mediated. Partner apps cannot call api.linkedin.com directly — the platform resolves the tenant’s stored OAuth credential and calls on the app’s behalf. A read-only app declares only linkedin.read and the bridge blocks any attempt to post.

ScopeTools
linkedin.readlinkedin_list_comments, linkedin_get_analytics
linkedin.writelinkedin_post, linkedin_reply_comment

No general search API. LinkedIn does not expose a public people/post search endpoint. If your app needs lead discovery, use a dedicated data provider (ProxyCurl, People Data Labs, etc.) via its own scope-less API key — there is no platform tool for this today.

ScopeTools
document.renderrender_document, create_pdf, create_letter, create_report, create_document, create_gutachten, business_render_pdf, excel_create_report
document.draftbusiness_create_document, business_update_document, business_get_document, business_list_documents, business_list_clients, business_lookup_price, business_transition_document, business_convert_quote_to_invoice, doc_templates_install_defaults
pricelist.readbusiness_lookup_price

pricelist.read vs document.draft. business_lookup_price is covered by both. Apps that ONLY do pricing lookups (e.g. an inbox classifier checking whether a quote request is in scope) should grant the narrower pricelist.read — declaring document.draft would also grant write privileges they don’t need.

ERP — Lexoffice + Odoo + Business Central

Section titled “ERP — Lexoffice + Odoo + Business Central”

erp.read covers all three providers’ read paths; erp.write covers all three write paths. Pick the provider whose tools you call — the platform routes per-tenant connection state automatically.

Lexoffice: lexoffice_list_contacts, lexoffice_get_contact, lexoffice_list_invoices, lexoffice_get_invoice, lexoffice_get_invoice_pdf, lexoffice_list_quotations, lexoffice_get_quotation_pdf, lexoffice_get_payments

Odoo: odoo_search_read, odoo_get_record, odoo_list_models, odoo_list_reports, odoo_get_report

Business Central: bc_query, bc_get_record, bc_list_companies, bc_download_document

Lexoffice: lexoffice_create_contact, lexoffice_create_invoice, lexoffice_create_quotation

Odoo: odoo_create_record, odoo_update_record, odoo_delete_record, odoo_copy_record, odoo_execute_action

Business Central: bc_create_record, bc_update_record, bc_delete_record

ScopeTools
vision.analyzedamage_analyze_photos, damage_estimate_cost, damage_generate_report

Used by quote-drafting flows that need to read a customer-supplied technical drawing — operations, title block, dimensions. The dxf_render tool produces a derivative PNG and is part of the same analysis flow, so it lives under the same scope.

ScopeTools
drawings.analyzedxf_analyze, dxf_find_operations, dxf_measure, dxf_render, dxf_interpret
ScopeTools
voice.transcribereserved — voice transcription happens via the realtime relay today, not the skill bridge
ScopeTools
tasks.createtask_create, project_goal_create, project_goal_start

These tools are available to every installed app without declaring anything in required_scopes. They cover storage and personalisation primitives that aren’t tenant-data-bearing — apps need them to function at all, so the platform grants them by default.

Tool familyToolsReference
App KV storeapp_kv_set, app_kv_get, app_kv_list, app_kv_deleteKV reference
App RAG storerag_query, rag_list_documents, rag_get_document, rag_upsert_document, rag_delete_documentRAG reference
User profileuser_profile_getsee best-practices

If you see a ToolCallError with decision: "scope_denied" on one of these, that’s a platform bug — please file an issue. Built-ins should never trip the scope gate.

Some tools surface in lint warnings or autocomplete because they exist inside the platform — but they are not callable from ctx.tools.call(...):

  • web_search — a Claude-native LLM tool. Available to the LLM inside your Chat handler’s reasoning loop (when the model decides to use it), not to your app code directly. Don’t declare it as a scope; don’t try to call it.
  • web_browser — a built-in compute skill used internally by the assistant for headless-browser flows. Same shape: LLM-only.
  • assistant_execute_code — the assistant’s own code-execution tool. Same shape: LLM-only.

If your lead-research, market-scan, or scraping flow needs web data, bring your own data provider (Brave Search, SerpAPI, ProxyCurl, etc.) and call it from your handler with your own API key — there is no platform scope for this today.

A tenant might install your app without granting every scope. Code defensively:

import { ToolCallError } from '@linkworld_ai/sdk'
try {
await ctx.tools.call('odoo_create_record', { model, values })
} catch (err) {
if (err instanceof ToolCallError && err.decision === 'scope_denied') {
console.log('[my-app] erp.write not granted; skipping ERP write')
return
}
throw err
}
from linkworld_sdk import ToolCallError
try:
await ctx.tools.call("odoo_create_record", model=model, values=values)
except ToolCallError as exc:
if exc.decision == "scope_denied":
return
raise

Scopes and tool names ship with the platform — partners pick from the list above and cannot invent their own. Two common cases:

  • The tool exists but no scope grants it. That’s a platform bug: the tool is silently un-gated. File an issue.
  • The tool doesn’t exist yet. Open an issue at github.com/linkworld/linkworld describing the integration and use case. New scopes/tools get added to packages/core/src/apps/scope_registry.py as part of a platform release.

For workloads the platform doesn’t cover today (web search, generic HTTP scraping, niche SaaS APIs), call the third-party service from your own handler with your own API key — that’s fully supported and needs no platform scope.