Skip to main content
Glama

Server Details

Connect your AI to your Well financial data - invoices, companies, contacts.

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Last Tested
Transport
Streamable HTTP
URL

Available Tools

43 tools
well_add_contact_channelAdd contact channelAInspect

Add a contact channel to a company or person.

Wraps the resource-scoped REST endpoints (POST /v1/{companies,people}/:id/{emails,phones,web-links,locations}).

channel + the matching value field:

  • email → value.email

  • phone → value.e164_number (E.164; a leading "+" is added if missing)

  • web_link → value.url (+ optional value.platform, default "website")

  • location → value.city, value.country (+ optional address_line1/2, region, postal_code) value.label is optional (defaults to "work").

NOTE: adding a phone is supported on a PERSON but NOT on a company (no endpoint) — that combination returns a clear error. To READ existing channels, use well_query_records on the parent (companies/people) or the channel root.

ParametersJSON Schema
NameRequiredDescriptionDefault
valueYesChannel value — fill the field(s) for the chosen channel
parentYesParent record type: company or person
channelYesChannel to add: email | phone | web_link | location
parent_idYesUUID of the parent company or person
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
parentNo
channelNo
successYes

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses the underlying POST endpoints, the E.164 normalization ('a leading + is added if missing'), optional defaults for label and platform, and the unsupported company+phone case. This significantly helps an agent predict behavior before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action, then uses compact bullet mappings and a final note for edge cases. Every line carries operational value; nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-object, multi-enum creation tool, it covers all critical input semantics, the invalid phone/company case, and routing to the read tool. The output schema exists, so return-value detail is not required. The definition is complete enough to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The channel-to-value mapping is explicit and goes well beyond the schema: email→value.email, phone→value.e164_number, web_link→value.url, location→value.city/country. It also clarifies optional fields and defaults. Schema coverage is 100%, but the description adds the crucial combination semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Add a contact channel to a company or person.' This goes beyond the title, defines the operation precisely, and is distinct from siblings like well_remove_contact_channel and well_query_records.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit alternative for reading channels ('use well_query_records on the parent'), and it warns against an invalid combination: phone on company returns a clear error. This is concrete when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_create_companyCreate companyAInspect

Create a new company in the current workspace.

Use this tool when the user asks to create, add, or register a new company.

REQUIRED: name OPTIONAL: description

After creation, enrichment (logo, domain, industry, tax ID, description fill-in) runs asynchronously in the background. The new company is available immediately for follow-up actions, but enriched fields may take a few seconds to populate — re-query after a brief delay to see them.

Returns { success: true, company_id, name } on success, or { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesCompany name (required)
descriptionNoBrief company description
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameNo
errorNo
successYes
company_idNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond the annotations by disclosing that enrichment runs asynchronously, that the company is available immediately, and that enriched fields may take a few seconds to appear. This is practical behavioral context an agent needs to manage user expectations and decide to re-query later.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded: purpose, trigger conditions, parameters, asynchronous behavior, and return value each have a clear place. Every sentence earns its keep with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the action, when to use it, required vs. optional parameters, post-creation async behavior, and the success/failure return shape. With rich schema descriptions and annotations also present, nothing essential is missing for an agent to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters well. The description adds a useful REQUIRED/OPTIONAL summary and mentions the current workspace, but it does not meaningfully explain workspace_id or idempotency_key beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action as 'Create a new company in the current workspace' and reinforces it with 'when the user asks to create, add, or register a new company.' This distinctly differentiates it from sibling tools like well_create_person or well_create_invoice_from_data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use this tool: when the user asks to create, add, or register a new company. It names the required and optional parameters but does not explicitly contrast this with updating an existing company via well_update_company, though the 'new company' phrasing largely makes that clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_create_invoice_documentCreate invoice documentAInspect

Render an existing invoice as a print-ready PDF and attach it as the invoice's source document.

The letterhead carries the issuing company's own mark when Well has one on file, and otherwise sets the issuer's name as text. Never promise a logo.

Use this tool when the user asks to generate, render, or attach a PDF for an invoice that already exists in the workspace. This does NOT email or send the invoice anywhere — it only creates and attaches the file.

REQUIRED: invoice_id (the invoice must already exist)

Refused if the invoice is already linked to a REAL ingested document (an upload, a connector import, or a provider-issued PDF) — that source of truth is never overwritten.

Returns { success: true, invoice_id, document_id, reference_number, file } on success, or { success: false, error } on failure.

file carries the rendered PDF's name and size plus the links to fetch it: download_url (saves the file), signed_url (opens it), and app_url (the document in Well). Hand the user download_url when they ask for the PDF itself. Both signed links stop working at expires_at; app_url does not.

ParametersJSON Schema
NameRequiredDescriptionDefault
invoice_idYes
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
fileNo
errorNo
successYes
invoice_idNo
document_idNo
reference_numberNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint=false, leaving write behavior undisclosed. The description fills this gap thoroughly: it attaches the PDF, never overwrites a real ingested source document, explains the logo fallback, and details refusal conditions. It also clarifies return behavior and link expiry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but every section earns its place: core action, subtle logo behavior, usage condition, refusal condition, and return details with link semantics. It is scannable and front-loaded with the main verb and resource.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even with an output schema present, the description usefully explains the return contract including file links and expiration semantics. It covers preconditions, refusal cases, logo caveats, and non-email scope, making the tool callable without further investigation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, and the description adds meaningful semantics for invoice_id by marking it required and requiring the invoice to already exist. workspace_id and idempotency_key are already well-described in the schema, so the description doesn't need to repeat them, though it doesn't tie them into the tool flow.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Render an existing invoice as a print-ready PDF and attach it as the invoice's source document') plus a concrete resource. Clearly distinguishes this from sibling tools like well_create_invoice_from_data and well_update_invoice by anchoring on an already-existing invoice.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it: when the user asks to generate, render, or attach a PDF for an invoice already in the workspace. It also states what it does not do (does not email or send) and when it is refused, though it does not name an alternative tool to use when the invoice does not yet exist.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_create_invoice_from_dataCreate invoice from dataAInspect

Create an invoice in Well from data you extracted by reading an invoice (your own OCR) — you send the structured fields, not the file.

Well persists the invoice + its line items + payment means using the same pipeline as uploaded documents. Fill every field you can read from the document:

  • issuer / receiver: { name (required), company_id?, domain?, tax_id? }

  • reference_number, issue_date (YYYY-MM-DD), due_date? (YYYY-MM-DD), currency (ISO 4217)

  • totals?: { items_total?, tax_total?, grand_total }

  • line_items[]: { name, quantity?, unit_price, currency?, tax_rate? }

  • payment_means?[]: { type, iban?, bic?, scheme? }

  • status?: draft | issued | paid | canceled

ONE CALL IS THE WHOLE WRITE. This tool takes the invoice's status and both parties' company ids, so a create never needs a well_update_invoice after it:

  • The user asked to DRAFT an invoice → pass status: "draft" here.

  • You already found the company (well_query_records, well_get_entity) → pass its company_id on that party. Naming the party without its id re-resolves it, which can attach the invoice to the wrong company or create a duplicate one.

Creating and then patching the same invoice writes twice and shows the user two confirmations for one action. Put the intent in this call.

ParametersJSON Schema
NameRequiredDescriptionDefault
issuerYes
statusNoThe invoice's lifecycle status. Set it here when the user asked for one ("draft an invoice") — do NOT create and then call well_update_invoice to change it. Omitted, the status is derived from the document type.
totalsNo
currencyYesISO 4217 (3 letters).
due_dateNoISO 8601 YYYY-MM-DD.
receiverYes
issue_dateYesISO 8601 YYYY-MM-DD.
line_itemsYes
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
payment_meansNo
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
reference_numberYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
invoice_idNo
document_idNo
payment_meansNo
reference_numberNo
invoice_item_countNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint=false, destructiveHint=false), the description discloses important side effects: re-resolving a party without company_id 'can attach the invoice to the wrong company or create a duplicate one,' and creating then patching 'writes twice and shows the user two confirmations for one action.' This goes far beyond the annotation metadata.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but efficiently organized: the core distinction is front-loaded, the field summary is compact, and the critical workflow warning is isolated under a bolded heading. A small amount of redundancy exists with the schema's own company_id description, but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter, nested-object write tool, the description covers the full data shape, formats, the workflow around status and company_id, and the pitfalls of double-writing. An output schema exists, so return-value explanation is unnecessary, and the combination leaves no significant gap for an agent to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%, and the description compensates with a compact field map including formats (YYYY-MM-DD, ISO 4217) and nested structures (issuer/receiver, totals, line_items, payment_means, status). It adds decision-level semantics—e.g., 'ALWAYS send this when you already know the company' for company_id and 'pass status:"draft" here' for status—meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Create an invoice in Well from data you extracted by reading an invoice' and distinguishes itself by clarifying 'you send the structured fields, not the file.' It also frames itself as the complete write, contrasting with well_update_invoice, which makes its role clear relative to siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly tells when to use this tool instead of alternatives: don't use well_create_invoice_document when you have structured fields rather than a file, and don't follow up with well_update_invoice because 'ONE CALL IS THE WHOLE WRITE.' It also gives concrete conditions like passing status:'draft' when the user asked for a draft and passing company_id when the company was already found via well_query_records or well_get_entity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_create_personCreate personAInspect

Create a new person (contact) in the current workspace.

Use this tool when the user asks to add, create, or register a new contact, employee, or person.

REQUIRED: first_name OPTIONAL: last_name, job_title

After creation, enrichment runs asynchronously in the background.

Returns { success: true, person_id, full_name } on success, or { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailNo
phoneNo
job_titleNoJob title
last_nameNoLast name (optional)
first_nameYesFirst name (required)
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
full_nameNo
person_idNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=false, destructiveHint=false, and openWorldHint=false, so the description adds valuable context beyond those: it discloses that enrichment runs asynchronously after creation, that required vs optional fields are listed, and it shows the exact success/failure return shape. This gives the agent important knowledge about side effects and response behavior that annotations alone do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short, focused sections: what it does, when to use it, required/optional fields, and return behavior. The most important trigger phrase is front-loaded, and every sentence earns its place without fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return values are already documented structurally. The description covers the creation workflow, async enrichment side effect, required fields, and error behavior. Given the moderate complexity (7 params, 1 required, no nested objects), this is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, and several parameters already have descriptions (job_title, last_name, first_name, workspace_id, idempotency_key). The description reinforces required/optional semantics for first_name, last_name, and job_title. It does not explain email or phone in prose, but the schema already describes them adequately, so the marginal gap is small.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new person (contact)') and gives concrete synonyms ('add, create, or register a new contact, employee, or person'). Clearly distinguishes from siblings like well_create_company and well_create_invoice_document, while the emphasis on 'person' and 'current workspace' differentiates it from well_update_person and well_delete_person.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use this tool ('when the user asks to add, create, or register a new contact, employee, or person'). It also clearly signals alternatives by naming sibling tools that create other entity types or update/delete people, so an agent can route correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_create_statement_uploadCreate statement upload slotAInspect

Mint a one-time, short-lived upload slot for a bank-statement file.

Use this when the user has a statement file (PDF, or a large CSV/XML) to import; the file's bytes do not travel through the model. It returns a single-use upload URL + token; the client (or the user) POSTs the raw file bytes to that URL, and the resulting document enters the exact same import pipeline as an in-app upload (detection, dedup, promotion).

This result renders a card in widget-capable hosts right away — do not wait for a poll to make it appear. Once the client has uploaded the file bytes, call well_get_statement_import_result with the document_id below ONE time to learn the outcome. The card refreshes itself as extraction and promotion complete, so a repeated poll only serves your own narration in chat, never the card's rendering.

The token authorizes exactly ONE upload to this workspace and expires in 15 minutes. It is burned on first use — a second upload needs a new slot. It cannot be used for anything other than a statement upload.

The response's document_id is PRE-ALLOCATED at mint time — the upload has not happened yet, and this exact id is what the document will carry once it does. A call to well_get_statement_import_result before the upload lands is a normal "not_found_yet", not an error.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
tokenNo
successYes
upload_urlNo
document_idNoThe pre-allocated document id — poll well_get_statement_import_result with it.
expires_in_secondsNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses one-time token burn, 15-minute expiry, single-workspace authorization, pre-allocated document_id, 'not_found_yet' semantics before upload, and the card auto-refresh behavior that eliminates the need for polling. This far exceeds what the annotations convey and materially affects how an agent should invoke and follow up.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is multi-paragraph but every block earns its place: purpose, usage conditions, lifecycle constraints, and preallocation semantics. Some repetition around polling and card rendering exists, but it is not padded overall.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the full lifecycle: mint URL/token, POST raw bytes, call result exactly once, card rendering behavior, expiry and burn, and pre-upload result semantics. Given that an output schema is present, nothing needed for correct use is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema coverage is 100%, so the baseline is 3. The description reinforces that workspace_id may be omitted when the token authorizes one workspace, but it does not add significant parameter-level meaning beyond the schema's existing descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Mint') and resource ('one-time, short-lived upload slot for a bank-statement file'), which clearly distinguishes it from the many sibling create_* tools and from well_get_statement_import_result. The title alone is generic, but the description anchors the tool precisely.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to use this when the user has a statement file (PDF, large CSV/XML) to import and notes that the file bytes do not travel through the model. It also prescribes the follow-up call to well_get_statement_import_result once, but it does not name an alternative tool or explicitly state when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_delete_companyDelete companyA
Destructive
Inspect

Delete a company from the current workspace (soft delete).

Use this tool when the user asks to delete, remove, or archive a company.

REQUIRED: company_id

This soft-deletes the company and its company_person relationships. Linked people records themselves are NOT deleted. Invoices and documents referencing the company are preserved.

Returns { success: true, company_id } on success, or { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
company_idYesThe UUID of the company to delete (required)
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
company_idNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already signal destructiveHint=true, but the description goes further by explaining that it is a soft delete, what gets deleted, what is preserved, and the success/failure response shape. This is exactly the side-effect context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: purpose first, then trigger phrase, required parameter, side effects, and return contract. Every sentence earns its place without unnecessary fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive tool with three parameters and an output schema, the description plus the schema fully cover what the deletion affects, what is preserved, the required ID, and the expected result. Nothing important is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% description coverage, including rich explanations for company_id, workspace_id, and idempotency_key. The description only repeats that company_id is required and does not add much semantic value beyond the schema, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: Delete a company from the current workspace, and immediately qualifies it as a soft delete. This distinguishes it clearly from sibling delete tools such as well_delete_invoice and well_delete_person.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states when to use the tool: when the user asks to delete, remove, or archive a company. It does not mention alternatives or exclusions, so it stops short of full 5-level guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_delete_invoiceDelete invoiceA
Destructive
Inspect

Delete an invoice from Well (soft delete).

REQUIRED: invoice_id

Soft-deletes the invoice. Linked line items and payment_means rows are NOT cascade-deleted — they remain in the database, orphaned. The delete is reversible only at the database level.

ParametersJSON Schema
NameRequiredDescriptionDefault
invoice_idYesThe UUID of the invoice to delete
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
invoice_idNo

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description explicitly reveals the soft-delete behavior, the lack of cascade deletion for line items and payment_means rows, the orphaning effect, and that reversal is only possible at the database level. These are material side effects that go beyond the destructiveHint annotation and should influence an agent's decision to call the tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core operation and critical caveats are front-loaded and written densel y, with no filler. The redundant 'REQUIRED: invoice_id' line repeats schema info, which keeps it from being perfectly lean.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description contains everything an agent needs to decide whether to call and whatto expect: soft delete, orphaned rows, database-only reversibility, and required argument. The output schema covers return values and the input schema covers workspace/dempotency details, so no critical context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents all three parameters, including workspace_id's conditional requirement and idempotency_key behavior, so the description adds no new parameter semantics. Its only param note, 'REQUIRED: invoice_id', duplicates the schema's required field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Delete an invoice from Well') and immediately qualifies it as a soft delete. This clearly distinguishes it from update/company/person siblings, so an agent knows exactly what action is offered.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states what the operation does but does not explicitly say when to prefer it over alternatives, nor does it name sibling tools as alternatives or exclusions. Usage must be inferred from the verb 'delete', which is a reasonable but implicit signal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_delete_personDelete personA
Destructive
Inspect

Delete a person (contact) from the current workspace (soft delete).

Use this tool when the user asks to delete, remove, or archive a contact.

REQUIRED: person_id

This soft-deletes the person and its company_person relationships. Linked companies themselves are NOT deleted. The authenticated user cannot delete their own person record.

Returns { success: true, person_id } on success, or { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
person_idYesThe UUID of the person to delete (required)
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
person_idNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations only indicate destructiveHint=true, but the description adds substantial behavioral detail: soft-delete behavior, deletion of company_person relationships, preservation of linked companies, the self-deletion restriction, and the success/failure response shape. This goes well beyond what annotations provide and gives the agent an accurate model of side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized and front-loaded: purpose, explicit when-to-use, required parameter, behavioral side effects, restrictions, and return shape. Every sentence contributes useful guidance, with no unnecessary filler or redundancy that weakens the message.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive tool with an output schema, the description covers the key operational context: scope, soft-delete semantics, cascade behavior, non-deletion of companies, self-deletion restriction, and error return shape. The input schema already documents the workspace_id and idempotency_key nuances, so nothing essential is missing from the overall tool definition.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description mostly repeats the already-schema'd required person_id and adds little new parameter-level meaning; workspace_id and idempotency_key are fully explained in the schema itself. The behavioral notes about soft-deleting company_person relationships are context, not parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Delete a person (contact) from the current workspace (soft delete).' It is immediately clear this performs a soft delete on a person/contact, and the explicit behavior around company-person relationships and company preservation distinguishes it from sibling delete tools like well_delete_company and well_delete_invoice.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear when-to-use rule: 'Use this tool when the user asks to delete, remove, or archive a contact.' It also notes the authenticated user cannot delete their own person record, which is a practical exclusion. It stops short of explicitly naming alternatives for related cases, such as well_delete_company for companies, so it earns a 4 rather than a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_burnGet average monthly burnA
Read-only
Inspect

Get the workspace's average monthly burn — the trailing average of actual outflows, the exact same computation and number the Well app's avg-burn KPI tile shows. Use this instead of summing transactions yourself.

Returns amount (a positive magnitude, not a signed figure) and currency, plus the window it was measured over: trailing_months is the window length, months_in_window and months_with_data say how much of it actually carried outflow.

per_month is the outflow of each month in that window, oldest first — the numbers the average is the mean of. A month with no recorded outflow is present with 0, not omitted, so the series and the average always agree; do not drop those months when you describe the trend. Use it to say whether burn is rising or falling. amount is the figure the app shows, so it is the one you lead with and the one you call the burn — never put a figure computed from the series in its place. If a dark month looks like a data gap rather than a real month of no spend, say it may be a gap; amount stays the headline either way.

change is a percentage against baseline, not against anything in per_month. baseline.period names the months it was measured over. That window anchors earlier than amount, so it normally covers a month this payload does not carry, and you usually cannot recompute change from the series. The two windows normally SHARE months, so this is a comparison between two overlapping averages rather than between two independent periods — a small change says less about a real shift than the same figure across separate periods would. When you quote change, say what it compares: baseline.period against the window in per_month. To describe movement WITHIN the displayed window, compute it from per_month and say so.

trend is whether the change is GOOD, not which way the number went. trend_polarity is lower_is_better for burn, so trend: "up" means burn FELL (the app renders it green) and "down" means burn ROSE. Never narrate trend: "up" as burn rising — read the sign of change for direction.

State the window whenever you present the number. The average always divides by months_in_window, so when months_with_data is lower the figure is a real average over a window containing dark months, NOT an average of only the months that had spend — say so rather than presenting it as the typical monthly outflow.

unavailable: true means amount is a placeholder rather than a measurement (e.g. nothing has synced yet) — a burn of zero standing on nothing measured is not a reading, so say that instead of reporting a €0 burn. partial: true means individual transactions were excluded from an otherwise real figure (e.g. a missing FX rate); disclose the exclusion count and any hints.

Pass year + month to measure a past period instead of the live window, and months_back to change the window length (default 3).

For months of cash left, call well_get_runway — it composes this burn with the cash position. For what the spend is made of, call well_get_cost_structure. Neither is a decomposition of the other: cost structure covers a single closed month and will not sum to a trailing average.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year of the reporting period, e.g. 2026. Must be given together with `month`.
monthNoCalendar month of the reporting period, 1 = January … 12 = December. Must be given together with `year`. Omit both to read the live/current figure.
months_backNoHow many closed months to average the burn over. Defaults to 3 — the same trailing window the app's KPI tile uses. Raise it to smooth a lumpy month, lower it to react faster.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
as_ofNo
errorNo
hintsNo
trendNoWhether the change is GOOD for this KPI, not the direction the number moved. Burn is lower-is-better, so "up" means burn FELL and "down" means it ROSE. Read the sign of `change` for direction.
amountYes
changeNoSigned percentage change of `amount` against `baseline.value` (e.g. -20.7 for a 20.7% fall). Measured over `baseline.period`, never over the months in `per_month` — the baseline is a different window, so a delta computed from the series is a different number.
partialNo
successYes
baselineNoWhat `change` was measured against. It arrives with `change`, `trend` and `trend_polarity` as one group; when the baseline has no named period all four are withheld rather than sending a percentage with no referent.
currencyNo
excludedNo
per_monthNo
unavailableNo
connectors_urlNo
trend_polarityNoWhich direction counts as good. Burn is lower-is-better, which is why a fall reads as `trend: "up"`.
trailing_monthsNo
months_in_windowNo
months_with_dataNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the call read-only, and the description goes well beyond that: zero months are included as 0 rather than omitted, unavailable is placeholder not measurement, partial excludes transactions with disclosure, change compares overlapping baselines, and trend means good/bad rather than direction. This materially prevents misreading the result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every paragraph earns its place: first sentence front-loads purpose, then each paragraph handles one output concept (amount/window, change/baseline, trend polarity, unavailable/partial, parameters, alternatives). The repetition of key warnings is deliberate reinforcement, not filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with subtle output semantics, output schema, and optional parameters, the description is complete: it covers window measurement, average divisor, placeholders, partial data, trend direction vs polarity, year/month override, alternatives, and single- vs multi-workspace auth. An agent has everything needed to call and interpret this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema already covers 100% of parameters with detailed descriptions, so the baseline is 3; the tool description adds practical guidance by linking year/month to past-period measurement, months_back to window length default 3, and workspace_id to the multi-workspace authorization context. This is a modest addition above an already-rich schema, not a full transformation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description opens with a specific verb and resource ('Get the workspace's average monthly burn') and pins the exact definition to the app's avg-burn KPI tile. It explicitly contrasts with sibling tools at the end, so an agent can distinguish it from well_get_runway and well_get_cost_structure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use ('Use this instead of summing transactions yourself'), names alternatives for other questions (runway for months of cash left, cost structure for spend composition), and explains the multi-workspace condition requiring workspace_id. No exclusion is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_cash_flow_bridgeGet cash flow bridgeA
Read-only
Inspect

Get the workspace's cash-flow bridge — how the opening cash position became the closing one — the exact same steps the Well app's cash-flow waterfall chart shows. Use this instead of deriving flows from raw transaction reads.

Returns steps in render order, each { label, value, kind }. kind says how to read value:

  • "start" and "total" carry an ABSOLUTE cash position (the opening and closing anchors).

  • "increase" and "decrease" carry a gross flow MAGNITUDE, always positive. The direction lives in kind, not in the sign — never report a "decrease" as a negative number or add the magnitudes as though they were signed.

  • "unexplained" carries a SIGNED adjustment and is the one kind whose sign you must keep. It appears only when the four measured bars do not reconcile: it is the gap between them and the measured closing position, NOT cash that moved. Report it as an unexplained difference and say the bridge does not fully reconcile. Never fold it into the inflow or outflow figure, and never present it as spending, income, or a transfer.

Walk the steps to reach the total: opening, plus every "increase", minus every "decrease", plus any "unexplained". When an "unexplained" step is present that sum equals the "total" exactly. When none is present the bridge reconciled to within a small tolerance — say it reconciles, not that it is exact to the cent. A bridge can also omit the step because an anchor could not be measured at all; the hints say so when that happens, so read them before claiming either.

This is a SELF-CONTAINED reconciliation: the "start" and "total" steps ARE the opening and closing balances for the period, so do not also call well_get_cash_position to fetch them. That tool answers a different question — the balance right now — and pairing it with this one reports today's figure beside last period's bridge as though they were the same reading.

An EMPTY steps array means neither anchor could be measured (nothing connected, or the reads timed out). That is missing data, NOT a month with no movement — say the bridge is unavailable rather than reporting flat cash.

period_start and period_end are the inclusive YYYY-MM-DD bounds these bars cover — a trailing multi-month window, not a single month. Read the period from those fields and state it whenever you present the numbers. Never derive it from today's date, and never assume one month. If both fields are absent, say the period is unknown rather than naming one.

Pass year + month to bridge a past period instead of the live window. Read the window you actually got from period_start/period_end either way.

This is not a decomposition of well_get_cost_structure: this reconciles opening to closing cash across inflow and outflow, while cost structure splits a single month's outflow by category. They will not tie out, and presenting one as the breakdown of the other is wrong.

If hints are present (excluded accounts, an FX gap, or an unexplained residual between the anchors and the flows), disclose them rather than presenting the bridge as balanced.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year of the reporting period, e.g. 2026. Must be given together with `month`.
monthNoCalendar month of the reporting period, 1 = January … 12 = December. Must be given together with `year`. Omit both to read the live/current figure.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
hintsNo
stepsYes
successYes
currencyNo
period_endNoInclusive YYYY-MM-DD end of that window.
unavailableNo
period_startNoInclusive YYYY-MM-DD start of the window the flow bars cover (a trailing multi-month span).
connectors_urlNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, yet the description adds substantial behavioral context beyond them: sign conventions for 'increase'/'decrease' kinds (never report a decrease as negative), the special status of 'unexplained' as a non-cash gap, tolerance-based reconciliation wording, empty-steps meaning missing data rather than flat cash, the trailing multi-month period semantics, and the requirement to disclose hints. It also states the tool is a self-contained reconciliation and will not guess a workspace when several are authorized. No contradiction with annotations — 'this read' wording is consistent with readOnlyHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but every sentence earns its place by preempting a distinct agent error: misreporting sign, folding 'unexplained' into flows, claiming flat cash on empty data, deriving the period from today's date, pairing with cash position, or tying out to cost structure. It is front-loaded with the core purpose, then proceeds logically through return semantics, reconciliation math, edge cases, parameter usage, sibling distinctions, and auth. Density is justified by the tool's semantic complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description explains the steps array semantics, period fields, hints, empty-array behavior, reconciliation edge cases, multi-workspace auth, and sibling tool contrasts. It covers every call-relevant scenario an agent could encounter: absent period fields, missing anchors, timing-out reads, and authorization scope. Nothing needed to invoke the tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema descriptions already document year/month pairing and workspace_id conditions. The description adds genuine value on top: year+month select a past period rather than the live window, the returned period_start/period_end must be read from the response rather than assumed to match the request, and workspace_id is a disambiguation for multi-workspace tokens rather than a general selector. That is real semantic enrichment beyond the schema, though the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb (get), resource (cash-flow bridge), and the core transformation (how opening cash became closing). It names the exact same steps as the Well app's waterfall chart, anchoring what the tool returns. Sibling differentiation is built in: the description explicitly contrasts this with well_get_cash_position and well_get_cost_structure, so an agent can select it without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage guidance is explicit and exhaustive: 'Use this instead of deriving flows from raw transaction reads'; 'do not also call well_get_cash_position' because it answers a different question; 'this is not a decomposition of well_get_cost_structure' and they will not tie out. It also gives precise conditions for passing year/month (bridge a past period vs. live window) and for workspace_id (omit when token authorizes one workspace, pass when several). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_cash_forecastGet cash position forecastA
Read-only
Inspect

Get the workspace's cash-position forecast — trailing actual month-end balances plus a worst-case projection forward — the exact same series the Well app's "Cash Position Forecast" chart draws. Use this instead of projecting cash forward yourself from a cash figure and a burn rate.

Returns entries, one per month, oldest first, each { month, actuals, projection } where month is YYYY-MM:

  • actuals is the settled cash position at that month's end, and is null for future months.

  • projection is the worst-case value at that month's end, and is null for past months.

So the series has exactly one turn: actuals up to the present, projection after it. Do not fill the nulls in or treat a null as a zero.

anchor names what the projection counts forward from: { month, amount, basis }, where the first projection point is amount minus one month of trailing burn. Name the anchor whenever you present that point — without it a reader cannot tell a projection falling from a base that is weeks old from cash that is actually dropping, and the two produce the same number. anchor is absent when nothing is projected.

Read basis before describing the anchor, because the two values are different readings and only one is a month-end:

  • closed_month_endamount is the settled balance at the end of month. When month is not the month just gone, say so: the projection for a month already under way was computed without anything that happened in it.

  • current_positionamount is today's consolidated cash, which DOES include the month under way. Here month is only where the projection starts on the chart's grid, not the date the amount was read, so do not present it as a closing balance.

The projection is explicitly WORST CASE — it assumes NO revenue and declines at the trailing average burn until it reaches zero, where it stays clamped. Say so whenever you present it. It is a floor, not a forecast of what will happen, and a workspace that expects income will not follow it.

Takes no period. A worst-case projection has no coherent meaning for a month whose real outcome is already known, so this always returns the live forecast — unlike well_get_cash_position and well_get_cost_structure, which do accept year/month.

If hints are present (a short actuals window, excluded accounts, or a burn-coverage gap), disclose them rather than presenting the series as unconditionally complete.

This tool renders its own chart card in the host. Do not re-plot the series with a charting or visualisation tool — that draws a second, unbranded copy of a chart the reader is already looking at, from the same numbers. Read the series to answer in words; leave the drawing to the card.

For the single months-of-cash-left figure call well_get_runway; for the burn rate driving the decline call well_get_burn.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
hintsNo
anchorNo
entriesYes
successYes
currencyNo
connectors_urlNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint and destructiveHint, so the description carries the behavioral burden and excels. It discloses null-handling rules ('Do not fill the nulls in or treat a null as a zero'), the exact actuals/projection turn, the worst-case assumption with clamping, the anchor/basis interpretation pitfalls, the self-rendering chart card, and the 'do not re-plot' rule. These are meaningful behaviors beyond any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but every section earns its place given the nuanced output semantics. It is front-loaded with the core purpose and the most important behavioral constraint, then uses bullet lists and bolded cues to keep the dense details scannable. There is no fluff or tautology.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read tool with a rich output contract, the description covers return shape, null semantics, anchor/basis meanings, worst-case assumptions, hints handling, chart-card behavior, sibling routing, and workspace ambiguity — all without needing to reproduce the output schema. It is complete enough for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already fully documents workspace_id, including when to omit it and when it is required, so schema coverage is 100%. The description repeats this guidance but does not add new parameter-level semantics beyond what the schema provides. Baseline 3 is appropriate because the schema carries the parameter documentation burden completely.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get the workspace's cash-position forecast' and immediately scopes it as 'trailing actual month-end balances plus a worst-case projection forward.' It also names the exact chart series it mirrors, which distinguishes it from other cash-related tools, and later contrasts itself with well_get_cash_position and well_get_cost_structure on the period parameter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit alternative to manual projection ('Use this instead of projecting cash forward yourself'), clarifies when not to use it ('Takes no period'), and routes to siblings for related but different needs: 'For the single months-of-cash-left figure call well_get_runway; for the burn rate driving the decline call well_get_burn.' It also gives concrete caller guidance for workspace authorization, including when to pass workspace_id.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_cash_positionGet cash positionA
Read-only
Inspect

Get the workspace's current cash position: total cash on hand right now, converted to the workspace base currency, plus a per-account breakdown — the exact same computation and numbers the Well app's canvas KPI card shows. Use this instead of summing account balances yourself.

Returns amount/currency (the converted total), accounts (per-account contributions: native amount/currency, converted amount, the FX rate applied), as_of (the FX-rate anchor date this snapshot is valid for), and balance_history when the workspace has one.

balance_history is the trailing closed month-ends plus today, oldest first. Month-end is the only historical granularity that exists, so describe movement between months, never within one, and never as a daily series. A null amount is a month no connected account covered — not a zero balance. The field is absent when there is no reconstructed history, so make a trend claim only when it is present.

unavailable: true means amount is a placeholder, not a real measurement (e.g. no accounts connected yet) — say so plainly rather than presenting it as a real €0 balance. partial: true means one or more accounts were excluded from an otherwise real total (e.g. missing FX rate) — mention the exclusion count and any hints rather than presenting the number as unconditionally complete.

Everything here is backward-looking — no burn rate or runway is implied. Call well_get_runway instead for a forward-looking figure.

Pass year + month to read the balance as of the end of a past month instead of today. Note that balance_history (the trailing sparkline series) is returned ONLY for the live reading: a historical month has no live final point to anchor a trailing series on, so asking for a period returns the point-in-time balance without the series.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year of the reporting period, e.g. 2026. Must be given together with `month`.
monthNoCalendar month of the reporting period, 1 = January … 12 = December. Must be given together with `year`. Omit both to read the live/current figure.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
as_ofNo
errorNo
hintsNo
amountYes
partialNo
successYes
accountsYes
currencyNo
excludedNo
unavailableYes
connectors_urlNo
balance_historyNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the call read-only, and the description adds substantial behavioral context: unavailable/partial placeholder semantics, null balance_history meaning, backward-looking scope, live-only balance_history, and month-end historical granularity. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though long, the description is front-loaded with purpose and every paragraph earns its place: output interpretation, historical semantics, edge-case flags, and workspace/auth behavior. There is no filler or redundant marketing language.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only tool with zero required parameters, a full schema, and an output schema, the description is comprehensive. It covers return fields, edge-case flags, live vs historical behavior, workspace selection, and routes to well_get_runway when appropriate, leaving no material gap for an agent to guess.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema documents all three parameters at 100% coverage, so the baseline is 3. The description adds meaningful semantics on top: year+month means end-of-past-month as-of, balance_history is omitted for historical reads, and workspace_id selection rules for multi-workspace tokens.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Get the workspace's current cash position') and details exactly what it returns: the converted total, per-account breakdown, and the same computation as the Well app's KPI card. It also distinguishes itself from manual summing and nearby cash-related tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent when to use this tool and when not: use it instead of summing account balances yourself, and call well_get_runway instead when a forward-looking figure is needed. It also gives concrete invocation rules for single-workspace vs multi-workspace tokens.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_cost_structureGet cost structureA
Read-only
Inspect

Get the workspace's cost structure: outflow for the latest closed month, broken down by category — the exact same computation and numbers the Well app's canvas cost-structure donut chart shows. Use this instead of summing/grouping transactions yourself.

Returns entries (an array of { category, amount, pct }, sorted by amount descending) and currency (the workspace base currency). amount is a magnitude (outflow), not signed.

period_start and period_end are the inclusive YYYY-MM-DD bounds these amounts cover — always a single month. Read the period from those fields and state it whenever you present the numbers. Never derive it from today's date. Never present the figures as a quarter or a multi-month span. If both fields are absent, say the period is unknown rather than naming one.

rung names which grouping actually produced these categories — "ledger_account" (the workspace's own chart of accounts), "category_normalized" (Well's auto-categorization), "transaction_type" (a technical fallback bucket), or "uncategorised" (no rung qualified — either nothing covered the month, or a rung had the coverage but too few labelled rows). State it when you present the breakdown so the user knows whether they're looking at their own ledger's categories or Well's.

label_provenance says whether a human owns those labels, which rung cannot — "curated" (a person set or confirmed every one), "machine" (none were confirmed by a person), "mixed" (some of each), or "unlabelled" (the breakdown is not grouped on a category, so the question does not apply). When it is "machine" or "mixed", say the categories were assigned automatically and may be wrong on any individual line, rather than presenting them as the user's own categorization.

If hints are present (e.g. a coverage caveat about uncategorized spend), disclose them rather than presenting the breakdown as unconditionally complete.

Pass year + month to break down a specific past month instead of the latest closed one. Read the month you actually got from period_start/period_end either way — a requested month with no data still comes back with whatever the endpoint could cover.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year of the reporting period, e.g. 2026. Must be given together with `month`.
monthNoCalendar month of the reporting period, 1 = January … 12 = December. Must be given together with `year`. Omit both to read the live/current figure.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rungNoWhich ladder rung produced these categories: the workspace's own ledger accounts, Well's auto-categorization, a technical fallback bucket, or none qualified.
errorNo
hintsNo
entriesYes
successYes
currencyNo
period_endNoInclusive YYYY-MM-DD end of that window.
records_urlNoLogin-gated deep link to the web-app transactions table, so the user can categorize the underlying spend. Null when no workspace is in context.
period_startNoInclusive YYYY-MM-DD start of the window the amounts cover (the latest closed month).
label_provenanceNoWhether a human owns the labels: every one set or confirmed by a person (curated), none confirmed (machine), some of each (mixed), or not grouped on a category at all (unlabelled).
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the readOnlyHint annotation by explaining the exact computation, the meaning of rung and label_provenance, the single-month period semantics, and the requirement to disclose hints. It also specifies how to handle missing period fields and machine-assigned labels, which an agent could not infer from annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence carries operational value; the core purpose and output are front-loaded, followed by caveats in a logical order. No filler, redundant restatements, or vague wording is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists and annotations cover safety, the description adds all remaining operational context: return field meaning, period constraints, grouping provenance, label ownership, and multi-workspace handling. An agent has everything needed to invoke the tool correctly and present results accurately.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though the schema already describes year, month, and workspace_id at 100 percent coverage, the description adds important runtime behavior: what happens when no data exists for a requested month, how the rung and label_provenance affect interpretation, and why workspace_id is required in multi-workspace contexts. This extra meaning is directly actionable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific resource (the workspace cost structure) and a specific computation: outflow for the latest closed month broken down by category, matching the Well canvas donut chart. It also signals the tool's scope by saying to use it instead of manually summing transactions, which separates it from generic query tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly tells the agent when to call this tool directly and when to add workspace_id for multi-workspace tokens, and it gives the year+month path for past months. It also warns to treat the returned period as authoritative and to avoid naming a period when the fields are absent, which is clear behavioral guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_design_tokensGet design tokensA
Read-only
Inspect

Get Well's colours, shape and type vocabulary, so a view you compose for Well data looks like Well rather than a generic page.

Call this ONLY when you are about to render something yourself — an HTML artifact, a report, a chart you are drawing. You do not need it to answer in prose or in a markdown table.

Do NOT use it to restyle a card a Well tool already drew. Where a tool ships its own card the host renders it, and a second styled copy of the same figures is a duplicate, not an improvement.

Returns colors (roles, not raw token names — page_background, card_surface, text_primary, accent, positive, negative, ...), series (categorical chart colours in the order to consume them), shape (corner radius and gap), fonts, and color_scheme, which tells you which ground to compose against. When it is absent the stylesheet did not declare one — pick a ground from page_background rather than assuming.

Values come from the same token package the Well app, the browser extension and the tool cards compile against, so they cannot drift from the product.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. Optional: this tool describes the token itself rather than one workspace's data, so omitting it returns the same answer.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
fontsYes
hintsNo
shapeYes
colorsYes
seriesYes
successYes
color_schemeNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this read-only, and the description adds substantial behavioral context: the exact return fields and their semantics, the note that colors are roles rather than raw token names, the consumption order for series, and the fallback behavior when color_scheme is absent. It also explains the token source cannot drift from the product.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is somewhat long but every sentence earns its place: purpose, usage precondition, exclusion, return-field semantics, and provenance. It is front-loaded with the core purpose and then layers necessary detail without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description fully equips an agent to decide when to call the tool, what to expect, and how to interpret edge cases such as missing color_scheme. An output schema exists, so the explicit return-field details are a bonus, not a necessity. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% coverage for the single optional workspace_id parameter, describing it as optional and stating omitting it returns the same answer. The main description adds no further parameter-level meaning, which is acceptable because the schema handles it; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get Well's colours, shape and type vocabulary'. It clearly differentiates the tool from all sibling data tools by positioning it as the design-token source for custom rendering, not for data retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage guidance is explicit: 'Call this ONLY when you are about to render something yourself' and 'Do NOT use it to restyle a card a Well tool already drew.' It gives concrete conditions for use and non-use, making the agent's decision unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_entityGet entity (with sub-resources)A
Read-only
Inspect

Read ONE entity with its sub-resources nested in a single call.

Convenience over well_get_schema + well_query_records: resolves the field paths for you and returns the single record with its related data expanded.

depth (relation-nesting BOUNDARY, 1-3, default 1): 1 = the entity + its direct sub-resources (emails, phones, locations, …) 2 = + the sub-resources' related scalars 3 = the full level-3 graph (LARGER payload — use when you need the whole picture) Stops at depth 3. Aggregates are excluded. Each child collection is capped at 50 rows; for a full list or to page a large child collection, use well_query_records on that child root instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe entity's public UUID (the value of its *_id field, e.g. company_id)
rootYesEntity type, e.g. companies | people | invoices | transactions
depthNoRelation-nesting boundary 1-3 (default 1).
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.

Output Schema

ParametersJSON Schema
NameRequiredDescription
depthNo
errorNo
foundYes
entityYes
successYes
columnMetaNoPer-column field meaning ({context, enrichment}) for documented columns — read this to interpret the entity's values.
fields_selectedNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial behavior beyond that: depth semantics, hard stop at depth 3, aggregate exclusion, 50-row cap per child collection, and the warning that omitting workspace_id may hit the token's primary workspace rather than the intended one. These are exactly the behavioral details an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear opening sentence, a comparison to alternatives, and a compact bulleted explanation of depth. Every sentence carries useful information, and the most important scoping details are front-loaded. It is longer than minimal, but the added detail is directly actionable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the description does not need to document return values. It covers all call-critical context: exactly what the tool reads, depth boundaries, exclusions, row caps, workspace targeting behavior, and when to switch to well_query_records. Nothing essential is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all four parameters. The description adds meaningful depth semantics beyond the schema, explaining what depth 1, 2, and 3 mean, the payload-size tradeoff, and the 50-row cap. The description does not add much for id/root, but the schema already covers them well, so a 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Read ONE entity with its sub-resources nested in a single call.' It clearly states what the tool does and distinguishes it from the related well_get_schema and well_query_records flow, so an agent can tell it apart from the many sibling get_* tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly frames this tool as a convenience over well_get_schema + well_query_records and explains that it resolves field paths and returns a single expanded record. It also gives a concrete alternative for large child collections: use well_query_records on that child root. This is strong when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_investment_holdingsGet investment holdingsA
Read-only
Inspect

Get the live holdings/positions (what's currently held and its value) for a connected Plaid investment account — brokerage, IRA, 401k, etc.

WORKFLOW:

  1. well_list_connectors() → pick the ENABLED Plaid connector (connection_status: "enabled") and read its workspace_connector_id directly off the row.

  2. well_get_investment_holdings({ workspace_connector_id }) → the current holdings, fetched fresh from Plaid on every call (never stored/stale data).

Only works on Plaid connectors that support the investments product — not the MCP-transport connector-tool-passthrough tools (well_list_connector_tools / well_invoke_connector_tool), and not for investment transactions (buy/sell/dividend/fee), which are queryable as ordinary rows via well_query_records on the transactions root instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
workspace_connector_idYesThe connected Plaid provider's workspace_connector_id (from well_list_connectors).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
holdingsNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds meaningful behavioral context beyond that: data is fetched fresh from Plaid on every call and never stored or stale, and the tool only works on Plaid connectors supporting the investments product. This is genuinely useful for an agent deciding whether to trust or cache the result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence immediately establishes purpose, followed by a compact workflow and a clear 'not for' list. The structure is front-loaded and every section earns its place without irrelevant detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only tool with an output schema and safety annotations, the description covers what is needed: how to prepare, what the call returns conceptually, and when to use an alternative. The exclusions remove the main ambiguity an agent would encounter among the sibling tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters fully. The description reinforces the source of workspace_connector_id by tying it to well_list_connectors, but adds no new format or semantic detail beyond the workflow context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Get the live holdings/positions... for a connected Plaid investment account.' It clearly differentiates from siblings by explicitly excluding investment transactions and the MCP-transport passthrough tools, and by directing transaction queries to well_query_records.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit numbered workflow: list enabled Plaid connectors, read the workspace_connector_id, then call this tool. It also states when not to use it and names the exact alternatives (well_list_connector_tools, well_invoke_connector_tool, well_query_records).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_own_companyGet own companyA
Read-only
Inspect

Get which company the workspace itself is: the confirmed own-company anchor (anchor) and any detected companies not yet confirmed as it (candidates).

Use this whenever a question turns on "mine" versus "theirs" — my payables, my receivables, invoices I owe, what we billed — and then filter by the company_id this returns. Never decide which records are the workspace's own by comparing a company NAME: the same legal entity appears under several labels (a registered name, a trade name, a bank-issued label), so a name filter silently drops rows.

Returns anchor (company_id, registered_name, trade_name) or null when the workspace has not resolved one yet, and candidates (each with company_id, names, role, confidence_score, state).

anchor: null means the workspace has no confirmed own company. Say so plainly and do not promote a candidate to the anchor yourself — a candidate is a detection, not a decision, and confirming one is a user action.

Registry tax ids and registered addresses are deliberately not returned.

Call this directly — no other tool call is needed first. Both the anchor and the candidates are read from the same workspace this call is scoped to.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
anchorYes
successYes
candidatesYes
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the readOnlyHint: it explains the `anchor: null` case, warns against promoting a candidate to anchor, explicitly states that registry tax ids and registered addresses are not returned, and confirms no prerequisite call is needed. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is thoroughly organized: definition first, usage guidance second, return shape and edge cases after. Every paragraph earns its place, and there is no fluff or repeated schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only lookup with one optional parameter, the description is complete: return shape, null behavior, deliberate omissions, scoping, and usage rules are all covered. The output schema exists, so return value details do not need to be exhaustively repeated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single optional parameter is well documented. The description adds extra semantic value by stating that both anchor and candidates are read from the same workspace the call is scoped to and that no other tool call is needed first.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get which company the workspace itself is' and clarifies the distinction between `anchor` and `candidates`. This makes the tool's purpose immediately distinguishable from related tools like `well_set_own_company` and `well_get_entity`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit when-to-use: 'Use this whenever a question turns on "mine" versus "theirs"' with concrete examples, and an explicit when-not-to: 'Never decide which records are the workspace's own by comparing a company NAME.' It does not name an alternative tool by name, but the usage context is strong and would not mislead an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_runwayGet runwayA
Read-only
Inspect

Get the workspace's current cash runway — cash on hand, trailing-3-month average burn, and months of cash left — the exact same computation and numbers the Well app's canvas KPI cards show. Use this instead of computing runway yourself from raw account/transaction reads.

Returns cash (amount + currency), avg_burn (amount + currency + trailing_months), months, and a status discriminator:

  • "ok" — a finite months figure.

  • "capped" — runway exceeds 36 months; report as ">36 months", not the raw number.

  • "infinite" — cash is positive and the workspace isn't burning (net inflow); there is no meaningful "months" figure.

  • "insufficient_data" — not enough connected cash/transaction data to compute; tell the user to connect a bank/accounting connector (well_list_connectors) instead of guessing.

change is a percentage against baseline. A baseline runway divides a month-end cash reading by a trailing burn window, so it takes two dates to describe: baseline.period is the cash month-end it was anchored at, and baseline.burn_window is the span of the burn it divided by, which normally ends an earlier month. Never present the baseline as the runway measured on one day. trend is whether the change is GOOD, not which way the number moved; trend_polarity is higher_is_better for runway, so "up" means the runway grew. Read the sign of change for direction.

partial: true means some accounts or transactions were excluded from the computation (e.g. missing FX rate) — mention the exclusion counts and any hints if present rather than presenting the number as unconditionally complete.

Pass year + month to read a past reporting period instead of the live figure. There is no burn-window option here on purpose: the runway figure composes the endpoint's own trailing burn, so a custom window would pair months from one window with avg_burn from another and the cash ÷ burn division could not reproduce the headline. Call well_get_burn for a different window.

For the month-by-month cash series, call well_get_cash_forecast. Its forward half is a WORST CASE: it assumes the trailing burn continues and no revenue arrives at all. Never describe it as expected, forecast or likely cash, and never quote a month from it as what the balance will be — say what it is, the floor if nothing changes. A month in the settled half is a measured balance and may be stated plainly.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year of the reporting period, e.g. 2026. Must be given together with `month`.
monthNoCalendar month of the reporting period, 1 = January … 12 = December. Must be given together with `year`. Omit both to read the live/current figure.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
cashNo
as_ofNo
errorNo
hintsNo
trendNoWhether the change is GOOD for this KPI, not the direction the number moved. Runway is higher-is-better, so "up" means the runway grew. Read the sign of `change` for direction.
changeNoSigned percentage change of `months` against `baseline.value`.
monthsYes
statusYes
partialNo
successYes
avg_burnNo
baselineNoWhat `change` was measured against. It arrives with `change`, `trend` and `trend_polarity` as one group; when the baseline has no named period all four are withheld rather than sending a percentage with no referent.
excludedNo
connectors_urlNo
trend_polarityNoWhich direction counts as good. Runway is higher-is-better, so a longer runway reads as `trend: "up"`.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations only provide readOnlyHint and destructiveHint, so the description carries the full behavioral burden and exceeds it: it defines each status discriminator, explains partial-computation semantics, clarifies baseline/trend polarity, and warns that the forecast sibling's forward half is worst-case. It also discloses the design decision not to offer a burn-window option and why, which goes well beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loaded with purpose, return semantics, and statuses before moving to edge cases and sibling routing. It repeats a couple of schema-level workspace/year-month rules and could be tightened, but the density is largely justified by the number of statuses and interpretation hazards.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema and annotations cover types and safety, while the description fills in all the interpretation and workflow context: status meanings, capped/infinite/insufficient-data handling, partial exclusion hints, baseline/treend semantics, auth behavior, and sibling routing. For a tool with this many edge cases, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents the year/month pairing, the omit-both-for-live rule, and the workspace_id authorization behavior. The description largely restates those rules rather than adding new per-parameter meaning, so the high-coverage baseline of 3 applies; the extra rationale about the absent burn-window option is not parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific read operation (get workspace cash runway), enumerates the exact metrics returned (cash on hand, trailing-3-month burn, months of cash left), and anchors it to the Well app's KPI cards. It also explicitly contrasts this with computing from raw account/transaction reads and later names the sibling tools it should not be confused with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: use this instead of computing runway yourself, and call it directly when the token authorizes one workspace. It names alternatives with conditions — well_get_burn for a different burn window and well_get_cash_forecast for the monthly series — and explains why a burn-window parameter is intentionally absent here.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_schemaGet schemaA
Read-only
Inspect

Discover available data types and fields.

USAGE:

  • well_get_schema() → List ALL available roots, including the accounting graph (ledger_accounts, journals, journal_entries) plus account_balances, tax_rates, exchange_rates — query these for real financial statements (compte de résultat / balance sheet) instead of reconstructing them from raw invoices

  • well_get_schema({ root: "invoices" }) → List all available fields for invoices

WORKFLOW:

  1. Call well_get_schema(root) to see available fields

  2. Pick the fields you need for your task (typically 5-15)

  3. Call well_query_records with those specific fields

Returns fields with path, type, and (when documented) semantic context:

  • { path: "invoices.grand_total", type: "numeric", context: "Total invoice amount incl. tax in the document currency...", enrichment: "AI extraction" } → use _eq, _gt, _lt, etc.

  • { path: "invoices.local_currency", type: "enum" } → use ONLY _eq, _neq, _in, _nin, _is_null

  • { path: "invoices.issuer.name", type: "text" } → use _eq, _like, _ilike, etc.

  • "context" (when present) explains what the field MEANS in the domain and how it's used — read it to pick the right field and write correct filters.

  • "enrichment" (when present) is the value's provenance (e.g. "Bank sync", "AI extraction", "System generated", "Derived", "Manual"). Use the type to choose the right whereClause operators in well_query_records. To use in well_query_records, convert path to array: "invoices.issuer.name" → ["invoices", "issuer", "name"]

ParametersJSON Schema
NameRequiredDescriptionDefault
rootNoEntity root to inspect. Omit to list every available root (call well_get_schema() with no argument first). Includes the accounting graph (ledger_accounts, journals, journal_entries) alongside companies, invoices, transactions, accounts, and more.
depthNoRelationship depth: 0=scalars only, 1=direct relations (default), 2=nested, 3=level-3 graph
workspace_idNoTarget workspace. Optional: this tool describes the token itself rather than one workspace's data, so omitting it returns the same answer.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rootNo
errorNo
rootsNo
totalNo
fieldsNo
successYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as read-only and non-destructive, and the description adds meaningful behavioral detail: it returns fields with path, type, context, and enrichment provenance; explains that context helps pick the correct field and filters; and notes that workspace_id is irrelevant because the tool describes the token itself rather than workspace data. This goes well beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well structured with USAGE, WORKFLOW, and return-format sections, and it front-loads the core purpose first. Every section earns its place, including the practical examples and the note about converting paths for well_query_records. It is dense but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a schema-discovery tool with zero required parameters and an output schema, the description covers everything an agent needs: what roots to expect, how to invoke with or without a root, how to use the returned field metadata, how to map types to query operators, and how to translate paths for well_query_records. No critical guidance is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% coverage for all three parameters, including root, depth, and workspace_id semantics. The description adds extra value with concrete root examples, the accounting-graph hint, operator selection by type, and path-to-array conversion. It does not add much beyond the schema for depth, but the schema already documents that sufficiently.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb+resource statement: 'Discover available data types and fields,' then concretely demonstrates both invocation forms—no argument for all roots and with a root for field lists. It clearly distinguishes this tool from well_query_records by positioning it as the discovery step that feeds query construction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides an explicit WORKFLOW: call well_get_schema(root) first, select 5-15 fields, then call well_query_records. It also gives domain guidance, such as using the accounting graph for real financial statements instead of reconstructing them from raw invoices. This is specific, actionable, and tells the agent exactly when and how to use the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_get_statement_import_resultGet statement import resultA
Read-only
Inspect

Read the outcome of a bank-statement upload started with well_create_statement_upload, by the document_id that tool returned.

well_create_statement_upload already renders a card from its own result — this tool does not create or redraw it. Call it once, shortly after the client has uploaded the file bytes, to learn what happened. The card refreshes itself as extraction and promotion complete, so a later call here narrates the current state in chat; it never advances or re-renders the card.

  • status "not_found_yet": the upload has not landed yet — a NORMAL result right after minting the slot, not an error. Poll again once the file has been uploaded.

  • status "processing": the file is uploaded and the statement is still being extracted / promoted.

  • status "imported" | "needs_account" | "duplicate" | "skipped" | "failed": the terminal outcome. On "imported", matched_count / review_count / minted_count / already_present_count report the promotion's own snapshot counts, taken once at import time and covering every promotable line of the file disjointly; null on any of them means the row predates count tracking — treat as unknown, never as 0. records lists the minted transactions only — matched or ambiguous lines link an existing transaction and are excluded; graph is the frozen record graph for the same snapshot; records_url opens the workspace's transactions table.

This tool reads only — it changes nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
document_idYesThe document_id well_create_statement_upload returned — pre-allocated at mint, before the upload lands.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNo
errorNo
graphNoThe frozen record graph for this import, taken from the same snapshot as `records`. Never present on "processing" or "not_found_yet". Like `records`, its counterparty fields are null (frozen before resolution runs) — see `records_url` for the live values.
statusNo
recordsNoTransactions this import minted as new rows — matched or ambiguous lines link an existing transaction and are excluded. Present only on a terminal "imported" result that carries a snapshot. The snapshot freezes at mint time, so `counterparty` is always null here — resolution runs asynchronously after import; open `records_url` for the live resolved value.
successYes
document_idNo
imported_atNo
records_urlNoLogin-gated deep link to the workspace's transactions table — opened on the first minted record when `records` is non-empty, otherwise the plain table.
minted_countNoLines minted as new transactions. Absent means the row predates count tracking — treat as unknown, never as 0.
review_countNoLines skipped as an ambiguous cross-connector match, pending review. Absent means the row predates count tracking — treat as unknown, never as 0.
matched_countNoLines linked to an existing cross-connector transaction. Absent means the row predates count tracking — treat as unknown, never as 0.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
already_present_countNoLines an earlier import already carried — a partial-overlap re-export mints only the new lines, so the four counts cover the file's promotable lines. Absent means the row predates count tracking — treat as unknown, never as 0.
statement_extraction_idNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=true and destructiveHint=false, and the description goes further by explaining it 'reads only — it changes nothing,' never advances or re-renders the card, and provides detailed status semantics, count snapshot behavior, null handling, and the frozen graph. This is rich behavioral context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is detailed but every sentence earns its place, covering purpose, relationship to the sibling tool, status values, count semantics, and read-only behavior. It is front-loaded with the core purpose and structured with a bulleted list for statuses, making it easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering safety, the description fully explains the statuses, the meanings of the count fields, the content of records vs. graph, and the read-only nature. Nothing needed for correct invocation or interpretation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already describes both document_id and workspace_id with 100% coverage. The description reinforces that document_id comes from well_create_statement_upload and mentions pre-allocation, but this information is already present in the schema. The description does not add substantially new parameter-level meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Read the outcome of a bank-statement upload started with well_create_statement_upload, by the document_id that tool returned.' It clearly distinguishes this from the sibling creation tool by noting it does not create or redraw the card.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs when to call the tool: 'Call it once, shortly after the client has uploaded the file bytes, to learn what happened.' It also contrasts with well_create_statement_upload, saying that tool already renders a card and this one does not, and explains polling behavior for 'not_found_yet'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_invoke_connector_toolInvoke connector toolA
Destructive
Inspect

Run one tool on a connected provider's own MCP server (e.g. create a record in Attio), on behalf of this workspace's connection.

Use this ONLY for an action the user explicitly asked to take on that provider. It is NOT a way to read financial data: Well already syncs invoices, transactions, accounts and the accounting graph from every connected provider — read those with well_query_records instead of calling a provider's own list/read tools.

WORKFLOW:

  1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row.

  2. well_list_connector_tools({ workspace_connector_id }) → the live tool names + input schemas that connection actually exposes right now.

  3. well_invoke_connector_tool({ workspace_connector_id, tool: "<one of the names from step 2>", args: { ... } }).

Only works on connectors that expose an MCP server (e.g. Attio, Notion, Linear) and whose connection is enabled. Returns the provider's tool result, or { success: false, error } if the tool failed / is not granted.

ParametersJSON Schema
NameRequiredDescriptionDefault
argsNoArguments object passed straight to the provider tool. Omit if the tool takes none.
toolYesThe provider tool name to run (one of the connector's available_tools).
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
workspace_connector_idYesThe connected provider's workspace_connector_id (from well_list_connectors).

Output Schema

ParametersJSON Schema
NameRequiredDescription
toolNo
errorNo
resultNo
successYes
error_codeNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool destructive and open-world; the description adds that args pass straight through, that it only works on connectors exposing an MCP server with an enabled connection, and that it returns either the provider's tool result or {success:false,error} on failure or grant denial. It does not contradict the annotations and provides useful behavioral context beyond them, though it doesn't enumerate provider-side side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core definition, then the key exclusion, then a numbered workflow and constraints. It is longer than average, but the extra length is all operational guidance for an open-world invocation tool, with no repetitive filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity dynamic tool, it covers purpose, when to use and not use, prerequisites, the exact upstream calls for parameters, and the failure return shape; the output schema handles return-value details. The only remaining details, such as workspace_id and idempotency_key behavior, are already fully documented in the input schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all five parameters; the description adds the crucial provenance: workspace_connector_id comes off an enabled row from well_list_connectors, tool must be one of the names from well_list_connector_tools, and args are passed straight through from that tool's live schema. This turns the parameters into an executable sequence.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a concrete verb and resource: 'Run one tool on a connected provider's own MCP server' on behalf of the workspace connection. It differentiates itself from the large sibling set by explicitly saying it is not for reading financial data and routing those reads to well_query_records, so an agent can distinguish it from list/query tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit when: only for actions the user explicitly asked to take on the provider, and an explicit when-not: not for reading synced financial data, which should go to well_query_records instead. The numbered workflow names well_list_connectors and well_list_connector_tools as prerequisites, and the final conditions (MCP-server connector, enabled connection) tell the agent when the tool cannot be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_connectorsList connectorsA
Read-only
Inspect

List the connectors a workspace can install AND everything it has already connected, each with a one-click install deep link.

ONE tool answers both halves of the connect question — "what can I connect to Well?" and "what is connected, still syncing, or broken?" — because every existing connection is overlaid onto its catalog row. Do NOT read workspace_connectors records to work out connection coverage; this tool is that answer.

Each entry has:

  • service_id: the connector's stable catalog id (e.g. "stripe"), used in the install link.

  • name, category_id, direction: what the connector is.

  • data_domains: the financial domains it serves — any of "bank", "accounting", "invoicing" — or null for a non-financial connector. One connector can serve several domains (Qonto serves all three). "bank" here means the connector delivers cash movements, which a payroll or billing platform also does; do NOT read it as "this is a bank". To list banks, pass kind: "bank", which the server scopes on its own bank classification.

  • status: "available" connectors are connectable now; "coming_soon"/"unavailable"/"maintenance" are not.

  • is_matched / is_selected: whether this workspace's detected tools matched this connector / already picked it.

  • match_score: 0..1 confidence of that match; null when unmatched. A high score is a tool Well is confident the workspace already uses.

  • is_connected: this workspace has a connection you should REPAIR or MANAGE, not install fresh. True for "enabled", "processing", "error", "need_reconnect" and "suspended"; false for "to_configure" and "disabled", where a fresh install IS the right next step.

  • connection_status: the existing connection's state, or null when this workspace has no connection row for the connector at all. One of:

    • "enabled" — connected and syncing.

    • "processing" — the grant is in and the FIRST sync is still running; data may be partial. Connected: do NOT ask the user to connect it again.

    • "error" — authenticated but its last real sync failed. Offer install_url as a reconnect.

    • "need_reconnect" — the grant is dead and only the user can restore it. Offer install_url as a reconnect, NOT a first install.

    • "suspended" — the connection is held back administratively; tell the user it is paused. The user cannot fix it by reconnecting.

    • "to_configure" — a connect attempt that never completed its handshake. Nothing is connected: offer install_url as a first install, and never claim the tool is connected.

    • "disabled" — the connection was torn down. Offer install_url as a first install. A "degraded" connector never appears: it is resolved server-side against its own sync history into "enabled" or "error", so you never surface a state that clears itself. A connection whose state this build cannot read also reports null, and there is_connected stays true — read the two fields together, and treat "null status, is_connected true" as an existing connection whose health is unknown.

  • workspace_connector_id: the connection instance's id, or null when there is no connection row. This is the id well_invoke_connector_tool and well_list_connector_tools need — resolve it HERE, never via well_query_records on workspace_connectors.

  • last_successful_sync_at: ISO timestamp of the last SUCCESSFUL sync, or null when none has landed yet. An "enabled" connector with null here has a valid grant but has never delivered data.

  • sync_in_progress: a data sync is running right now. Tell the user to wait rather than to act.

  • is_preselected: Well recommends connecting this one now (a high-confidence match with is_connected false). The interactive picker pre-checks exactly these. A "to_configure" or "disabled" row can still be pre-checked — installing it IS the fix. On kind: "accounting" at most ONE row carries it — the single highest-confidence accounting tool — because connecting the accounting software is a pick-one step; every other scope pre-checks each high-confidence match.

  • install_url: a one-click link that STARTS or REPAIRS the connection in Well. It works from any state — it signs the user in if needed, creates their workspace if they have none, then runs the connector's own auth flow — and it covers banks too (a bank opens its bank-login flow pre-selected). Null only when the connector is not "available". Hand this to the user to get started in one click.

install_all_url is a TOP-LEVEL field, not a per-connector one. It is ONE link that installs every installable connector in this result that is not already connected, in the order they are listed. Its reach is wider than the per-row links: a connector the catalog holds by service id alone carries a null install_url and is still installed by this link, so never read a null install_url as "cannot be installed". When the answer offers several connectors to install, hand the user install_all_url and do NOT list the per-connector install_url links beside it — the one link IS the whole offer, and a table of links beside it puts the reader back through several sign-ins. One link carries at most 10 connectors, and install_all_omitted names the service ids it left out, so offer those rows their own install_url. install_all_url is null when the result offers nothing to install. It is null too wherever the result names no set the user has chosen: the unfiltered catalog and the whole bank domain never carry the link, and a name search or an accounting or invoicing domain carries it only while the WHOLE result fits in one link and this page holds all of it — past that the link would stand for whichever rows the page happened to carry. from_selection always carries the link, however many vendors were picked, because the user named each one. Where install_all_url is null, the rows' own install_url links ARE the offer: list them, and never announce a batch link the result does not carry.

Scoping: pass kind ("bank" | "accounting" | "invoicing") to get only the connectors serving that domain — the whole set, server-ordered, including the long tail of bank institutions. Pass q to name-search the full catalog. Omit all three for the curated, matched-first view. Use well_list_connector_tools for a live connection's actions.

Pass from_selection: true for the connect step that FOLLOWS a vendor pick: it returns ONLY the connectors behind the counterparties the user picked on the missing-invoices card this session, every installable one pre-checked, because the user already chose them. It takes no q and no kind — those browse a catalog, and this names a set already decided. An empty list means the session holds no pick for this workspace, or no picked counterparty matched a connector.

Every result carries scope — "catalog", one of the three domains, or "picked_vendors" — naming what the list IS. The card words its title from that field, so a caller must not describe the result as a domain the scope does not name.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoName search across the full catalog (e.g. a specific bank). Omit for the curated, matched-first view.
kindNoScope the catalog to one financial domain: "bank" (every bank and neobank, including the long tail of open-banking institutions, plus the platforms that hold an account like Qonto and Pennylane — never a payroll or billing tool that merely reports transactions), "accounting", or "invoicing". Use this for a connect-a-bank or connect-an-accounting-tool step instead of filtering the default view yourself. Omit for every connectable connector.
limitNoMax connectors to return (1-100, default 50).
titleNoHeading for the connect card shown to the user, OVERRIDING the wording the card otherwise derives from the scope/kind. Use it to frame the step in its flow (e.g. "Connect your accounting tool for the close"). At most 120 characters. Omit to keep the default wording for the requested kind.
offsetNoNumber of connectors to skip, for paging (default 0).
subtitleNoSupporting line under the connect card's heading, OVERRIDING the scope-derived subtitle. At most 240 characters. Omit to keep the default wording for the requested kind.
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
from_selectionNoScope the card to the connectors behind the counterparties the user picked on the missing-invoices card this session, each installable one pre-checked. Use it for the connect step that FOLLOWS a vendor pick, where the user has already chosen and the card must offer only what they chose. Cannot be combined with `q` or `kind` — those name a catalog to browse, and this names a set already decided. Returns an empty list when the session holds no pick for this workspace, or when no picked counterparty matched a connector.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
limitNo
scopeNoWhat this result is a list OF: the requested kind, the picked vendors' connectors, or the curated catalog when neither was asked for. The card words itself from this, so it never describes the rows as a domain that was not requested.
totalNo
offsetNo
successYes
connectorsNo
install_all_urlYesOne link that installs every installable connector in this result. Null when the result offers nothing to install, or when its scope names a set the reader has not chosen. When it is non-null it is the ONLY install link the answer offers — do not list the rows' own install_url beside it. When it is null, the rows' own install_url is the offer instead.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
install_all_omittedYesThe service ids install_all_url could not carry, because one link names a bounded number of connectors. Offer these rows their own install_url instead of promising the batch link covers them.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even though annotations already declare readOnlyHint=true and destructiveHint=false, the description goes far beyond them, explaining nuanced behaviors: the seven connection_status states and their user-facing implications, how null status with is_connected=true should be interpreted, how 'degraded' is resolved server-side, install_all_url null conditions, and is_preselected rules. This is rich behavioral disclosure that annotations alone could never convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but every sentence earns its place given the tool's complexity: 8 parameters, nuanced connection states, install-all behavior, and scoping rules. It is front-loaded with the core purpose, then organized into clear sections for entry fields, install_all_url, and scoping. The structure makes the density navigable rather than overwhelming.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the full decision space: parameter usage, return-field semantics, edge cases like null install_url and empty from_selection results, sibling-tool routing, and even how to word the card via the scope field. With annotations and output schema present, nothing an agent needs to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 100% of parameters with its own descriptions, so baseline is 3. The tool description adds meaningful workflow semantics on top: when to choose kind versus q versus from_selection, that from_selection cannot combine with q/kind, and what 'bank' means in the data_domains context. It does not merely restate the schema, but it also does not need to add much more given the schema's already strong parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: list the connectors a workspace can install AND everything it has already connected, each with a one-click install deep link. It clearly distinguishes itself from siblings by explicitly naming well_list_connector_tools for live connection actions and telling the agent not to use well_query_records on workspace_connectors. The dual-scope purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance for every scenario: pass kind for a domain-scoped catalog, pass q for name search, omit both for the curated view, and use from_selection: true after a vendor pick. It also names exclusions and alternatives, such as 'Use well_list_connector_tools for a live connection's actions' and 'Do NOT read workspace_connectors records to work out connection coverage.' No inference is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_connector_toolsList connector toolsA
Read-only
Inspect

Discover the actions a connected provider exposes (e.g. "what can I do with Attio?").

WORKFLOW:

  1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row.

  2. well_list_connector_tools({ workspace_connector_id }) → the actions that provider offers (name + description + input schema).

  3. well_invoke_connector_tool({ workspace_connector_id, tool, args }) → run one, shaping args from the input schema returned here.

Use this whenever you don't already know a connector's tool names — never guess them.

Every response also carries reconnect_url: a deep link to the connector's setup page in the web app. When success is false or status is "need_reconnect" (the provider's token is stale/revoked, so no tools come back), give the user reconnect_url so they can re-authenticate the connector. Surface it as a clickable link; never invent connector URLs.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
workspace_connector_idYesThe connected provider's workspace_connector_id (from well_list_connectors).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
toolsNo
totalNo
statusNo
successYes
usage_notesNo
reconnect_urlNo
connector_slugNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already mark this as read-only and non-destructive, and the description adds meaningful behavioral context beyond that: every response carries reconnect_url, and when success is false or status is 'need_reconnect,' the agent should surface the link. This gives the agent actionable knowledge about failure behavior and how to handle it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well structured with a clear purpose statement, numbered workflow, explicit usage rule, and a concise error-handling note. Every sentence adds useful information and the most important guidance is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete for a listing tool: it explains when to use it, how to obtain the required id, what the tool returns, and how to handle reconnect failures. The presence of an output schema means return-value details need not be repeated in the description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds context by saying workspace_connector_id comes from well_list_connectors and that args should be shaped from the input schema returned here, but most parameter meaning is already fully documented in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Discover the actions a connected provider exposes' and explicitly says the tool returns 'name + description + input schema' for each action. It also names sibling tools like well_list_connectors and well_invoke_connector_tool, making the purpose easy to distinguish.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear workflow: list connectors, pick the enabled provider, then call this tool, then invoke. It explicitly says to use it 'whenever you don't already know a connector's tool names — never guess them,' which is strong and direct usage guidance with no ambiguity about when it applies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_counterpartiesList counterpartiesA
Read-only
Inspect

List the workspace's counterparty companies and how each one is CATEGORIZED — the company-level industry labels a counterparty carries. Use it for "which suppliers have no category?", "what industries are my counterparties in?", and before categorizing a counterparty so you name real ids instead of guessing.

Name a scope, and say whether to keep only the ones missing a category:

  • periods: [{ calendar_year, calendar_month }, …] (1-12): the counterparties whose invoices those months are still missing, categorized ones included, each row tagged with its month and carrying tx_count, base_total_amount in base_currency, and suggested_retrieval. Every month must have ended.

  • periods PLUS uncategorized_only: true: the same months, keeping ONLY the counterparties that carry no category. Use this whenever the question is which of a period's suppliers still need one, and whenever a step asks the user to categorize them: the categorized ones are not the work, and listing them buries it.

  • uncategorized_only: true alone: a WORKSPACE-WIDE sweep for every counterparty that carries no category, no month involved. Returns 50 rows per page plus total_count; tx_count, base_total_amount and suggested_retrieval are null because the call names no period. When next_cursor is not null the sweep has more counterparties: call again with cursor set to it to read them. It is a POSITION, not a row offset, so categorizing the rows of one page never hides the rows of the next. Only this sweep pages: cursor is refused beside periods.

COST: the period form has no batch endpoint, so each named month is a separate read of that month's spend. Ask for the months the user actually named, not a whole year "to be safe".

Every row carries categories ([{ category_id, name }]) and is_categorized. categorized_count and uncategorized_count count the COUNTERPARTIES OF THE SCOPE, once each however many months they appear in, not the rows returned. Under uncategorized_only the result lists the uncategorized ones alone while categorized_count still counts the ones it withheld, so the two together are the period's coverage and uncategorized_count is the work left. Report both: naming the listed rows as the period's whole counterparty set overstates how much is uncategorized.

TO SET a counterparty's categories, call well_update_company({ company_id, category_ids: [...] }) — that field REPLACES the company's whole set. Read the available labels first with well_query_records({ root: "categories", whereClause: { category_type: { _eq: "company" } } }): that is the company-category catalog. It has no curated allowlist — the labels are minted during enrichment — so pass ids from it rather than inventing a taxonomy.

suggested_retrieval is derived from the PROVIDER match, not from the category. Categorizing a counterparty does not change it; do not tell the user otherwise.

This tool only reads. It categorizes nothing, mints no task, connects nothing and fetches no invoice.

Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).

ParametersJSON Schema
NameRequiredDescriptionDefault
cursorNoThe next page of the workspace-wide uncategorized sweep: pass back the `next_cursor` the previous call returned. Only that sweep pages, so this needs `uncategorized_only: true` and NO `periods`, because a period scope returns every month it covers in one call.
periodsNoThe calendar months whose counterparties to list, 1-12. Each month costs one separate read of that month's spend. Duplicates are refused.
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
uncategorized_onlyNoKeep only the counterparties that carry no industry category. WITH `periods`: the uncategorized counterparties OF those months. Use it whenever the question is which of a period's suppliers still need a category. WITHOUT `periods`: a WORKSPACE-WIDE sweep for every uncategorized counterparty, 50 rows per page plus the total, with a `next_cursor` for the page after this one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
modeNoWhich SCOPE the call asked for; the row fields that are populated follow from it. `periods` whenever the call named months, whether or not it also filtered to the uncategorized ones.
rowsYes
errorNo
hintsNo
successYes
row_countNo
next_cursorNoThe uncategorized sweep's next page: pass it back as `cursor`. Null when this page ends the sweep, absent on the periods scope, which pages nothing.
total_countNoCounterparties MATCHING the call, before the row cap, so a capped sweep says what it left out. On the periods scope: the DISTINCT counterparties `rows` names, and a multi-month call lists one counterparty on one row per month, so row_count can exceed it. Under `uncategorized_only` it counts the uncategorized ones alone; the scope's whole population is `categorized_count` plus `uncategorized_count`.
workspace_idNo
base_currencyNo
periods_coveredNoThe months the result covers, oldest first.
categorized_countNoCOUNTERPARTIES of the scope that carry at least one category, counted over the whole scope, not over `rows`, and counted once however many months a counterparty appears in. Under `uncategorized_only` these are exactly the counterparties the result withheld, so a non-zero figure beside rows that are all uncategorized is the coverage, not a contradiction.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
uncategorized_onlyNoWhether `rows` holds ONLY the counterparties that carry no category. True on the workspace-wide sweep and on a period scope the call filtered. When true, `categorized_count` counts counterparties the result did NOT list.
uncategorized_countNoCOUNTERPARTIES of the scope that carry none, counted the same way. This is the outstanding work; with `categorized_count` it is the scope's whole population.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and destructiveHint, but the description goes well beyond them: it states the tool only reads and categorizes nothing, mints no task, and fetches no invoice. It discloses the per-month cost, the cursor-as-position paging semantics, the distinction between row counts and counterparty counts, and the fact that suggested_retrieval is provider-derived and unaffected by categorization. This adds substantial behavioral context beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every paragraph earns its place: it front-loads the core purpose, structures the three modes clearly, and packs warnings and constraints into distinct labeled sections. The length is justified by the tool's combinatorial parameter behavior and the many traps an agent could otherwise fall into.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, the 100% schema coverage, and the presence of an output schema, the description is complete. It covers all parameter combinations, paging behavior, cost implications, count semantics, null-value behavior, and the relevant sibling calls for adjacent operations. Nothing an agent needs to invoke this tool correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds significant semantic meaning by explaining how periods, uncategorized_only, and cursor combine into three valid usage modes. It clarifies that cursor is refused with periods, that periods accept 1-12 months with each month costing a separate read, and that uncategorized_only alone triggers a paged workspace-wide sweep. This goes far beyond the input schema's field-level descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool lists the workspace's counterparty companies and their company-level industry categories, with a specific verb and resource. It clearly differentiates the three modes (period, period+uncategorized_only, workspace-wide sweep) and distinguishes this tool from category-setting and catalog-reading siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: use it for finding uncategorized suppliers, use uncategorized_only for work-remaining questions, use the sweep for workspace-wide checks, and do not use it to set categories or read the label catalog. It also names the exact sibling calls well_update_company and well_query_records for those adjacent needs, and states that no prerequisite call is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_missing_invoicesList missing invoicesA
Read-only
Inspect

List the supplier invoices a past period is still missing — the settled spend whose invoice has not been collected, one row per counterparty, exactly as the Well app's expense-invoices card shows them. Use it for "which invoices am I missing for ?" and as the input to fetching them.

Name the period ONE way: { calendar_year, calendar_month } (the calendar month, e.g. June 2026 → 2026, 6), { fiscal_year, fiscal_period }, or periods: [{ calendar_year, calendar_month }, …] for SEVERAL months in one call (1-12) — or name NO period at all to use the months the user selected on the period card this session (well_list_periods → the user clicks → well_switch_workspace records them). With no period named and no months selected, the call refuses and tells you to run the period step first. Every month must have ended — a current or future month is refused, and so is the adjustment period (13). Duplicate months are refused.

COST: there is no batch endpoint, so each named month is a separate read of that month's spend. Ask for the months the user actually named, not a whole year "to be safe".

Returns rows, ONE per counterparty for the whole call, never one per month. Each row carries name, tx_count and base_total_amount in base_currency SUMMED over the months it covers, its own months array naming those months (each with that month's tx_count, base_total_amount, proof_task_id, acquisition_status and refusal_reason), and the route fields mode, available_modes, suggested_action, matched_provider_name and matched_connector_service_id, which the provider match resolves once per counterparty. NEVER list a counterparty once per month and never present its months as separate gaps: it is one supplier to chase, and one collection covers every month behind it. Name the months a row spans from its months array. The envelope's own months carries each month's totals (rows are NOT repeated there), periods_covered names the months read, and transaction_count, group_count and dropped_groups are totals across every month read. row_count counts the DISTINCT counterparties, so it is never the sum of the months' own row_count. dropped_groups counts the GROUPS that produced no row — party-less bank operations, unresolved counterparties, unnamed companies — never transactions, and bank_internal and unknown hold one group per month whatever they contain, so quote neither as a quantity of operations. unknown and unnamed_company ARE categorized expense spend still missing a supplier invoice, so an empty rows over a non-zero count is not a complete period; bank_internal alone is, since no supplier can invoice a party-less operation. The single-month fields calendar_year, calendar_month, fiscal_year, fiscal_period and period_label appear ONLY when the call named exactly one month.

Every row also carries transactions — the counterparty's own lines behind the row, each with date, description (the bank's remittance text), category, amount, currency and base_amount. amount is signed and stays in the transaction's own currency, so never add those together across a row; base_amount is the same line in base_currency, and the magnitudes of those DO add up to base_total_amount. The list is capped at 25 per row and transactions_omitted says how many the cap left out — quote that number instead of implying the list is complete.

mode is the ONE route the card suggests for that row: agent (a browser agent can collect it from the supplier portal), connect (connect the named service and Well fetches it), upload (the user supplies the file). available_modes lists every route the row offers instead of only the suggested one — agent and upload on every row, plus connect when the catalog holds a connector for the matched provider, so 2 or 3 entries. Present mode as the suggestion and available_modes as the choice.

Only CATEGORIZED expense transactions are considered — uncategorized spend is not listed, so poor categorization coverage under-reports the gaps; disclose the hints.

This tool reads the user's data and changes none of it. It does not mint tasks, start a close, connect anything, or fetch any invoice.

Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).

ParametersJSON Schema
NameRequiredDescriptionDefault
periodsNoSeveral calendar months in one call, 1-12. Each month costs one separate read, so name only the months you need. Duplicates are refused.
fiscal_yearNoFiscal year (the calendar year the workspace's fiscal year STARTED in).
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
calendar_yearNoCalendar year, e.g. 2026.
fiscal_periodNoFiscal period, 1-12. The adjustment period (13) is refused: it has no calendar month.
calendar_monthNoCalendar month, 1 = January … 12 = December.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYesThe card's rows, ONE per counterparty for the whole call, in the order the oldest month listed them, each naming the months it covers in `months`. A counterparty owing an invoice in several of the months read is one row, never one per month.
errorNo
hintsNo
monthsNoPer-month totals, oldest first.
successYes
row_countNoRows in `rows`, which is the DISTINCT counterparties the call found. Never the sum of the months' own `row_count`.
fiscal_yearNoPresent only when the call named exactly one month.
group_countNoGroups the reads returned before the card's projection.
period_labelNoHuman-readable label of the period, e.g. "June 2026". Present only when the call named one month.
workspace_idNo
base_currencyNo
calendar_yearNoPresent only when the call named exactly one month.
fiscal_periodNoPresent only when the call named exactly one month.
calendar_monthNoPresent only when the call named exactly one month.
dropped_groupsNo
periods_coveredNoThe months the result covers, oldest first.
periods_requestedNoHow many calendar months the call named.
transaction_countNoEvery transaction missing its invoice, across all groups and all months.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description discloses that the tool changes no data, does not mint tasks, does not start a close, does not connect anything, and does not fetch invoices. It also explains subtle behaviors such as one row per counterparty regardless of month count, row_count counting distinct counterparties, the transactions cap, and refusal of current/future/adjustment periods—far more than annotations alone provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but the tool is genuinely complex and every major section earns its place: purpose, period selection, cost, result semantics, modes, categorization caveats, and side-effect guarantees. It is front-loaded with the purpose and would be a 5 but for some repeated warnings about one row per counterparty that, while useful, are stated more than once.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with six optional parameters and a rich output schema, the description covers all decision-relevant context: how to select periods, what rows represent, what each mode means, which caveats to surface to users, what counts as a complete result, and how workspace resolution works. Nothing material an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents every parameter, but the description adds critical meaning the schema cannot express: the three mutually exclusive period-naming forms, the requirement that months must have ended, rejection of duplicate months and period 13, the per-month cost model, and how workspace_id resolves when omitted. This goes well above the baseline for a fully covered schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource: 'List the supplier invoices a past period is still missing' with an explicit definition of what counts as missing. It also nails the cardinality ('one row per counterparty') and references a recognizable UI card, so an agent can distinguish this from generic list tools without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear use case ('which invoices am I missing for <month>?'), explains how to name periods, when to omit a period, refusal conditions, and even cost-aware guidance to request only the months the user named. It stops short of explicitly naming alternative tools to use instead, but it is exceptionally clear on when and how to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_periodsList periodsA
Read-only
Inspect

List the recent accounting months of the workspace, with each month's close status, its invoice-retrieval state, and the counts that describe how much work it holds. Use this to ask the user WHICH month or months to work on before any close, review, or month-scoped read — do not guess a month, and do not derive one from today's date yourself.

Each entry carries:

  • calendar_year / calendar_month: the month itself.

  • fiscal_year / fiscal_period: the same month in the workspace's fiscal calendar — this is the pair every close endpoint and close tool takes.

  • label: the month written out, e.g. "March 2026".

  • is_complete: the calendar month has ended. A still-accruing month is never a valid close target.

  • selectable: the month can be CLOSED. False for a month that has not ended, one already closed, one with nothing to close, and a December whose year-end close is not supported yet. Read this one for a close pick.

  • inspectable: the month can be LOOKED INTO. A reader can open its transactions, its missing invoices and its days. True for EVERY month that has begun, the month in progress included. False only for a month that has not begun. It reads no close verdict and no activity count, so a closed month, an empty month and a workspace with no accounting connector at all still have readable months. An empty month answers with an empty list, which is an answer. Read this one for a retrieval or review pick; every selectable month is also inspectable.

  • close_status: "closeable" (ready), "not_ready" (work remains), "closed" (already locked), "nothing_to_close" (no activity), or null when the workspace has no verdict for that month.

  • close_reason: the blocking reason behind the status, or null.

  • invoice_state: "missing_invoices" (at least one counterparty still owes a supplier invoice), "has_invoices" (checked, and nothing is missing), or "none" (no state: no activity, the month has not begun, or the check could not run). Never read "none" as "nothing missing".

  • missing_invoice_count: how many counterparties owe an invoice for the month — the rows well_list_missing_invoices would return. 0 whenever invoice_state is "none", including when the check did not run.

  • transaction_count: how many transactions the month holds, whatever delivered them.

  • bank_transaction_count: the subset of transaction_count delivered by a connector the workspace actually BANKS with, meaning a bank, a neobank, or a treasury or spend platform whose product is an account. An accounting platform and a payment processor deliver transactions too, so transaction_count is NOT a bank signal. Only this field answers "has a bank fed this month". A transaction counts as not-bank when its source connector is unknown, or when that connector has since been disconnected, so a zero here never licenses skipping a bank-connection step.

  • unposted_invoice_count: invoices the month HAS that have not posted to the ledger. This is a posting gap, not a missing invoice — do not present it as one.

  • uncategorized_transactions: transactions in the month not yet categorized — the "help categorize" errand behind a not-ready close.

  • categorized_unposted_transactions: categorized transactions not yet posted to the ledger — part of the "review and book" errand.

  • days: the DAYS of the month that carry a retrieval state, ascending, each { day, state } over the same vocabulary as invoice_state. A day is "missing_invoices" when it holds settled expense spend still missing its supplier invoice, and "has_invoices" when it holds activity and no such gap. Days with neither are OMITTED, so an absent day means "none". days is empty for every month whose invoice_state is "none" — an unchecked month has no day the tool can call clean. This is calendar detail for a picker to paint; quote the month's own counts, not a day list, when answering in prose.

  • close_days: present ONLY for a purpose: "close" call — the DAYS carrying a non-neutral close-readiness state, ascending, each { day, state } over "posted" / "progress". A day absent from it is "neutral" (nothing to close). Calendar detail for the close picker, like days is for retrieval.

default_period is the oldest month that is ready to close, falling back to the oldest still in progress. Offer it as the default choice. It reads selectable, so it is null whenever no month in the window can be CLOSED, and a null one does not mean the window is empty: an inspectable month can still be worked on for invoice retrieval.

PURPOSE: pass purpose: "close" when the user is closing the books, so the picker paints close readiness and each month carries its close_days and the categorize / review counts. Omit it (or purpose: "collect") for invoice retrieval, the default. This is the calling skill's intent — set it from the flow, never from the user's phrasing.

WINDOW: by default the months most recent calendar months, ending with the current one. Pass year instead to get ONE calendar year in full — all twelve of its months, December back to January — which is how you reach a year the recent window does not cover, backwards or forwards. navigable_years reports the range year is answered for.

A year ahead of today comes back in full and every month of it is selectable: false and inspectable: false with close_reason "period_not_ended": books close on a month that has ENDED, and a month that has not begun holds nothing to read. Show such months when the user asks to look ahead, and say why they cannot be picked. Never omit them.

COST: the invoice state is read per month from a separate endpoint, so a wide window costs one extra read for every month that holds activity, plus one day-coverage read per calendar year those months touch. Ask for the months the user needs, not 24 by default. A wholly future or wholly empty year is cheap — no month in it can hold a settled gap, so none is read.

Call this directly — no other tool call is needed first (the workspace is resolved from the caller's authorized token, same as every other well_* tool).

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoOne calendar year to return in full — all twelve of its months, December back to January, instead of the recent window. Use it to reach a year the recent window does not cover, in either direction; future months come back visible but never selectable. Accepted range: 2000-2100, also reported as `navigable_years`.
titleNoHeading for the picker card shown to the user. At most 120 characters.
monthsNoHow many recent calendar months to return, ending with the current month. Each month holding activity costs one extra read for its invoice state. Ignored when `year` is given.
purposeNoWhy the months are being listed, set by the calling skill (not guessed from the user's words). "close" is book closure: the card paints close readiness, and each month carries its per-day `close_days` and the counts behind its "why not ready" errands. Omit or "collect" for invoice retrieval (the default), which paints the retrieval axis and skips the close-readiness fields.
subtitleNoSupporting line under the picker card's heading. At most 240 characters.
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
hintsNo
periodsYes
successYes
workspace_idYes
base_currencyYes
default_periodYes
navigable_yearsYesThe calendar years a `year` request is answered for. A picker's year steppers stop here.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
fiscal_year_start_monthYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it read-only and non-destructive, and the description adds substantial behavioral context: the subtle 'selectable' vs 'inspectable' distinction, 'invoice_state: none' explicitly never meaning 'nothing missing', the cost model of one extra read per active month, and the null default_period behavior. No statement contradicts the readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, uses clear section headers (PURPOSE, WINDOW, COST), and almost every caveat earns its place given the tool's semantic traps. It is long, and some field-by-field explanations could be deferred to the output schema, so it is not maximally concise for a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with six optional parameters, many sibling month-scoped tools, and subtle return-field semantics, the description covers selection intent, edge cases (future years, empty months, disconnected connectors), cost behavior, and defaults. Nothing an agent needs to call it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds meaning beyond the schema: purpose must be set by the calling skill and never inferred from wording, year returns a full calendar year and future months are included but unselectable, months has a cost implication, and workspace_id falls back to the token's primary workspace. These are operational details the schema alone does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'List the recent accounting months of the workspace' with close status, invoice-retrieval state, and work counts. It immediately states the tool's role ('Use this to ask the user WHICH month or months to work on before any close, review, or month-scoped read'), which sets it apart from siblings like well_list_missing_invoices that operate on an already chosen month.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to call it ('before any close, review, or month-scoped read'), what not to do ('do not guess a month, and do not derive one from today's date yourself'), and that no prerequisite call is needed. The PURPOSE section also tells the agent whether to pass 'close' or omit it based on the flow's intent, which is actionable selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_list_workspacesList workspacesA
Read-only
Inspect

List the workspaces this connection is authorized to access.

Use this FIRST when a single token may cover more than one workspace. Each entry has:

  • workspace_id: pass this as the workspace_id argument on other tools to target one workspace.

  • workspace_name: human-readable name (null if it can't be resolved).

  • is_primary: true for the token's default workspace (used when you omit workspace_id on a write).

  • identity: the company behind the workspace (registered name, trade name, registry number, country, website, currency, fiscal year start), so two similarly-named workspaces can be told apart. Every field is null when the workspace has no accounting settings yet. Tax identifiers are deliberately not included.

  • has_bank_transactions: whether a connector the workspace BANKS with has delivered any transaction to it, meaning a bank, a neobank, or a treasury or spend platform whose product is an account. An accounting platform and a payment processor deliver transactions too and do NOT count here. Neither does a transaction whose source connector is unknown, whose install has since been disconnected, or whose catalog entry has been retired. Only true shows that a bank has fed this workspace: false means no such transaction was found and null means the signal could not be read, so an absent value is never a zero and neither value licenses skipping a bank-connection step. Read this before any month read when the flow needs to know whether the workspace banks with anything at all.

The result also carries session — what the user's card clicks have already recorded this session: pinned_workspace_id (null when not switched), workspace_queue (the workspaces to work through next, empty when none), selected_periods (the months picked on the period card, empty when none), and selected_counterparties (the counterparties picked on the missing-invoices card, with the workspace their company ids belong to; null when none was picked). Call this any time you need to resync with clicks you may have missed.

When the token authorizes a single workspace you can omit workspace_id everywhere; when it authorizes several, read tools fan out across all of them unless you pass a workspace_id, and write tools require one.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspace_idNoTarget workspace. Optional: this tool describes the token itself rather than one workspace's data, so omitting it returns the same answer.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
sessionNoWhat this session's card clicks recorded so far; null/empty fields when nothing was clicked yet.
successYes
workspacesYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial behavioral detail beyond that: the optional-workspace_id behavior, null semantics for identity and bank-transaction fields, deliberate omission of tax identifiers, and the meaning of has_bank_transactions as a signal rather than a definitive zero. It also discloses the session resync capabilities, leaving little hidden behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though long, the description earns its length: it is front-loaded with the core purpose, then uses bullets for entry fields and paragraphs for nuanced semantics like bank-transaction detection and session resync. Every sentence carries actionable information, and the structure makes the complex content navigable rather than sprawling.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is fully complete for a tool of this complexity. It covers the authorization context, the meaning of every returned entry field, the workspace_id selection behavior, bank-signal caveats, and session-staleness resync. Even with an output schema present, this description goes beyond what is needed and leaves no obvious agent question unanswered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%: the input schema already fully describes the only parameter, including that it is optional and that omitting it returns the same answer. The description reinforces this by explaining the workspace_id argument's role on other tools, but it does not meaningfully add new parameter-level semantics beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb-resource statement: 'List the workspaces this connection is authorized to access.' It specifies the resource, the authorization scope, and immediately positions the tool as the first step when a token may span multiple workspaces, distinguishing it from workspace-scoped operations like well_switch_workspace or well_get_own_company.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use instructions: 'Use this FIRST when a single token may cover more than one workspace,' and 'Call this any time you need to resync with clicks you may have missed.' It also explains when workspace_id can be omitted versus when it must be provided, giving actionable context for read and write tools across the API.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_preview_invoice_fetchPreview invoice fetchA
Read-only
Inspect

Preview which vendors a past period is still missing supplier invoices from, where each one's invoices are, and which route would obtain them. Use it for "what would happen if I fetched 's missing invoices?" before anything runs.

Name the period ONE way: { calendar_year, calendar_month } (the calendar month, e.g. June 2026 → 2026, 6), { fiscal_year, fiscal_period }, or periods: [{ calendar_year, calendar_month }, …] for SEVERAL months in one call (1-12) — or name NO period at all to use the months the user selected on the period card this session (well_list_periods → the user clicks → well_switch_workspace records them). With no period named and no months selected, the call refuses and tells you to run the period step first. Every month must have ended — a current or future month is refused, and so is the adjustment period (13). Duplicate months are refused.

COST: there is no batch endpoint, so each named month is a separate read of that month's spend. Ask for the months the user actually named, not a whole year "to be safe".

Returns vendors — EVERY vendor of the rows THIS CALL covers, one entry per supplier portal ACROSS the whole window (one portal is one place to go, however many months it spans), or one per counterparty where no portal matched: name, provider_id, domain, url and url_source, the counterparties it covers (each tagged with calendar_year, calendar_month, period_label and suggested_route), tx_count, base_total_amount in base_currency. THE ROUTE NEVER FILTERS vendors: a vendor Well has no published flow and no connector for is listed exactly like the rest, with its route on its counterparties. WHAT the call covers is a separate question, and two fields answer it: a counterparty pick narrows the rows to the picked companies (see scoped_to_selected_counterparties below), and a hints line names any group the projection could produce no vendor for. So vendors is every vendor of the rows THIS CALL covers, which is the whole period only when neither of those is present. upload_rows (the user must supply the file) and connect_rows (connecting the named service fetches it) carry the same counterparties again, split by route, with the same month tags.

WHERE A VENDOR'S INVOICES ARE: url_source says how much url knows. "blueprint" is the page Well's own published flow opens, so it IS the billing page. "enrichment" is the vendor's front door — the catalog entry address or the company's domain — so the user still has to find the invoices on it. "none" means no address at all and url is null. Never present an "enrichment" address as the invoice page. url_source informs and gates nothing: an "enrichment" vendor is offered for the pick, and carried on the link, exactly like a "blueprint" one.

ROUTES DESCRIBE HOW, NOT WHETHER: a counterparty Well holds a connector for is in connect_rows AND under its vendor, where its entry reads suggested_route: "connect" and connect_routed_counterparties counts it. Connecting is the route to suggest; the agent run stays available so the user has a way through when the connector does not work for them. A counterparty on suggested_route: "upload" is in upload_rows too. Never present the same counterparty as two separate gaps — it is one gap seen twice, so count it once.

counts covers the rows this call actually read, and every field states its own unit: vendors and agents count PORTALS, agent_tx counts TRANSACTIONS, upload and connect count COUNTERPARTY ROWS — one counterparty per month. They are not summable with each other: never add them into one total, and vendors is never the sum of the other four, because every counterparty reaches the vendor list whichever route it takes. A total over the whole window counts the DISTINCT counterparties named in vendors, and a counterparty appearing again in upload_rows or connect_rows is the same gap seen by its route. Across several months a counterparty counts once per month in upload and connect, while vendors and agents count each portal once for the window, so neither is the sum of the months' own. WHEN scoped_to_selected_counterparties IS PRESENT, vendors, upload_rows, connect_rows, counts AND months COVER ONLY THE PICKED COUNTERPARTIES, NOT THE WHOLE WINDOW: for the months the pick bounded, every row and every figure here is built from the picked rows alone, and selection_scope says how many counterparty rows it left out. Never report those rows as every vendor the period is missing an invoice from, and never report those counts as the period's own — state the truncation and its size, and point at well_list_missing_invoices for a fresh card that drops the pick. Without that field the counts cover the whole window. months gives each month's own counts; periods_covered names the months. A sum is null when any member of it had no FX rate, never a partial figure. The single-month fields calendar_year, calendar_month, fiscal_year, fiscal_period and period_label appear ONLY when the call named exactly one month.

THIS TOOL LAUNCHES NOTHING. It creates no task, starts no run, and fetches no invoice — mode is always "preview" and nothing_launched is always true. Launching the agents is NOT available on this surface, so present the preview as information and do not promise to run it.

collect_url is the ONE link to hand the user: the /collect page, which asks the Well browser extension to run these portals. It names each portal by its provider_id, and that id is the only field that decides which portal runs — a name or an address in the link labels a row and nothing more. Give the link as returned and never build one or edit its parameters. The page starts nothing until the user acts on it, it reports which portals the extension accepted, and it never reports that an invoice arrived. The link also names this workspace, and that name gates WHO may act on the link: the page starts nothing until the reader is signed in to Well as a member of it. It does NOT choose where the invoices land — the extension files into whichever workspace it is signed in to — so never tell the user the link picks the destination. THE LINK CARRIES EVERY VENDOR THAT HAS AN ADDRESS, whatever its url_source and whether or not Well holds a published flow for it. Deciding what a vendor's invoices need once the page opens belongs to the app and the extension, not to this read, so url_source labels a vendor and never withholds it. Two things still keep a vendor off the link: no address at all, and no provider_id the link can address. collect_url is null when the window holds no addressed vendor at all; collect_url_omits names the vendors a full window pushed past the 25-portal ceiling, and collect_url_unaddressable names the ones the link cannot name. A vendor on either list is still missing its invoice, so say the link cannot carry it, and offer the upload or the connect route from upload_rows and connect_rows instead. Never say it has nothing outstanding.

Only CATEGORIZED expense transactions are considered — uncategorized spend is not counted, so poor categorization coverage under-reports what an agent run would cover; disclose the hints.

Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).

ParametersJSON Schema
NameRequiredDescriptionDefault
periodsNoSeveral calendar months in one call, 1-12. Each month costs one separate read, so name only the months you need. Duplicates are refused.
fiscal_yearNoFiscal year (the calendar year the workspace's fiscal year STARTED in).
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.
calendar_yearNoCalendar year, e.g. 2026.
fiscal_periodNoFiscal period, 1-12. The adjustment period (13) is refused: it has no calendar month.
calendar_monthNoCalendar month, 1 = January … 12 = December.

Output Schema

ParametersJSON Schema
NameRequiredDescription
modeNo
errorNo
hintsNo
countsNoThe whole window's counts. `vendors` and `agents` count the distinct portals across it, so neither is the sum of the months' own. `upload` and `connect` add each month's counterparty rows, so a counterparty missing an invoice in two of the months read counts once per month.
monthsNoPer-month route counts, oldest first.
successYes
vendorsYesEVERY vendor of the rows THIS CALL covers, whatever route its invoice would arrive by — one entry per supplier portal across the whole window, or per counterparty where no portal matched. The ROUTE never filters this list: a vendor Well has no published flow and no connector for is listed exactly like the rest. What the call covers can still be narrower than the period, and the envelope says so: when `scoped_to_selected_counterparties` is present these are the picked counterparties alone and `selection_scope` sizes the remainder, and a `hints` line names any group the projection could produce no vendor for.
collect_urlNoThe `/collect` entry that hands these vendors to the Well browser extension, naming each one by its `provider_id` and naming this workspace as the link's authorization scope. The page starts nothing until the reader is signed in to Well as a member of it. It carries every vendor that has an address, whatever that address's `url_source`, because what a vendor's invoices need once the page opens is the app's and the extension's decision rather than this read's. Null in three unrelated cases: no vendor of the window carries an address, none of the addressed vendors carries an id the link can address, or this read could not name the workspace the link authorizes. The hints name which one, and only the first is a verdict on the vendors. Opening it starts nothing on its own: the user acts on the page.
fiscal_yearNoPresent only when the call named exactly one month.
upload_rowsYesCounterparties whose invoice only a manual upload can obtain.
connect_rowsYesCounterparties whose invoice arrives by connecting a service.
period_labelNoHuman-readable label of the period, e.g. "June 2026". Present only when the call named one month.
workspace_idNo
base_currencyNo
calendar_yearNoPresent only when the call named exactly one month.
fiscal_periodNoPresent only when the call named exactly one month.
calendar_monthNoPresent only when the call named exactly one month.
periods_coveredNoThe months the result covers, oldest first.
selection_scopeNoWhat the pick removed. Present with `scoped_to_selected_counterparties`, so the size of the truncation is readable beside the result.
nothing_launchedNoAlways true — this tool never starts anything.
collect_url_omitsNoThe portals `collect_url` does NOT name, because one link carries at most 25. Present only when the ceiling left some out. Report those vendors as outside the link — it starts nothing for them.
periods_requestedNoHow many calendar months the call named.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
collect_url_unaddressableNoThe vendors `collect_url` does not name: the vendor carries no address at all, or it carries one but no catalog id the link can address. A missing published flow is NOT among the reasons, because the link takes an enrichment address exactly like a blueprint one. Present only when the window holds some. They are real gaps and they are listed in `vendors`; report them as vendors the link cannot carry, never as absent.
scoped_to_selected_counterpartiesNoPresent when a counterparty pick narrowed this preview: for the months the pick was made against, every route below covers only those companies. A month outside the pick is covered in full.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description goes well beyond that. It explicitly states 'THIS TOOL LAUNCHES NOTHING', guarantees mode is always 'preview' and nothing_launched is always true, explains refusal and null-sum behavior, and details the collect_url semantics including the 25-portal ceiling and unaddressable vendors. There is no contradiction between the description and the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized into clear thematic paragraphs and front-loads the core purpose, but it is very long and contains some redundant restatement — for example, the point that 'vendors' is every vendor of the rows this call covers is made multiple times. The density is mostly justified given the tool's complexity, but tightening the repeated clarifications would improve readability without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool this complex, the description is remarkably complete. It covers output semantics for vendors, upload_rows, connect_rows, counts, months, periods_covered, selection_scope, collect_url, url_source, hints, and the uncategorized-spend limitation. It also explains what the tool does not do, such as launching tasks or fetching invoices, and how to handle scoped results. The presence of an output schema lowers the burden, but the description goes far beyond that baseline.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema description coverage is 100%, the description adds substantial meaning beyond the schema. It explains that the period must be named exactly one way, gives concrete examples for calendar versus fiscal versus periods arrays, clarifies the fallback to user-selected months when no period is named, and warns that each month is a separate read so the agent should ask only for the months actually named. It also adds refusal semantics for duplicates, future months, and the adjustment period that the schema alone does not fully convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair — 'Preview which vendors a past period is still missing supplier invoices from' — and adds scope by stating what the preview is for, what it covers, and what it never launches. It also differentiates itself from the sibling well_list_missing_invoices by explicitly pointing there for a fresh card and by emphasizing that this call only previews and runs nothing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit trigger: 'Use it for "what would happen if I fetched <month>'s missing invoices?" before anything runs.' It also states when the call refuses (no period named and no selected months, current/future months, adjustment period 13, duplicate months), tells the agent not to request a whole year just to be safe, and names well_list_missing_invoices as the alternative when a fresh card is needed. It even instructs that launching agents is not available on this surface, so the preview must be presented as information only.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_query_recordsQuery recordsA
Read-only
Inspect

Query records from Well's database.

⚠️ WORKFLOW:

  1. To SHOW the user a table of a record type, just omit fields. You never choose columns for presentation: the table the user sees is ALWAYS the root's display view in the Well web app's column order, trimmed on the widest roots to what fits a chat-width table.

  2. To answer a targeted question, call well_get_schema(root) FIRST to discover available fields, then name in fields ONLY the extra values you need (5-15 typically). They are ADDED to the display view in the payload you read — they do not replace, reorder, or trim the columns the user sees.

ROOTS (read-only — all 33): companies, people, connectors, invoices, documents, transactions, accounts, payment_means, workspace_connectors, memberships, cards, checks, ledger_accounts, journals, journal_entries, tax_rates, exchange_rates, invoice_transactions, categories, account_balances, tasks, workspaces, invoice_payment_means, chat_conversations, blueprint_runs, workspace_connector_sync_logs, media, emails, phones, web_links, locations, invoice_items, billing_events (The accounting graph — ledger_accounts, journals, journal_entries — and balances/rates are read-only projections owned by the sync/posting pipelines; query them for financial context, you cannot create/update them here. Sub-resources like emails/phones/locations are usually richer when read via their parent company/person.)

CATEGORY CATALOGS: "categories" holds two independent taxonomies, separated by category_type. Always filter on it — an unfiltered read mixes them:

  • whereClause: { category_type: { _eq: "company" } } is the COMPANY-CATEGORY catalog: the industry labels a counterparty carries, and the ids well_update_company({ category_ids }) accepts. There is no curated allowlist — the labels are minted during enrichment — so read them here rather than inventing a taxonomy.

  • whereClause: { category_type: { _eq: "transaction" } } is the management/transaction taxonomy.

CONNECTED TOOLS: do NOT use this tool to show the user what they have connected — call well_list_connectors instead. It owns that job: connection status, and an install link for anything not connected yet. Query root "workspace_connectors" here only for genuine RECORD-level needs — reading sync timestamps, filtering connections, joining them with other roots. ("connectors" is the installable catalog; "workspace_connector_sync_logs" is per-sync history.)

Well already syncs the providers' data into the roots above — invoices, transactions, accounts, the accounting graph. ALWAYS read it from here. well_invoke_connector_tool and a provider's own tools are for an ACTION the user explicitly asked to take on that provider (e.g. "create this record in Attio"), never a way to fetch data Well already holds.

EXAMPLE - show the user their invoices (no fields, ever): well_query_records({ root: "invoices", limit: 50 })

EXAMPLE - answer "how much is still owed on the unpaid invoices?": well_query_records({ root: "invoices", fields: [["invoices", "balance_due"]], whereClause: { "payment_status": { "_in": ["unpaid", "partial"] } } }) // balance_due arrives in the rows for you to total up; the user still sees the // standard invoices table, with its identity, counterparty and status columns.

⚠️ RULES:

  • fields is ADDITIVE — it widens the data you receive, never the table the user sees

  • Omitting fields (default view) or naming a few extras both beat allFields

  • Field paths from schema: "invoices.issuer.name" → ["invoices", "issuer", "name"]

  • Default 50 records per request, max 500.

ONE CALL IS THE ANSWER — do not walk the root: Every response already carries totalCount (ALL matches, not just this page) and records_url (the full web-app table, with your filter and sort already applied). So a request to see a record type is ONE call: the user gets a table of the first page, the count tells them how many there are, and the link takes them to the rest. "Show me all my invoices" is answered by one call + the link — NOT by fetching 483 rows into this conversation.

  • A non-null nextCursor is NOT a to-do. It means more rows exist, which totalCount already told you and the link already covers.

  • Never paginate to compute a total, count, average or breakdown: aggregate over the filtered set instead. Summing a paginated sample produces a wrong number.

  • Never paginate to "be thorough". Large roots will exhaust the output limit mid-walk, and the user ends up with nothing legible.

  • Paginate ONLY for per-row work over every match that no aggregate can express, and tell the user the cost before starting. Then: pass the returned nextCursor as cursor; nextCursor: null is the last page.

FILTERING (whereClause):

  • Uses Hasura-style operators on field names.

  • Safe operators (work on ALL field types): _eq, _neq, _in, _nin, _is_null

  • Numeric/date only: _gt, _gte, _lt, _lte

  • Text only: _like, _ilike

  • When unsure of a field's type, prefer _eq or _in (they always work).

  • Combine with _and, _or, _not

  • For relationship fields, use nested syntax: { "issuer": { "company_id": { "_eq": "" } } }

  • NEVER select the workspace's OWN records by matching a company name. One legal entity appears under several labels — a registered name, a trade name, a bank-issued label — so a name filter silently drops rows and the total reads as complete. On the invoices root, pass partyScope instead: it resolves the workspace's own side on the server, so this query needs no id lookup and no extra call. Call well_get_own_company for the id only when a root has no partyScope and you must filter on issuer_pk / receiver_pk or the nested company_id yourself.

  • Match a counterparty by id too whenever you have one. Reach for _ilike on a name only to DISCOVER candidates to show the user, never to compute a figure you will report. Examples: { "status": { "_eq": "unpaid" } } { "grand_total": { "_gt": 1000 } } { "local_currency": { "_eq": "EUR" } } { "_and": [{ "status": { "_eq": "unpaid" } }, { "grand_total": { "_gte": 500 } }] } { "issuer": { "company_id": { "_eq": "" } } }

SORTING (orderBy):

  • Sort by any field: { field: "grand_total", direction: "desc" }

  • Default sort is by primary key ascending.

Returns { rows, totalCount, nextCursor, success }.

ParametersJSON Schema
NameRequiredDescriptionDefault
rootYesThe entity type to query — any of the 33 read-only roots (companies, people, connectors, invoices, documents, transactions, accounts, payment_means, workspace_connectors, memberships, cards, checks, ledger_accounts, journals, journal_entries, tax_rates, exchange_rates, invoice_transactions, categories, account_balances, tasks, workspaces, invoice_payment_means, chat_conversations, blueprint_runs, workspace_connector_sync_logs, media, emails, phones, web_links, locations, invoice_items, billing_events). Call well_get_schema(root) first to discover fields.
limitNoMax records to return (default 50, max 500)
cursorNoOpaque cursor for the next page. Omit for the first page, then pass nextCursor from the previous response.
fieldsNoEXTRA field paths to add to the root's display view, for values you need to reason about. Each path is an array whose first segment is the root's table name — use the paths well_get_schema(root) returns verbatim, which is the root name for every root except people (whose table is peoples); a path opening with any other segment is dropped. Additive only: they widen the payload you receive, and the columns the user sees stay the root's display view (the ones the Well web app shows) no matter what you pass here. A scalar a composite renders comes back AS that composite — asking for grand_total gets you composite_total_amount_currency, with grand_total inside it — so read `columns` for what was actually materialized. Omit unless you need a value the display view does not carry.
orderByNoSort results by a field. Example: { field: "grand_total", direction: "desc" }
allFieldsNoIf true, automatically fetches all scalar fields from schema. No need to specify fields.
partyScopeNoWhich side of an invoice the workspace itself occupies, resolved from its own company rather than a party name. `invoices` root only. "purchase" = the workspace owes it (payables); "sales" = the workspace is owed (receivables); "intra_self" = both parties are companies the workspace owns; "unattributed" = Well cannot place it on either side. The four partition every invoice, so report the "unattributed" count beside any payable total rather than dropping it — an unattributed invoice may still be owed. Prefer this over hand-writing an issuer/receiver filter.
whereClauseNoHasura-style filter object. Operators: _eq, _neq, _gt, _gte, _lt, _lte, _like, _ilike, _in, _nin, _is_null. Example: { "status": { "_eq": "unpaid" } }
workspace_idNoTarget workspace. Omit to query every authorized workspace at once; each row comes back tagged with the workspace it belongs to.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYesQuery results
errorNo
columnsNoThe materialized columns in display order, with each composite substituted in place of the source fields it consumed. A row object's key order does not preserve this — the flattener appends reconstructed composites last — so a UI that wants the web app's column order must read it from here.
successYes
returnedYesNumber of rows returned
columnMetaNoPer-column field meaning, keyed by the same column paths as the rows. `context` = what the field means; `enrichment` = how the value is sourced (e.g. Bank sync, AI extraction). Only documented columns appear. Read this to interpret the returned values.
nextCursorNoCursor for the next page. null means last page.
totalCountYesTotal matching records
records_urlNoLogin-gated deep link to the FULL web-app records table for this root (real DataTable: composites, inline editing, resize/pin), carrying this call's `whereClause` and `orderBy` so it opens on the same rows. Hand it to the user for everything past this page — it is the answer to 'show me all of them', not pagination. Null when no workspace is in context or no web page serves the root.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description strongly reinforces read-only behavior. It adds substantial behavioral detail beyond the annotations: `fields` is additive and never changes what the user sees, every response carries totalCount and records_url, nextCursor should not trigger pagination for aggregates, and same-entity name filtering can silently drop rows.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but tightly structured with clear sections: WORKFLOW, ROOTS, CATEGORY CATALOGS, CONNECTED TOOLS, RULES, ONE CALL, FILTERING, SORTING. It front-loads the most important workflow guidance and every section carries operational value rather than filler or restatement of the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 9 parameters, nested objects, an output schema, and a large sibling set, the description is exceptionally complete. It covers root selection, field discovery, filtering operators, sorting, pagination semantics, return shape, anti-patterns, and sibling-tool routing, leaving no critical ambiguity for an agent selecting or invoking this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds meaning well beyond the schema. It explains field-path conversion ('invoices.issuer.name' → ['invoices', 'issuer', 'name']), safe vs type-restricted whereClause operators, the default limit of 50 and max of 500, the semantics of partyScope, and the additive behavior of `fields`.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Query records from Well's database', giving a specific verb and resource, and goes further by enumerating all 33 roots. It explicitly differentiates from sibling tools: 'do NOT use this tool to show the user what they have connected — call well_list_connectors instead' and contrasts it with well_invoke_connector_tool for provider actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use and when-not-to-use guidance: use it for data Well already syncs, never for provider actions, and never for showing connection status. It also prescribes a concrete workflow: call well_get_schema(root) first, then add only needed fields via `fields`, with examples for both display and targeted-answer use cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_remove_contact_channelRemove contact channelA
Destructive
Inspect

Remove a contact channel from a company or person.

Wraps the resource-scoped DELETE endpoints (DELETE /v1/{companies,people}/:id/{emails,phones,web-links,locations}/:channelId).

Pass channel_id = the UUID of the specific channel row to remove (NOT the parent). Find it by reading the parent with well_query_records and selecting the channel's id field.

ParametersJSON Schema
NameRequiredDescriptionDefault
parentYesParent record type: company or person
channelYesChannel to remove: email | phone | web_link | location
parent_idYesUUID of the parent company or person
channel_idYesUUID of the specific channel row to remove
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
parentNo
channelNo
successYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation destructiveHint=true already signals that this operation deletes data. The description adds valuable context by specifying that the action is scoped to a single channel row and explicitly warns 'NOT the parent', preventing accidental deletion of a company or person. It also identifies the underlying HTTP method as DELETE. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-structured: purpose, endpoint mapping, and critical parameter guidance are each covered in short, purposeful sentences. There is no filler, and the most operationally important warning about channel_id is given prominent placement.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the destructiveHint annotation, full schema coverage, and presence of an output schema, the description provides enough context for correct invocation. It explains the deletion target, the endpoint, how to obtain the required channel_id, and the parent types. Optional parameters such as workspace_id and idempotency_key are fully documented in the schema, so the description does not need to repeat them.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful guidance beyond the schema by clarifying that channel_id belongs to the specific channel row, not the parent record, and by recommending a lookup path through well_query_records. This helps the agent avoid a common misuse of the parameter even though the schema already describes it as the channel row UUID.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a clear, specific statement: 'Remove a contact channel from a company or person.' It names the exact endpoint pattern and enumerates the channel types, making it obvious this is a targeted delete operation on a channel row, not on the parent company or person. This distinguishes it well from siblings like well_add_contact_channel and well_delete_company.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear procedural guidance: pass the channel_id, not the parent, and find the correct channel_id by reading the parent with well_query_records. This tells an agent how to obtain the required identifier before invoking the tool. It does not explicitly state when to prefer this tool over alternatives, but the resource-scoped endpoint and channel-specific language make the intended use unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_resolve_reconciliation_taskResolve reconciliation taskAInspect

Approve or reject one or more reconciliation review tasks (from well_run_register_diff or the in-app review queue).

  • approve: confirms the match — the link is flipped to active.

  • reject: dismisses the match — the candidate does not silently re-surface.

Each task_id resolves independently; a failure on one (already resolved, not found) is returned in errors and does not block the rest of the batch.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionYes
task_idsYesThe review tasks' task_id values.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
errorsNo
successYes
resolvedNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, the description details the consequences of each action: approve flips the link to active, reject dismisses the match without silent re-surfacing. It also discloses independent resolution and partial-failure behavior, which is valuable for an agent invoking a write operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, front-loaded with the core operation, and uses a bulleted list for action semantics. Every sentence adds information; there is no filler or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the annotations, input schema, and output schema, the description covers the operation's source, per-action effects, failure semantics, and batch behavior. An agent has enough context to select and invoke the tool correctly without needing to infer hidden behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%, and the schema already documents task_ids, workspace_id, and idempotency_key well. The description adds meaning to the action parameter by defining approve and reject outcomes, and it clarifies that each task_id resolves independently. This is useful context beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific action (Approve or reject) on a specific resource (reconciliation review tasks) and ties the source to well_run_register_diff or the in-app review queue. This clearly distinguishes it from sibling tools like well_run_register_diff and well_resolve_register_diff_gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when the tool applies: tasks from well_run_register_diff or the review queue, with approve/reject semantics. It does not explicitly contrast this with the sibling well_resolve_register_diff_gap, so there is no explicit when-not-to-use statement, but the source and operation are clearly implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_resolve_register_diff_gapResolve register diff gapAInspect

Post a well_run_register_diff gap (one of missing_in_register_ids' review tasks) into QuickBooks as a Purchase or Deposit.

Requires the exact ledger_account_id (a UUID, not a name) for both:

  • bank_ledger_account_id: the bank/cash account the money moved through (e.g. Checking).

  • category_ledger_account_id: the expense or income category the gap books against.

Look these up first with well_query_records({ root: "ledger_accounts", filters: [...] }) scoped to the register connector — never guess an id or match an account by substring/fuzzy name.

Fails with an error (not a silent no-op) if gap posting is disabled for this workspace, if either account doesn't belong to this gap's register connector, or if either account no longer resolves in QuickBooks.

ParametersJSON Schema
NameRequiredDescriptionDefault
task_idYesThe gap review task's task_id.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
bank_ledger_account_idYesledger_account_id of the bank/cash account.
category_ledger_account_idYesledger_account_id of the category account.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
task_idNo
external_idNo
already_postedNo

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only provide readOnlyHint=false and destructiveHint=false, so the description carries the burden of explaining behavior. It does so well by stating that the operation fails with an error rather than silently no-op'ing when gap posting is disabled, accounts don't belong to the connector, or accounts no longer resolve in QuickBooks. It stops short of describing post-success state changes, but the failure semantics are a meaningful addition.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized: purpose first, then requirements, then lookup instructions, then failure conditions. Every sentence earns its place, and the structure front-loads the most decision-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write operation that depends on external QuickBooks resolution and workspace/account scoping, the description covers prerequisites, lookup procedure, validation constraints, and failure modes. The presence of an output schema means return values are documented elsewhere, so nothing essential is missing for an agent to invoke this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description adds value by explaining that bank_ledger_account_id and category_ledger_account_id must be UUIDs (not names), must be exact, and must belong to the gap's register connector. This goes beyond the terse schema descriptions and materially reduces misuse risk.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Post a well_run_register_diff gap ... into QuickBooks as a Purchase or Deposit.' This clearly identifies the action, the target system, and the record type. It also distinguishes itself from likely siblings like well_run_register_diff by framing this as the follow-up resolution step for a gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage prerequisites: both ledger account IDs must be exact UUIDs and must be looked up first via well_query_records scoped to the register connector, with a warning never to guess or fuzzy-match. It could add an explicit 'use this when...' contrast with well_resolve_reconciliation_task, but the lookup-first guidance and failure preconditions provide strong practical direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_run_register_diffRun register diffAInspect

Diff a workspace's bank transactions against its accounting-register transactions (e.g. QuickBooks), and persist the result.

  • Every match — hard evidence (structured reference, IBAN, tax ID) or inference-only (memo/payee reading) — is raised as a review task with the candidate already attached (raised_for_review). Nothing links automatically; resolve with well_resolve_reconciliation_task once a human decides.

  • Bank transactions with no register counterpart come back as missing_in_register_ids, each also minted as a gap review task (gaps_proposed) — resolve one with well_resolve_register_diff_gap once a human names the two ledger accounts. gaps_already_proposed counts gaps re-surfaced from an earlier run that already have an open, unresolved proposal.

  • Bank transactions NOT confirmed absent from the register come back as contended_in_register_ids — never minted as a gap. Two cases land here: (1) a plausible match lost to a higher-confidence sibling transaction this run, so the register-side movement is already accounted for by the winner; (2) the matcher couldn't produce a trustworthy answer (an invalid model response or a provider failure), so absence was never confirmed. Re-run the diff later; a genuine gap or duplicate should resolve itself once the winner's review task is handled or the matcher succeeds.

  • Register entries no bank transaction explains come back as unexplained_in_register_ids.

Returns { enabled: false, ... } with all counts 0 if the workspace's register-diff feature is off.

ParametersJSON Schema
NameRequiredDescriptionDefault
since_dateNoOnly diff bank transactions on/after this date (YYYY-MM-DD).
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
bank_workspace_connector_idYesThe bank connector's workspace_connector_id (e.g. Plaid).
register_workspace_connector_idYesThe accounting connector's workspace_connector_id (e.g. QuickBooks).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
enabledNo
matchedNo
successYes
gaps_proposedNo
already_linkedNo
raised_for_reviewNo
missing_in_registerNo
contended_in_registerNo
gaps_already_proposedNo
missing_in_register_idsNo
unexplained_in_registerNo
contended_in_register_idsNo
unexplained_in_register_idsNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description extensively discloses side effects beyond the annotations: matches become review tasks with candidates attached, gaps are minted as proposals, contended transactions are never minted, and results are persisted. It even explains the two underlying causes of contended results, including provider failures and invalid model responses.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized with a summary sentence followed by four focused bullet points, each covering a distinct output category. Although long, every sentence contributes operational detail, and the feature-disabled note is appropriately placed at the end. Nothing feels redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers every outcome class: raised_for_review, missing_in_register_ids, gaps_proposed, gaps_already_proposed, contended_in_register_ids, and unexplained_in_register_ids, plus the disabled-return behavior. Since an output schema exists and parameter schemas are complete, no essential context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all five parameters. The description adds no additional parameter meaning beyond mentioning QuickBooks as an example register, which the schema already includes. The baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states the specific verb 'Diff' with a clear resource: bank transactions against accounting-register transactions, and notes that the result is persisted. This distinguishes it from sibling follow-up tools like well_resolve_reconciliation_task, which the description explicitly names as later steps.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides practical workflow guidance: no automatic linking, resolution via well_resolve_reconciliation_task and well_resolve_register_diff_gap, and advice to re-run later for contended_in_register_ids. It also flags the feature-off disabled return. There is no sibling diff tool, so explicit alternative selection is unnecessary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_set_own_companySet own companyA
Destructive
Inspect

Set which company the workspace itself IS — the confirmed own-company anchor.

REQUIRED: company_id — a company that ALREADY EXISTS in this workspace. Obtain it with well_query_records (companies) or well_create_company; this tool never creates one.

This is a deliberate, accounting-critical write, not a convenience. Anchoring the own company overwrites the workspace's legal identity on its accounting settings (including clearing fields when the anchor moves), records a manual-confirm audit row, and syncs the billing customer name. It never re-posts existing journal entries. Confirm the exact company with the user before calling; never guess one from a name.

Only a workspace owner or admin may set the own company. A caller without that role is refused, not silently ignored.

well_start_close hard-gates on this anchor: a workspace with no own company cannot start a close.

ParametersJSON Schema
NameRequiredDescriptionDefault
company_idYesThe UUID of a company already in this workspace to anchor as its own company.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
own_company_idNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, the description discloses that this is an accounting-critical write that overwrites the workspace's legal identity, clears fields when the anchor moves, records a manual-confirm audit row, and syncs the billing customer name. It also states what it does not do—re-post journal entries—and that unauthorized callers are refused, not silently ignored. These details align with destructiveHint=true and add significant safety context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with bolded section labels and front-loads the core purpose before diving into details. Each sentence adds a distinct, non-redundant fact: prerequisite, side effects, boundary of behavior, authorization, and dependency. The length is justified by the sensitivity and complexity of the write operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers prerequisites, authorization, side effects, what the operation does not do, and a hard-gate dependency on well_start_close. With an output schema present and annotations aligning with the described behavior, nothing essential is missing for an agent to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents all three parameters at 100% coverage, but the description adds crucial semantics for company_id: it must already exist in the workspace, can be obtained via well_query_records or well_create_company, and this tool never creates one. It does not add extra meaning for workspace_id or idempotency_key, but the schema descriptions for those are sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise operation—setting which existing company is the workspace's own-company anchor—and distinguishes itself from creation tools by explicitly saying 'this tool never creates one.' It also names related tools like well_query_records and well_create_company for obtaining the company_id, making its role clear relative to siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance: company_id must reference an already-existing workspace company, how to obtain it, and the instruction to confirm the exact company with the user before calling. It also specifies the workspace owner/admin role restriction and notes that well_start_close hard-gates on this anchor, so an agent knows the prerequisite and consequence context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_switch_workspaceSwitch workspaceAInspect

Write this connection's session context — the one place a conversation's standing choices live. This is the tool the widget cards call when the user CLICKS them: the workspace pin and queue, the selected months, the selected counterparties, and the step acknowledgements are all recorded here, and every later tool call defaults to them.

Pass any of:

  • workspace_ids (ordered list): the workspaces to work in. The FIRST entry becomes the pin and the rest the workspace_queue to work through next. Every id must be one this connection is already authorized for — call well_list_workspaces to see them. This grants no new access; it only chooses among the authorized workspaces.

  • periods: the months the user VALIDATED on the period card ({ calendar_year, calendar_month } each). Period-scoped reads (well_list_missing_invoices, well_preview_invoice_fetch) default to them when called without a period. Send it only for the user's month selection — never to bound a counterparty pick, which would overwrite that selection.

  • counterparties: the counterparties (vendors) the user selected, each { company_id, matched_connector_service_id }. Copy both ids off the row you listed them from; pass no display name. The selection belongs to the workspace this call is dispatched to, and a switch to another workspace clears it. One session holds one selection, so a new one replaces it; a selection sent for a workspace this connection has switched away from is REFUSED instead, so a card the flow moved past cannot overwrite the pinned workspace's selection.

  • counterparty_periods: the months the counterparties card listed, sent alongside counterparties. The pick then narrows those months only, and a month it never covered is read in full. With none named, the months this session already holds bound the pick. This never becomes the session's selected months.

  • ack: "connectors" or "bank" — records that the user confirmed that flow step, in the workspace this call is dispatched to. A switch to another workspace clears it, so the next workspace's card asks for its own click. An acknowledgement sent for a workspace this connection has switched away from is REFUSED instead, so a card the flow moved past cannot un-confirm the step the pinned workspace's own card recorded.

Call it with NO argument at all to pin the workspace this call itself is dispatched to — its universal workspace_id, or the only workspace the token covers. workspace_ids is the PIN write and nothing else: it moves the pin AND replaces the workspace_queue, so a one-entry list ends a run that still had workspaces queued. Send it only to change the workspace. A call carrying periods, counterparties or ack needs no workspace_ids: its universal workspace_id targets that one call, and the pin and the queue stay where they are. Never re-pin the workspace this connection already holds.

Every provided input is applied, and changed names the session fields this call wrote. After a switch, every later call that omits workspace_id targets the pinned workspace, for reads and writes alike; passing workspace_id on a later call overrides it for that call only. well_list_workspaces reports the current session context, and well_wait_for_selection reads a card click back — instantly when it already landed here, after a short wait otherwise.

This changes nothing in the user's data.

ParametersJSON Schema
NameRequiredDescriptionDefault
ackNoAcknowledge a flow step: "connectors" for the connect-tools step, "bank" for the bank step. The acknowledgement is scoped to the workspace this call is dispatched to, and a switch to another workspace clears it. An acknowledgement sent for a workspace this connection has switched away from is refused, and the pinned workspace's own acknowledgement of that step stands.
periodsNoThe months the user VALIDATED on the period card, stored as this session's selected_periods. Later period-scoped reads default to them when called without a period. This field is the user's month selection alone — to bound a counterparty pick, send counterparty_periods instead.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
workspace_idsNoOrdered workspace selection, and the ONLY field that moves the pin: the FIRST entry becomes this connection's pin, and the rest REPLACE the workspace_queue — so a one-entry list empties a queue that still holds workspaces. Every entry must be authorized for this connection, or the whole call is refused. Never send it to name the workspace of a periods, counterparties or ack call: the universal workspace_id already targets those, while a re-pin to the id this connection already holds writes nothing and clears the queue.
counterpartiesNoThe counterparties the user selected, stored as this session's selected_counterparties and scoped to the workspace this call is dispatched to. At most 200 — a longer list is refused, so a select-all keeps to that bound. Copy the ids off the row: company_id, plus matched_connector_service_id when the row carries one. Send the card's months as counterparty_periods in the same call, so the pick applies to those months only; with none named, the months this session already holds bound it. The session holds ONE selection, so this REPLACES the previous one — but only when the call names the pinned workspace: a selection sent for a workspace this connection has switched away from is refused, and the pinned workspace's selection stands.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
counterparty_periodsNoThe months the counterparties card listed, which bound the pick sent as counterparties in the same call. Send it only with counterparties; it never becomes this session's selected months, so it cannot overwrite what the user validated on the period card. With none named, the months this session already holds bound the pick.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
changedNoWhich session fields this call wrote.
successYes
acknowledgedNo
workspace_idNo
workspace_nameNo
workspace_queueNoThe workspaces queued after the pinned one, in order.
selected_periodsNo
selected_counterpartiesNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly=false, destructive=false), it clarifies that the write touches session context only ('This changes nothing in the user's data'), explains pin/queue replacement, stale-workspace refusals, and acknowledgement clearing on switch. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long and occasionally repeats the scoping phrase 'the workspace this call is dispatched to,' but it is front-loaded, organized by parameter, and each section covers a distinct behavioral edge case. The complexity of the tool justifies most of the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stateful 7-parameter tool, the description covers the no-argument call, universal workspace targeting, auth constraints, the changed return field, and links to reporting/reading siblings. With full schema and an output schema present, nothing needed to invoke correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds substantial cross-parameter meaning: the first workspace_ids entry becomes the pin while the rest replace the queue, counterparty_periods never becomes the session's selected months, and ack/counterparties are scoped to the dispatched workspace. This goes well beyond the schema field descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Write this connection's session context' and enumerates exactly what gets recorded: workspace pin/queue, months, counterparties, and step acknowledgements. This is a specific verb+resource and clearly distinguishes the tool from sibling read/list tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states when the tool fires ('the tool the widget cards call when the user CLICKS them'), when to omit args entirely, and gives explicit exclusions: 'Send it only to change the workspace,' 'Never re-pin the workspace this connection already holds,' and 'never to bound a counterparty pick.' It also names well_list_workspaces as the way to see authorized workspaces.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_update_companyUpdate companyA
Destructive
Inspect

Update an existing company in the current workspace.

Use this tool when the user asks to change, fix, rename, or edit a company's fields.

REQUIRED: company_id OPTIONAL (only include fields the user wants changed): name, description, domain, registered_name, trade_name, tax_id_value, tax_id_type, registry_country (ISO 3166-1 alpha-2, e.g. "FR"), business_type, registered_value, registry_name, locale (ISO 639-1 two-letter language code, e.g. "en", "fr" — not "en_US").

CATEGORIES (a counterparty's industry): pass category_ids — the COMPLETE set of category ids the company should carry. It REPLACES the current set: ids you leave out are unlinked, and [] clears every category. Omit the field to leave the categories untouched. Read the catalog first with well_query_records({ root: "categories", whereClause: { category_type: { _eq: "company" } } }) and pass ids from it — an id that is not a category_type = "company" row is refused, and this tool never creates a category.

NOT CHANGEABLE via this tool: emails, phones, locations, linked people, media. Those require dedicated tools (not yet available).

Returns { success: true, company_id, name } on success — plus category_count, the number of categories the company carries afterwards, when the call passed category_ids. Returns { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoCompany name
domainNoPrimary website domain (e.g. acme.com)
localeNoPreferred language as an ISO 639-1 two-letter code (e.g. en, fr, de). Pass null to clear.
company_idYesThe UUID of the company to update (required)
trade_nameNoTrading name / DBA
descriptionNoBrief company description; pass null to clear
tax_id_typeNoTax identifier type (VAT, SIRET, EIN, ...)
category_idsNoThe COMPLETE set of company-category ids this company should carry. Replaces the current set; [] clears it; omit to leave categories unchanged.
tax_id_valueNoTax identifier value (VAT, SIRET, EIN, ...)
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
business_typeNoBusiness type / legal form
registry_nameNoRegistry name
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
registered_nameNoOfficial registered legal name
registered_valueNoRegistry identifier value
registry_countryNoISO 3166-1 alpha-2 country code of the registry (e.g. FR, US)

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameNo
errorNo
successYes
company_idNo
category_countNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark destructiveHint=true, and the description adds concrete destructive semantics: category_ids REPLACES the current set, omitted ids are unlinked, '[]' clears, and invalid category ids are refused. It also discloses return values (including category_count), states the tool never creates categories, and lists non-editable fields — far beyond annotation basics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but organized into clear sections (REQUIRED, OPTIONAL, CATEGORIES, NOT CHANGEABLE, Returns) and front-loads the purpose. Some parameter details repeat schema descriptions, but the destructive complexity and category replacement rules justify the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a fully described input schema, an output schema, and the annotations, the description still adds prerequisites (category catalog read), category replacement semantics, non-changeable fields, and return variants. Nothing an agent needs to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3. The description adds update-specific meaning ('only include fields the user wants changed'), clarifies the locale format ('not "en_US"'), and emphasizes the category replacement behavior — useful guidance beyond the schema. It does not duplicate every schema detail, which is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('Update an existing company in the current workspace') and the intended user requests ('change, fix, rename, or edit a company's fields'). The 'existing' qualifier and the NOT CHANGEABLE list clearly separate it from create/delete and other update tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use ('when the user asks to change, fix, rename, or edit a company's fields') and when not to use it for emails, phones, locations, linked people, and media, which 'require dedicated tools (not yet available)'. It also gives a prerequisite for category_ids. It does not name the sibling create/delete tools explicitly, but the scope language is enough for routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_update_invoiceUpdate invoiceA
Destructive
Inspect

Update an existing invoice in Well.

Call well_get_schema("invoices") to discover all available fields.

REQUIRED: invoice_id OPTIONAL (only pass fields you want changed):

  • reference_number, issue_date (ISO date), due_date (ISO date)

  • status (draft | issued | paid | canceled)

  • terms, description

  • grand_total, items_total, tax_total (numbers)

  • local_currency (ISO 4217 three-letter code, e.g. "EUR", "USD")

  • document_type_code (UN/CEFACT 1001 code, e.g. "380")

  • billing_context (e.g. subscription, one_time, project, ...)

  • issuer_company_id / receiver_company_id (uuid to set, null to clear, omit to leave unchanged)

Cannot change line items, payment_means, or document attachment via this tool.

ParametersJSON Schema
NameRequiredDescriptionDefault
termsNoPayment terms text; pass null to clear
statusNoInvoice lifecycle status
due_dateNoPayment due date (ISO 8601); pass null to clear
tax_totalNoTotal tax amount; pass null to clear
invoice_idYesThe UUID of the invoice to update
issue_dateNoIssue date (ISO 8601, e.g. 2026-04-27); pass null to clear
descriptionNoFree-form description; pass null to clear
grand_totalNoTotal invoice amount including tax; pass null to clear
items_totalNoSum of line items before tax; pass null to clear
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
local_currencyNoISO 4217 three-letter currency code (e.g. EUR, USD); pass null to clear
payment_statusNoUser-driven payment_status override — requires override_version (CAS)
billing_contextNoBilling context / business model; pass null to clear
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
override_versionNoRequired when payment_status is present — current override_version for CAS
reference_numberNoInvoice reference number (e.g. INV-2026-001); pass null to clear
issuer_company_idNoIssuer company UUID. Omit = no change, null = clear, uuid = set.
document_type_codeNoUN/CEFACT 1001 document type code (e.g. 380 for commercial invoice); pass null to clear
receiver_company_idNoReceiver company UUID. Omit = no change, null = clear, uuid = set.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
invoice_idNo
reference_numberNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as destructive and not read-only. The description adds meaningful behavior beyond that: partial-update semantics ('only pass fields you want changed'), the need to consult the schema for available fields, and the hard limitation on line items/payment_means/attachments. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a one-sentence purpose, then uses compact bullets, required/optional grouping, and a decisive limitation statement. It is long because there are many fields, but the structure makes it scannable and every section earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of 19 parameters, the schema carries full descriptions and an output schema exists, so the description focuses on workflow and constraints. It covers discovery via well_get_schema and key invariants. It doesn't summarize edge-case params like workspace_id or idempotency_key, but those are fully documented in the schema and the agent is directed to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All 19 parameters have schema descriptions, so the baseline is 3. The description adds selection semantics not fully encoded in the schema: REQUIRED vs OPTIONAL, 'only pass fields you want changed,' and explicit set/clear/omit rules for company IDs. This genuinely helps an agent construct a correct partialupdate call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific action and resource: 'Update an existing invoice in Well.' This clearly distinguishes it from create/delete invoice siblings, and the closing restriction on line items, payment_means, and attachments further sharpens the scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides concrete usage guidance: call well_get_schema to discover fields, only pass fields you want changed, and explicitly lists what cannot be changed. It does not name an alternative tool for those excluded changes, but the exclusion is clear enough for routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_update_personUpdate personA
Destructive
Inspect

Update an existing person (contact) in the current workspace.

Use this tool when the user asks to change, fix, rename, or edit a person's fields.

REQUIRED: person_id OPTIONAL (only include fields the user wants changed): first_name, last_name, job_title.

NOT CHANGEABLE via this tool: emails, phones, locations, linked companies, media. Those require dedicated tools (not yet available).

Returns { success: true, person_id, full_name } on success, or { success: false, error } on failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_titleNoJob title; pass null to clear
last_nameNoLast name
person_idYesThe UUID of the person to update (required)
first_nameNoFirst name
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
full_nameNo
person_idNo

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as destructiveHint=true and readOnlyHint=false, so the mutation semantics are covered. The description adds useful behavior beyond that: it explicitly lists non-changeable fields, documents the success and failure return shape, and clarifies that only requested fields should be included. This is strong supplementary context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections for required, optional, non-changeable, and return values. Every sentence adds practical guidance, and the most important instruction ('Update an existing person') is front-loaded. It is detailed without being bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple update tool, the description covers required parameters, optional usage guidance, unsupported fields, and return behavior. The schema provides rich detail for workspace_id and idempotency_key, so their absence from the description does not leave a meaningful gap. The tool is fully callable based on the provided metadata.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds value by clarifying that first_name, last_name, and job_title should only be included when the user wants them changed, and by emphasizing that person_id is required. It does not repeat the detailed workspace_id/idempotency_key semantics, but those are already well documented in the schema, so this is not a significant gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with 'Update an existing person (contact) in the current workspace', which uses a specific verb and resource, and the word 'existing' distinguishes it from creation tools like well_create_person. The added 'change, fix, rename, or edit' phrasing reinforces the intended use case and separates it from deletion and creation siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states 'Use this tool when the user asks to change, fix, rename, or edit a person's fields', giving clear selection criteria. It also lists what cannot be changed and notes that dedicated tools are 'not yet available', preventing the agent from attempting this tool for unsupported field updates.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_upload_statement_bytesUpload statement bytesAInspect

Upload a bank statement file's BINARY CONTENT (PDF or image) as base64, so the file's real bytes reach Well without any out-of-band HTTP call.

Use it for PDF and image statements up to 5 MiB decoded (the base64 text may be roughly a third larger). Base64-encode the file's bytes EXACTLY — never re-encode a screenshot, a transcription, or a summary of the file. Optionally send the file's sha256 (hex); the server decodes, hashes, and rejects a mismatch, proving the bytes arrived intact.

The response carries content_sha256 and byte_length of the decoded payload — report them for verification. The parsed rows, totals, and import outcome arrive via well_get_statement_import_result with the returned document_id.

Text statements (.csv/.txt/.xml) whose contents are verbatim in this conversation can go through well_upload_statement_content instead. The document enters the same import pipeline as an in-app upload (detection, dedup, promotion).

ParametersJSON Schema
NameRequiredDescriptionDefault
sha256NoThe source file's SHA-256 (hex). When sent, a mismatch with the decoded bytes rejects the upload.
filenameYesThe statement's file name, e.g. "statement.csv". Only its extension selects the format.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
content_base64YesThe file's bytes, base64-encoded (RFC 4648; whitespace tolerated). Decoded cap: 5 MiB.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
byte_lengthNo
document_idNoPoll well_get_statement_import_result with this id for the import outcome.
deduplicatedNoTrue when an identical document was already in the workspace — nothing was imported twice.
content_sha256NoSHA-256 (hex) of the payload the server received — compare against your source to verify fidelity.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (which only indicate a write and non-destructive operation), the description discloses meaningful behavior: server-side decode and hash verification, rejection on sha256 mismatch, response fields content_sha256 and byte_length, and routing of import results through well_get_statement_import_result. It also warns against re-encoding screenshots or transcriptions, which is valuable operational context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although longer than typical descriptions, every sentence earns its place: scope, size limit, encoding requirement, integrity verification, response handling, import-result routing, and alternative tool. The critical binary-vs-text distinction is front-loaded, and the structure is logical.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the presence of a full output schema, the description is complete. It covers the exact payload semantics, size constraints, verification behavior, post-upload flow, and relationship to the sibling text-upload tool. Nothing call-critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds real value beyond the schema by stressing exact base64 encoding, warning against re-encoding non-file content, noting that filename extension selects format, and explaining the sha256 integrity check. This pushes it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: uploading a bank statement file's BINARY CONTENT as base64. It clearly distinguishes this binary/PDF/image path from the text-based sibling well_upload_statement_content, so an agent can tell the two apart without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to use this tool for PDF and image statements up to 5 MiB, and that text statements whose contents are verbatim should go through well_upload_statement_content instead. This gives the agent both the positive condition and the named alternative, with no inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_upload_statement_contentUpload statement contentAInspect

Upload a bank statement's TEXT CONTENT (a .csv, .txt, or .xml file) directly, as an alternative to well_create_statement_upload's out-of-band file POST.

Use it when the user's statement is a small text file whose contents are verbatim in this conversation (1 MiB decoded limit). Send the content EXACTLY as you received it — never reformat, summarize, transcribe from memory, or reconstruct rows. A mangled relay imports wrong financial data.

This path is BEST-EFFORT fidelity: what Well ingests is what you relayed, not a byte-verified copy of the user's file. The response carries content_sha256 and byte_length of what the server received — report them so a corrupted relay is visible. The parsed rows, totals, and import outcome arrive via well_get_statement_import_result with the returned document_id, not in this response.

PDFs and images NEVER go here (the model cannot relay their bytes faithfully) — use well_upload_statement_bytes. XML with DOCTYPE/ENTITY declarations is rejected. The document enters the same import pipeline as an in-app upload (detection, dedup, promotion).

ParametersJSON Schema
NameRequiredDescriptionDefault
filenameYesThe statement's file name, e.g. "statement.csv". Only its extension selects the format.
content_textYesThe file's full text content, verbatim. UTF-8 encoded on the wire; capped at 1 MiB decoded.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
successYes
byte_lengthNo
document_idNoPoll well_get_statement_import_result with this id for the import outcome.
deduplicatedNoTrue when an identical document was already in the workspace — nothing was imported twice.
content_sha256NoSHA-256 (hex) of the payload the server received — compare against your source to verify fidelity.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say the tool is a non-read-only, non-destructive write, so the description carries the burden and does it thoroughly. It discloses best-effort fidelity, that content_sha256 and byte_length reflect what the server received, that rows/outcomes arrive separately via well_get_statement_import_result, and that the document enters the same import pipeline as an in-app upload.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: purpose, fidelity warning, reporting requirement, follow-up result retrieval, exclusions, and security constraint. It is front-loaded with the core action and alternatives, and the length is justified by the tool's nuance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers use case, constraints, fidelity behavior, server-verification reporting, follow-up result retrieval, and format exclusions. With an output schema present, the lack of return-value detail is fine; nothing an agent needs to invoke this safely and correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains filename, content_text, workspace_id, and idempotency_key. The description reinforces the verbatim requirement and 1 MiB limit, but it adds little parameter-level meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: uploading a bank statement's TEXT CONTENT directly from the conversation, as an alternative to out-of-band POST. It clearly distinguishes from well_create_statement_upload and well_upload_statement_bytes, so there is no ambiguity about which sibling tool is intended.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states when to use this tool: small text files (.csv, .txt, .xml) whose contents are verbatim in conversation and under 1 MiB. It also gives exclusions and alternatives: PDFs/images must go to well_upload_statement_bytes, and XML with DOCTYPE/ENTITY declarations is rejected.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_upsert_accounting_settingsSet accounting settingsA
Destructive
Inspect

Set the workspace's accounting configuration: fiscal year start month, first fiscal year start date, country, base currency, accounting framework, and chart-of-accounts confirmation.

Provide only the fields you are changing; omitted fields are left untouched. An empty call (no fields) is refused.

Only a workspace owner or admin may set the accounting configuration. A caller without that role is refused, not silently ignored.

Changing the fiscal year start month moves the whole fiscal calendar, so it is REFUSED when a period is locked or a close is in progress — the tool surfaces that refusal rather than forcing it. When the change is allowed, it soft-deletes the workspace's regenerable DRAFT journal entries so they re-mint on the new coordinates; VALIDATED and LOCKED entries are never touched.

These are accounting-critical values. Confirm each one with the user before calling and never guess them — do not infer a country, currency, framework, or start month the user did not state.

This tool does NOT set the workspace's legal identity (registered name, trade name, tax id, domain): that is owned by well_set_own_company. Use that tool for identity, this one for accounting configuration.

ParametersJSON Schema
NameRequiredDescriptionDefault
countryNoISO 3166-1 alpha-2 country code.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several — a write lands in exactly one workspace and this call would not say which.
base_currencyNoISO 4217 currency code.
coa_confirmedNoWhether the chart of accounts has been confirmed.
idempotency_keyNoOptional client-supplied key. A retried write with the same key returns the original result instead of re-applying the operation.
accounting_frameworkNoThe accounting framework the books follow.
fiscal_year_start_monthNoCalendar month (1-12) the fiscal year starts on, or null to clear it.
first_fiscal_year_start_dateNoFirst fiscal year start date as YYYY-MM-DD, or null to clear it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
countryNo
successYes
base_currencyNo
coa_confirmedNo
accounting_frameworkNo
fiscal_year_start_monthNo
first_fiscal_year_start_dateNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this destructive, but the description substantially enriches that signal: it discloses that DRAFT journal entries are soft-deleted and re-minted, VALIDATED/LOCKED entries are never touched, and unauthorized callers are refused rather than silently ignored. This is exactly the kind of behavioral context agents need beyond structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then each subsequent sentence covers a distinct operational concern: partial updates, authorization, destructive side effects, confirmation requirements, and scope boundary. There is no filler or redundant restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the presence of an output schema, the description covers all critical context: authorization, refusal conditions, partial-update behavior, destructive side effects, user confirmation expectations, and the intended boundary with a sibling tool. Nothing an agent needs to safely decide whether and how to call this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents each parameter. The description adds valuable cross-parameter semantics: only provided fields are changed, omitted fields are untouched, empty calls are refused, and the workspace must be unambiguous when the token authorizes multiple workspaces. This goes beyond the schema descriptions and helps avoid misuse.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: "Set the workspace's accounting configuration" and enumerates the exact fields involved. It also explicitly differentiates this tool from well_set_own_company by stating that identity fields are NOT handled here, which is strong sibling disambiguation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: use this for accounting configuration and well_set_own_company for identity. It also states preconditions and refusals: owner/admin required, empty calls refused, fiscal-year changes refused when periods are locked, and omitted fields remain untouched. This is much more than an implied usage hint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

well_wait_for_selectionWait for selectionA
Read-only
Inspect

Read the user's card click — returns instantly if they already clicked; otherwise waits briefly. Call it after the tool whose card asks the user to click: well_list_workspaces (kind "workspace"), well_list_periods (kind "periods"), well_list_missing_invoices (kind "counterparties" — its card is the only one that records a counterparty pick), or well_list_connectors (kind "connect_ack" for the connect step, "bank_ack" for the bank step).

  • status "selected": the choice is recorded. selection carries it — the pinned workspace_id and workspace_queue, the picked periods, the picked counterparties (each { company_id, matched_connector_service_id } plus the workspace_id they belong to and the periods they were listed for), or the acknowledgement plus the workspace_id it was made in. already_set: true means it was recorded before this call (the user had already clicked). Continue the flow with it.

  • status "no_selection_yet": nothing is recorded and no click landed within the wait (default 10s, clamped 5-90s). This is a NORMAL result, not an error — end your turn by asking the user to click the card; the click prefills the reply that resumes the flow.

A counterparty pick belongs to the workspace AND the months it was made against, and it carries those months in selection.periods. A switch to another workspace, a change of the selected months, or a fresh well_list_missing_invoices card drops it. So kind "counterparties" never hands back a pick made against another month — with that pick dropped, the call waits for the new click instead. A pick recorded BEFORE this call is reported only when it was made in the workspace this call targets, so pass workspace_id to ask about a workspace the connection is not switched to. A pick that lands DURING the wait rides back with the workspace it was made in — compare selection.workspace_id before you act on it.

An acknowledgement belongs to the workspace it was made in, and rides back as selection.workspace_id. A switch to another workspace drops it. An ack recorded BEFORE this call is reported only when it was made in the workspace this call targets, so pass workspace_id to ask about a workspace the connection is not switched to. A click that lands DURING the wait is reported with its own workspace, which can be another card's — compare selection.workspace_id before you act on it.

This tool reads and waits — it changes nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindYesWhich card click to wait for: "workspace" (the workspace picker's Use), "periods" (the month picker's Validate), "counterparties" (the missing-invoices card's Continue), "connect_ack" / "bank_ack" (the connect card's Continue).
timeout_sNoHow long to wait, in seconds. Default 10, clamped to 5-90.
workspace_idNoTarget workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNo
kindNo
errorNo
statusNo
successYes
selectionNoThe value the click wrote. Present only when status is "selected".
already_setNoTrue when the selection was already recorded before this call started — no wait happened.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description explicitly states 'This tool reads and waits — it changes nothing.' It discloses nuanced behaviors such as picks being dropped on workspace/month changes, 'already_set: true' semantics, and that a 'no_selection_yet' status is a normal result rather than an error. This gives the agent a clear behavioral model beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and pairing rules, then presents detailed semantic nuances in clearly separated paragraphs. It is long and contains some parallel repetition (e.g., the workspace-dropping behavior for both counterparties and acks), but the structure makes each segment trackable and relevant, so it remains more organized than bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the existence of an output schema, the description covers everything needed to invoke it correctly: when to call it, which kind pairs with which tool, how to interpret statuses, workspace scoping caveats, timeout behavior, and that no_selection_yet is a normal outcome requiring user follow-up. No critical operational gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already covers all parameters with descriptions (100% coverage), so the baseline is 3. The description adds significant flow-level meaning, e.g., what each kind means in context, how workspace_id scopes the reported data, and how timeout_s default/clamp works. This goes beyond the schema but is somewhat redundant with schema text in places.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific action, 'Read the user's card click', and clarifies the behavior in both states: 'returns instantly if they already clicked; otherwise waits briefly.' It also distinguishes the tool from sibling list tools by naming exactly which list tool produces which card click (well_list_workspaces, well_list_periods, well_list_missing_invoices, well_list_connectors), so an agent can tell it apart from those siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs when to use the tool: 'Call it after the tool whose card asks the user to click', then maps each kind to a specific sibling tool. It also provides guidance for the 'no_selection_yet' outcome: 'end your turn by asking the user to click the card', and for workspace-sensitive cases tells the agent to pass workspace_id and compare selection.workspace_id.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Frequently Asked Questions

Discussions

No comments yet. Be the first to start the discussion!

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables Wave invoicing operations including listing invoices, retrieving details, and generating branded PDFs directly from AI assistants.
    19
    ISC
  • A
    license
    C
    quality
    A
    maintenance
    Enables AI assistants to manage invoices, contacts, purchases, journal entries, and other accounting operations via the Fiken API.
    100
    24
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects AI assistants to QuickBooks Online, enabling management of invoices, customers, expenses, and reports through natural language.
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Connect Claude, Cursor, or any MCP-compatible AI client to your Wasabil account. Issue Chilean electronic invoices (DTE/SII), reconcile bank payments, and manage clients — all through natural language.
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

TDQS

A4.5/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: CRUD for companies, people, and invoices; financial analytics (cash, cost, runway, holdings); connector management and invocation; schema discovery; querying; reconciliation; and contact channel management. No two tools could be confused for the same action.

Naming Consistency5/5

All tools follow the `well_verb_noun` pattern with consistent verb choices (create, get, list, update, delete, add, remove, run, resolve, query, invoke). The naming is predictable and makes the tool's purpose immediately clear.

Tool Count4/5

With 26 tools, the set is slightly above the ideal 3-15 range, but every tool earns its place given the breadth of the domain (CRM, invoicing, financial analytics, reconciliation, connector management). The count is well-scoped and not excessive.

Completeness4/5

The tool surface covers core CRUD, financial KPIs, reconciliation, and connector management. Minor gaps exist (e.g., no direct tool to update contact channels or manage accounts), but the query and schema tools allow agents to work around them, and the primary workflows are fully supported.

Resources