Skip to main content
Glama

List the billing contexts a reader can count as recurring

well_list_recurring_contexts
Read-only

List the billing contexts a reader can count as recurring revenue over one window, each with what counting it would add. This is what the recurring-contexts card offers; it measures nothing well_sum_invoices did not already measure, but it does judge each context by the months it billed.

Each entry in groups is one billing context's revenue in the window: context_key (the id a selection is matched on), label (the context as the product writes it), amounts (one entry per currency, each already net of credit notes and never converted) and count (the invoices behind it). The named contexts are sorted biggest first in the currency that carries the most invoices, so the biggest decision reads first. A context whose window nets to nothing in every currency is NOT listed — counting it would add nothing, so it is not a choice. A context that nets NEGATIVE stays on the list: its credit notes outweighed its invoices, which is a real state, and hiding it would move the figure by an amount nobody saw.

The last entry may be context_key: "unclassified", labelled "No billing context". It is the invoices whose billing_context is null: extraction fills the field rather than a billing system, so on most workspaces it holds most of the revenue. It is a choice like the others. A business that bills only subscriptions can count it as recurring; a business with one-off work usually cannot. When it is counted, apply it to the well_sum_invoices rows whose billing_context is null — no row carries the key itself. State its amount whenever it is listed, counted or not, because it is the part of the figure extraction could not describe.

totals is the sum of the groups' amounts per currency: the window's whole readable issued revenue. This read converts nothing and never adds one currency to another. The reader decides per context, so the choice needs no single total; convert once, in the arithmetic, at a rate you state.

measured is the read's own view on which contexts are recurring: each listed context is judged by the months it billed in the window, under the same schedule rule the subscription detector applies on the bank side — monthly, bimonthly, quarterly or yearly. measured.contexts carries every verdict (cadence, missed_rule, months_billed) so the answer can be checked, and measured.policy states the rule in one line for the answer to restate. This is a measurement of the invoices, not a fact about the reader's business — a retainer is recurring for one company and a one-off engagement for another — so the card stays open for a correction, and a pick the reader records replaces the measured set on the next call.

recurring_contexts is the set this call settled on, and reuse_stored_choice: true says the card asks nothing: the answer applies as it stands. choice_source names what settled it — "recorded_pick" when the pick this conversation recorded applies, "measured" when the cadence verdicts did. When reuse_stored_choice is false — a read cut short, or a context whose months the rows did not carry — the card asks as before and recurring_contexts is empty.

invoice_basis is the window's issued revenue under the applied set, ready for the arithmetic: totals and monthly_average per currency (the average divides by every month of the window, dark ones included), per_month the same per month, months_in_window, months_with_revenue, invoice_count, the unclassified_count and unattributed_count the sum reported, and excluded (one_off is the invoices under contexts not counted, credit_notes the ones netted into the figure, unreadable_rows the defective rows). by_client answers the value per client on the same basis — every issued invoice in the window, counted or not under the recurring rule — one line per client per currency, largest first, the rest folded into an is_other line whose client_count says how many. by_client_truncated: true means the client grouping hit its cap, so the folded line may hold more than client_count names.

Apply the answer this result already carries when reuse_stored_choice is true: keep only the well_sum_invoices rows whose billing_context is in recurring_contexts, reading "unclassified" as the rows whose billing_context is null, pass the same keys to well_render_mrr as recurring_contexts, and state measured.policy in one line when choice_source is "measured" — a recorded pick is the reader's own rule, so name the contexts it counted instead. An EMPTY recurring_contexts beside reuse_stored_choice: true is the verdict that nothing in the window recurs under the rule: say no recurring revenue was found, never render a zero, and ask nothing. When reuse_stored_choice is false the card asks: take the reader's answer from it — its Continue records the pick with well_switch_workspace as recurring_contexts, and you read it back with well_wait_for_selection (kind "recurring_contexts").

The window is whole months: from and to are both the first day of a month, YYYY-MM-01, from inclusive and to EXCLUSIVE. window echoes both back exactly as you sent them. When a comparison will be measured, read the list over BOTH windows, from the start of the earlier one to the end of this one, so a context that stopped billing between them is still offered.

partial: true means the aggregate was cut short: every amount here is a FLOOR, a context's real share can only be larger, and a choice made because a share looked small may not survive the full read. Say so before presenting the list as a basis for the decision. A cut-short read never settles the recurring set either: the verdicts stay in measured as evidence, and the card asks. unreadable_rows counts invoices whose net amount or currency could not be read at all; they are in no figure here. It is null when that count could not be read, which is not zero: say it is unmeasured.

Read party_scope: when party_scope.side_unknown is true the workspace has no resolved own company, so no side filter was applied and the list covers invoices on both sides, purchase invoices included. Say the side is unknown and never offer the list as recurring revenue; resolve the own company, then list again.

Read success before groups: a failed read returns no contexts, which looks exactly like a window with nothing to choose.

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

Input Schema

NameRequiredDescriptionDefault
toYesEXCLUSIVE end of the window: the first day of the month after the last one you want, YYYY-MM-01.
fromYesInclusive start of the window: the first day of a month, YYYY-MM-01.
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.
conversation_idNoThe conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.
workspace_scopeNoRestrict this call to the family: the token's primary workspace plus the company workspaces under it that you are a member of. Unrelated authorized workspaces drop out of the read; row reads merge across the family, while a per-workspace figure still reports exactly one workspace.

Output Schema

NameRequiredDescriptionDefault
errorNo
groupsYes
totalsYes
windowYes
partialYesTrue when the aggregate behind these figures was cut short. Every amount is then a FLOOR rather than a measurement, and the recurring set is never settled by one.
successYes
measuredYesThe read's own cadence verdicts. Null on a refused read; always present on a successful one, partial included.
next_stepNoWhat to do with the card this result renders. Added by the dispatcher when the card asks for a click.
party_scopeYesWhat the receivable side resolved to. `side_unknown: true` means the workspace resolved no own company, so NO side filter was applied (`applied: false`) and the list covers invoices on both sides — say the side is unknown, never that these are the contexts the workspace issued. `null` when the read reported no scope resolution.
choice_sourceYesWhat settled `recurring_contexts`: the pick this conversation recorded, or the cadence the read measured. Null when the card still asks.
invoice_basisYesThe window's issued revenue under the applied recurring set. Null when no set applies — the card still asks.
conversation_idNoThe conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.
newly_connectedNoTools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. The connected-line rule says when to tell an entry; when it does, one line per entry, in the person's language: "<name> is connected.". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later.
unreadable_rowsYesInvoices in the window whose net amount or currency could not be read. They are in no figure here, including the no-billing-context one. Null when the count could not be read.
recurring_contextsYesThe settled set: the keys the figure counts as recurring, applied as they stand when `reuse_stored_choice` is true. Empty when the card still asks — and also when the verdict is that nothing recurs, which `reuse_stored_choice` tells apart.
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
reuse_stored_choiceYesTrue when the card asks nothing this call: the recurring set is already settled — by the pick this conversation recorded, or by the cadence the read measured. Apply `recurring_contexts` as they stand and wait for nothing. An empty set beside `true` is the verdict that nothing in the window recurs: say so plainly, never render a zero.
conversation_id_noteNoPresent only when the server opened a fresh lane, stating that no choice recorded earlier was read.
conversation_id_sourceNoWhere the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • changedOutput schema / properties / invoice_basis / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "by_client": {
      -        "description": "The value per client on the same issued-invoice basis — every invoice in the window, counted or not under the recurring rule. One line per client per currency, largest first; the rest fold into one `is_other` line per currency.",
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "amount": {
      -              "description": "The client's issued total over the window, net of credit notes, in `currency`.",
      -              "type": "number"
      -            },
      -            "client_count": {
      -              "description": "On an `is_other` line, how many clients it sums.",
      -              "type": "number"
      -            },
      -            "count": {
      -              "description": "Issued invoices behind the total.",
      -              "type": "number"
      -            },
      -            "counterparty_id": {
      -              "anyOf": [
      -                {
      -                  "type": "string"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            "currency": {
      -              "type": "string"
      -            },
      -            "is_other": {
      -              "const": true,
      -              "description": "Present on the rolled-up line that sums the clients too small to name.",
      -              "type": "boolean"
      -            },
      -            "name": {
      -              "anyOf": [
      -                {
      -                  "type": "string"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            "per_month": {
      -              "description": "`amount` divided by every month of the window.",
      -              "type": "number"
      -            }
      -          },
      -          "required": [
      -            "counterparty_id",
      -            "name",
      -            "currency",
      -            "amount",
      -            "per_month",
      -            "count"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "by_client_truncated": {
      -        "description": "True when the client grouping hit its cap: the folded line may hold more than `client_count` names, so say the list is partial.",
      -        "type": "boolean"
      -      },
      -      "excluded": {
      -        "additionalProperties": false,
      -        "description": "What fell out of the figure, as three invoice counts kept apart.",
      -        "properties": {
      -          "credit_notes": {
      -            "description": "Credit notes netted into the figure.",
      -            "type": "number"
      -          },
      -          "one_off": {
      -            "description": "Issued invoices under a context not counted.",
      -            "type": "number"
      -          },
      -          "unreadable_rows": {
      -            "anyOf": [
      -              {
      -                "type": "number"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ],
      -            "description": "Invoices with no readable net amount or currency. Null when unmeasured."
      -          }
      -        },
      -        "required": [
      -          "one_off",
      -          "credit_notes",
      -          "unreadable_rows"
      -        ],
      -        "type": "object"
      -      },
      -      "invoice_count": {
      -        "description": "Issued invoices in the window, counted or not.",
      -        "type": "number"
      -      },
      -      "monthly_average": {
      -        "description": "`totals` divided by every month of the window — the figure an MRR reports, per currency.",
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "amount": {
      -              "type": "number"
      -            },
      -            "currency": {
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "currency",
      -            "amount"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "months_in_window": {
      -        "description": "Every month of the window — the divisor the average used.",
      -        "type": "number"
      -      },
      -      "months_with_revenue": {
      -        "description": "Months holding at least one invoice of the applied set.",
      -        "type": "number"
      -      },
      -      "per_month": {
      -        "description": "The applied set's net revenue per month, every window month once in order. A dark month carries an empty `amounts`.",
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "amounts": {
      -              "items": {
      -                "additionalProperties": false,
      -                "properties": {
      -                  "amount": {
      -                    "type": "number"
      -                  },
      -                  "currency": {
      -                    "type": "string"
      -                  }
      -                },
      -                "required": [
      -                  "currency",
      -                  "amount"
      -                ],
      -                "type": "object"
      -              },
      -              "type": "array"
      -            },
      -            "month": {
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "month",
      -            "amounts"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "totals": {
      -        "description": "The applied set's net revenue over the window, one entry per currency it carries, never converted.",
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "amount": {
      -              "type": "number"
      -            },
      -            "currency": {
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "currency",
      -            "amount"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "unattributed_count": {
      -        "anyOf": [
      -          {
      -            "type": "number"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Invoices Well could place on neither side, reported beside the figure rather than inside it. Null when unmeasured."
      -      },
      -      "unclassified_count": {
      -        "anyOf": [
      -          {
      -            "type": "number"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Invoices carrying no billing context, as the sum reported them. In the figure only when the unclassified key is counted."
      -      }
      -    },
      -    "required": [
      -      "totals",
      -      "monthly_average",
      -      "per_month",
      -      "months_in_window",
      -      "months_with_revenue",
      -      "invoice_count",
      -      "unclassified_count",
      -      "unattributed_count",
      -      "excluded",
      -      "by_client",
      -      "by_client_truncated"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "by_client": {
      +        "description": "The value per client on the same issued-invoice basis — every invoice in the window, counted or not under the recurring rule. One line per client per currency, largest first; the rest fold into one `is_other` line per currency.",
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "amount": {
      +              "description": "The client's issued total over the window, net of credit notes, in `currency`.",
      +              "type": "number"
      +            },
      +            "client_count": {
      +              "description": "On an `is_other` line, how many clients it sums.",
      +              "type": "number"
      +            },
      +            "count": {
      +              "description": "Issued invoices behind the total.",
      +              "type": "number"
      +            },
      +            "counterparty_id": {
      +              "type": [
      +                "string",
      +                "null"
      +              ]
      +            },
      +            "currency": {
      +              "type": "string"
      +            },
      +            "is_other": {
      +              "const": true,
      +              "description": "Present on the rolled-up line that sums the clients too small to name.",
      +              "type": "boolean"
      +            },
      +            "name": {
      +              "type": [
      +                "string",
      +                "null"
      +              ]
      +            },
      +            "per_month": {
      +              "description": "`amount` divided by every month of the window.",
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "counterparty_id",
      +            "name",
      +            "currency",
      +            "amount",
      +            "per_month",
      +            "count"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "by_client_truncated": {
      +        "description": "True when the client grouping hit its cap: the folded line may hold more than `client_count` names, so say the list is partial.",
      +        "type": "boolean"
      +      },
      +      "excluded": {
      +        "additionalProperties": false,
      +        "description": "What fell out of the figure, as three invoice counts kept apart.",
      +        "properties": {
      +          "credit_notes": {
      +            "description": "Credit notes netted into the figure.",
      +            "type": "number"
      +          },
      +          "one_off": {
      +            "description": "Issued invoices under a context not counted.",
      +            "type": "number"
      +          },
      +          "unreadable_rows": {
      +            "description": "Invoices with no readable net amount or currency. Null when unmeasured.",
      +            "type": [
      +              "number",
      +              "null"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "one_off",
      +          "credit_notes",
      +          "unreadable_rows"
      +        ],
      +        "type": "object"
      +      },
      +      "invoice_count": {
      +        "description": "Issued invoices in the window, counted or not.",
      +        "type": "number"
      +      },
      +      "monthly_average": {
      +        "description": "`totals` divided by every month of the window — the figure an MRR reports, per currency.",
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "amount": {
      +              "type": "number"
      +            },
      +            "currency": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "currency",
      +            "amount"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "months_in_window": {
      +        "description": "Every month of the window — the divisor the average used.",
      +        "type": "number"
      +      },
      +      "months_with_revenue": {
      +        "description": "Months holding at least one invoice of the applied set.",
      +        "type": "number"
      +      },
      +      "per_month": {
      +        "description": "The applied set's net revenue per month, every window month once in order. A dark month carries an empty `amounts`.",
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "amounts": {
      +              "items": {
      +                "additionalProperties": false,
      +                "properties": {
      +                  "amount": {
      +                    "type": "number"
      +                  },
      +                  "currency": {
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "currency",
      +                  "amount"
      +                ],
      +                "type": "object"
      +              },
      +              "type": "array"
      +            },
      +            "month": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "month",
      +            "amounts"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "totals": {
      +        "description": "The applied set's net revenue over the window, one entry per currency it carries, never converted.",
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "amount": {
      +              "type": "number"
      +            },
      +            "currency": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "currency",
      +            "amount"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "unattributed_count": {
      +        "description": "Invoices Well could place on neither side, reported beside the figure rather than inside it. Null when unmeasured.",
      +        "type": [
      +          "number",
      +          "null"
      +        ]
      +      },
      +      "unclassified_count": {
      +        "description": "Invoices carrying no billing context, as the sum reported them. In the figure only when the unclassified key is counted.",
      +        "type": [
      +          "number",
      +          "null"
      +        ]
      +      }
      +    },
      +    "required": [
      +      "totals",
      +      "monthly_average",
      +      "per_month",
      +      "months_in_window",
      +      "months_with_revenue",
      +      "invoice_count",
      +      "unclassified_count",
      +      "unattributed_count",
      +      "excluded",
      +      "by_client",
      +      "by_client_truncated"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedOutput schema / properties / measured / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "contexts": {
      -        "description": "One verdict per listed context, in the order `groups` lists them.",
      -        "items": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "cadence": {
      -              "anyOf": [
      -                {
      -                  "enum": [
      -                    "monthly",
      -                    "bimonthly",
      -                    "quarterly",
      -                    "yearly"
      -                  ],
      -                  "type": "string"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ],
      -              "description": "The cadence the context's billed months formed, or null when none did or the months could not be read."
      -            },
      -            "context_key": {
      -              "type": "string"
      -            },
      -            "label": {
      -              "type": "string"
      -            },
      -            "missed_rule": {
      -              "anyOf": [
      -                {
      -                  "type": "string"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ],
      -              "description": "Why the context is out: a cadence rule it missed (\"one_month\", \"too_few_months\", \"irregular_gaps\", \"multiple_debits_in_month\"), or \"months_unreadable\" when the rows carried no readable month for it. Null when it is in."
      -            },
      -            "months_billed": {
      -              "description": "The distinct months the context billed in, sorted, as YYYY-MM.",
      -              "items": {
      -                "type": "string"
      -              },
      -              "type": "array"
      -            }
      -          },
      -          "required": [
      -            "context_key",
      -            "label",
      -            "cadence",
      -            "missed_rule",
      -            "months_billed"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "policy": {
      -        "description": "The recurring rule the verdicts applied, in one line for the answer to restate.",
      -        "type": "string"
      -      },
      -      "recurring_contexts": {
      -        "description": "The keys the cadence rule counted — the measured set itself, which a recorded pick can still outrank.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "policy",
      -      "contexts",
      -      "recurring_contexts"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "contexts": {
      +        "description": "One verdict per listed context, in the order `groups` lists them.",
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "cadence": {
      +              "anyOf": [
      +                {
      +                  "enum": [
      +                    "monthly",
      +                    "bimonthly",
      +                    "quarterly",
      +                    "yearly"
      +                  ],
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ],
      +              "description": "The cadence the context's billed months formed, or null when none did or the months could not be read."
      +            },
      +            "context_key": {
      +              "type": "string"
      +            },
      +            "label": {
      +              "type": "string"
      +            },
      +            "missed_rule": {
      +              "description": "Why the context is out: a cadence rule it missed (\"one_month\", \"too_few_months\", \"irregular_gaps\", \"multiple_debits_in_month\"), or \"months_unreadable\" when the rows carried no readable month for it. Null when it is in.",
      +              "type": [
      +                "string",
      +                "null"
      +              ]
      +            },
      +            "months_billed": {
      +              "description": "The distinct months the context billed in, sorted, as YYYY-MM.",
      +              "items": {
      +                "type": "string"
      +              },
      +              "type": "array"
      +            }
      +          },
      +          "required": [
      +            "context_key",
      +            "label",
      +            "cadence",
      +            "missed_rule",
      +            "months_billed"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "policy": {
      +        "description": "The recurring rule the verdicts applied, in one line for the answer to restate.",
      +        "type": "string"
      +      },
      +      "recurring_contexts": {
      +        "description": "The keys the cadence rule counted — the measured set itself, which a recorded pick can still outrank.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "policy",
      +      "contexts",
      +      "recurring_contexts"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • removedOutput schema / properties / resolved_workspace / properties / name / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / resolved_workspace / properties / name / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / unreadable_rows / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / unreadable_rows / type
      Added value: +[
      +  "number",
      +  "null"
      +]
  2. Changed7 schema fields changed
    • addedOutput schema / properties / choice_source
      Added value: +{
      +  "anyOf": [
      +    {
      +      "enum": [
      +        "recorded_pick",
      +        "measured"
      +      ],
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "What settled `recurring_contexts`: the pick this conversation recorded, or the cadence the read measured. Null when the card still asks."
      +}
    • addedOutput schema / properties / invoice_basis
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "by_client": {
      +          "description": "The value per client on the same issued-invoice basis — every invoice in the window, counted or not under the recurring rule. One line per client per currency, largest first; the rest fold into one `is_other` line per currency.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "amount": {
      +                "description": "The client's issued total over the window, net of credit notes, in `currency`.",
      +                "type": "number"
      +              },
      +              "client_count": {
      +                "description": "On an `is_other` line, how many clients it sums.",
      +                "type": "number"
      +              },
      +              "count": {
      +                "description": "Issued invoices behind the total.",
      +                "type": "number"
      +              },
      +              "counterparty_id": {
      +                "anyOf": [
      +                  {
      +                    "type": "string"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              },
      +              "currency": {
      +                "type": "string"
      +              },
      +              "is_other": {
      +                "const": true,
      +                "description": "Present on the rolled-up line that sums the clients too small to name.",
      +                "type": "boolean"
      +              },
      +              "name": {
      +                "anyOf": [
      +                  {
      +                    "type": "string"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              },
      +              "per_month": {
      +                "description": "`amount` divided by every month of the window.",
      +                "type": "number"
      +              }
      +            },
      +            "required": [
      +              "counterparty_id",
      +              "name",
      +              "currency",
      +              "amount",
      +              "per_month",
      +              "count"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "by_client_truncated": {
      +          "description": "True when the client grouping hit its cap: the folded line may hold more than `client_count` names, so say the list is partial.",
      +          "type": "boolean"
      +        },
      +        "excluded": {
      +          "additionalProperties": false,
      +          "description": "What fell out of the figure, as three invoice counts kept apart.",
      +          "properties": {
      +            "credit_notes": {
      +              "description": "Credit notes netted into the figure.",
      +              "type": "number"
      +            },
      +            "one_off": {
      +              "description": "Issued invoices under a context not counted.",
      +              "type": "number"
      +            },
      +            "unreadable_rows": {
      +              "anyOf": [
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ],
      +              "description": "Invoices with no readable net amount or currency. Null when unmeasured."
      +            }
      +          },
      +          "required": [
      +            "one_off",
      +            "credit_notes",
      +            "unreadable_rows"
      +          ],
      +          "type": "object"
      +        },
      +        "invoice_count": {
      +          "description": "Issued invoices in the window, counted or not.",
      +          "type": "number"
      +        },
      +        "monthly_average": {
      +          "description": "`totals` divided by every month of the window — the figure an MRR reports, per currency.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "amount": {
      +                "type": "number"
      +              },
      +              "currency": {
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "currency",
      +              "amount"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "months_in_window": {
      +          "description": "Every month of the window — the divisor the average used.",
      +          "type": "number"
      +        },
      +        "months_with_revenue": {
      +          "description": "Months holding at least one invoice of the applied set.",
      +          "type": "number"
      +        },
      +        "per_month": {
      +          "description": "The applied set's net revenue per month, every window month once in order. A dark month carries an empty `amounts`.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "amounts": {
      +                "items": {
      +                  "additionalProperties": false,
      +                  "properties": {
      +                    "amount": {
      +                      "type": "number"
      +                    },
      +                    "currency": {
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "currency",
      +                    "amount"
      +                  ],
      +                  "type": "object"
      +                },
      +                "type": "array"
      +              },
      +              "month": {
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "month",
      +              "amounts"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "totals": {
      +          "description": "The applied set's net revenue over the window, one entry per currency it carries, never converted.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "amount": {
      +                "type": "number"
      +              },
      +              "currency": {
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "currency",
      +              "amount"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "unattributed_count": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "description": "Invoices Well could place on neither side, reported beside the figure rather than inside it. Null when unmeasured."
      +        },
      +        "unclassified_count": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "description": "Invoices carrying no billing context, as the sum reported them. In the figure only when the unclassified key is counted."
      +        }
      +      },
      +      "required": [
      +        "totals",
      +        "monthly_average",
      +        "per_month",
      +        "months_in_window",
      +        "months_with_revenue",
      +        "invoice_count",
      +        "unclassified_count",
      +        "unattributed_count",
      +        "excluded",
      +        "by_client",
      +        "by_client_truncated"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "The window's issued revenue under the applied recurring set. Null when no set applies — the card still asks."
      +}
    • addedOutput schema / properties / measured
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "contexts": {
      +          "description": "One verdict per listed context, in the order `groups` lists them.",
      +          "items": {
      +            "additionalProperties": false,
      +            "properties": {
      +              "cadence": {
      +                "anyOf": [
      +                  {
      +                    "enum": [
      +                      "monthly",
      +                      "bimonthly",
      +                      "quarterly",
      +                      "yearly"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ],
      +                "description": "The cadence the context's billed months formed, or null when none did or the months could not be read."
      +              },
      +              "context_key": {
      +                "type": "string"
      +              },
      +              "label": {
      +                "type": "string"
      +              },
      +              "missed_rule": {
      +                "anyOf": [
      +                  {
      +                    "type": "string"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ],
      +                "description": "Why the context is out: a cadence rule it missed (\"one_month\", \"too_few_months\", \"irregular_gaps\", \"multiple_debits_in_month\"), or \"months_unreadable\" when the rows carried no readable month for it. Null when it is in."
      +              },
      +              "months_billed": {
      +                "description": "The distinct months the context billed in, sorted, as YYYY-MM.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              }
      +            },
      +            "required": [
      +              "context_key",
      +              "label",
      +              "cadence",
      +              "missed_rule",
      +              "months_billed"
      +            ],
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "policy": {
      +          "description": "The recurring rule the verdicts applied, in one line for the answer to restate.",
      +          "type": "string"
      +        },
      +        "recurring_contexts": {
      +          "description": "The keys the cadence rule counted — the measured set itself, which a recorded pick can still outrank.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        }
      +      },
      +      "required": [
      +        "policy",
      +        "contexts",
      +        "recurring_contexts"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "The read's own cadence verdicts. Null on a refused read; always present on a successful one, partial included."
      +}
    • changedOutput schema / properties / partial / description
      Previous value: -"True when the aggregate behind these figures was cut short. Every amount is then a FLOOR rather than a measurement."New value: +"True when the aggregate behind these figures was cut short. Every amount is then a FLOOR rather than a measurement, and the recurring set is never settled by one."
    • addedOutput schema / properties / recurring_contexts
      Added value: +{
      +  "description": "The settled set: the keys the figure counts as recurring, applied as they stand when `reuse_stored_choice` is true. Empty when the card still asks — and also when the verdict is that nothing recurs, which `reuse_stored_choice` tells apart.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / reuse_stored_choice
      Added value: +{
      +  "description": "True when the card asks nothing this call: the recurring set is already settled — by the pick this conversation recorded, or by the cadence the read measured. Apply `recurring_contexts` as they stand and wait for nothing. An empty set beside `true` is the verdict that nothing in the window recurs: say so plainly, never render a zero.",
      +  "type": "boolean"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "groups",
      -  "totals",
      -  "partial",
      -  "unreadable_rows",
      -  "party_scope",
      -  "window",
      -  "success"
      -]New value: +[
      +  "groups",
      +  "totals",
      +  "recurring_contexts",
      +  "choice_source",
      +  "reuse_stored_choice",
      +  "measured",
      +  "invoice_basis",
      +  "partial",
      +  "unreadable_rows",
      +  "party_scope",
      +  "window",
      +  "success"
      +]
  3. Changed3 schema fields changed
    • changedOutput schema / properties / newly_connected / description
      Previous value: -"Tools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. Start the reply with one line per entry, in the person's language: \"<name> is connected.\". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later."New value: +"Tools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. The connected-line rule says when to tell an entry; when it does, one line per entry, in the person's language: \"<name> is connected.\". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later."
    • addedOutput schema / properties / party_scope
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "applied": {
      +          "type": "boolean"
      +        },
      +        "requested": {
      +          "enum": [
      +            "purchase",
      +            "sales",
      +            "intra_self",
      +            "unattributed"
      +          ],
      +          "type": "string"
      +        },
      +        "side_unknown": {
      +          "type": "boolean"
      +        }
      +      },
      +      "required": [
      +        "requested",
      +        "applied",
      +        "side_unknown"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "What the receivable side resolved to. `side_unknown: true` means the workspace resolved no own company, so NO side filter was applied (`applied: false`) and the list covers invoices on both sides — say the side is unknown, never that these are the contexts the workspace issued. `null` when the read reported no scope resolution."
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "groups",
      -  "totals",
      -  "partial",
      -  "unreadable_rows",
      -  "window",
      -  "success"
      -]New value: +[
      +  "groups",
      +  "totals",
      +  "partial",
      +  "unreadable_rows",
      +  "party_scope",
      +  "window",
      +  "success"
      +]
  4. Changed1 schema field changed
    • addedInput schema / properties / workspace_scope
      Added value: +{
      +  "description": "Restrict this call to the family: the token's primary workspace plus the company workspaces under it that you are a member of. Unrelated authorized workspaces drop out of the read; row reads merge across the family, while a per-workspace figure still reports exactly one workspace.",
      +  "enum": [
      +    "family"
      +  ],
      +  "type": "string"
      +}
  5. Changed1 schema field changed
    • addedOutput schema / properties / newly_connected
      Added value: +{
      +  "description": "Tools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. Start the reply with one line per entry, in the person's language: \"<name> is connected.\". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "name": {
      +        "type": "string"
      +      },
      +      "service_id": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "name",
      +      "service_id"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  6. Changed4 schema fields changed
    • addedInput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_note
      Added value: +{
      +  "description": "Present only when the server opened a fresh lane, stating that no choice recorded earlier was read.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_source
      Added value: +{
      +  "description": "Where the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.",
      +  "enum": [
      +    "host_meta",
      +    "argument",
      +    "minted"
      +  ],
      +  "type": "string"
      +}
  7. Added

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/no-destructive/closed-world, yet the description still adds substantial non-obvious behavior: `partial: true` makes every amount a floor and prevents the read from settling the recurring set, `unreadable_rows: null` is explicitly not zero, negative-netting contexts stay listed, and `success` must be read before `groups` because a failed read looks identical to an empty window. These are exactly the operational caveats annotations cannot express.

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?

Front-loaded with purpose, the sibling disambiguation, and the field walkthrough, then bolded call-outs for the unclassified entry and the no-conversion rule, so an agent can stop reading early. It is nonetheless very long and takes on a lot of return-value exposition that overlaps the output schema, which keeps it from 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?

Covers everything an agent needs for a complex, card-driven read: window semantics, reuse/choice-source branching, aggregation caveats, side-unknown and partial-read failure modes, and the exact follow-up calls and arguments. Nothing material is left to inference.

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 earns an extra point by adding semantics the schema does not carry, notably that whole-month `from`/`to` windows must be extended across BOTH windows when a comparison will be measured, and by restating the whole-month constraint and the `workspace_id` decision rule in operational terms. It does largely repeat the schema's inclusive/exclusive wording for `from`/`to`.

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?

Opens with a specific verb+resource+scope ('List the billing contexts a reader can count as recurring revenue over one window') and explicitly distinguishes itself from the sibling it is most likely confused with: it 'measures nothing `well_sum_invoices` did not already measure, but it does judge each context by the months it billed.' It also names the downstream tools (`well_render_mrr`, `well_switch_workspace`, `well_wait_for_selection`) so the agent can place it in the flow 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?

Gives explicit branches: apply the result directly when `reuse_stored_choice` is true, drive the card and read back via `well_wait_for_selection` when it is false, and treat an empty `recurring_contexts` beside `reuse_stored_choice: true` as a verdict to report rather than a zero to render. It also states the when-not condition for `workspace_id` (single vs. multiple authorized workspaces) and the pre-condition for `party_scope.side_unknown` (resolve the own company, then list again).

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources