List periods
well_list_periodsList 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.
analyzable: the month can be REPORTED ON. True once the month has ENDED and while it remains inside the window the canvas endpoints serve; false for the month in progress, for a future month, and for one too far back. It does NOT ask for a close verdict, because a report reads transactions and an unchecked month still has them. Read this one for an analysis 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_invoiceswould return. 0 whenever invoice_state is "none", including when the check did not run.transaction_count: how many transactions the month holds, dated on the basis this purpose measures on.
analysiscounts onexecuted_at, the same columnwell_sum_transactionsranges, so a month's count and a reporting figure cover the same WINDOW. It is not the same row set, and must never be quoted as the figure's row count: the sum can also drop internal transfers and exempt categories on request, and it widens to a parent's granted transactions where this count does not. Read it as a presence signal for the month.closeandcollectcount on the books date,COALESCE(value_date, booking_date), which a transaction the bank has not booked does not carry — so a zero under those purposes means no BOOKED transaction, never an empty month.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. Dated on the books, so it is ABSENT under
analysisrather than 0 — that purpose counts on execution and never measures this errand, and a 0 would read as "nothing left to categorize". It is also absent on a month the coverage read did not cover. Never read an absent count as "nothing left to categorize": say the month was not measured, or read it again.categorized_unposted_transactions: categorized transactions not yet posted to the ledger — part of the "review and book" errand. Dated on the books, absent under
analysis, and absent on an unmeasured month for the same reason.invoice_state / missing_invoice_count: the month's invoice-retrieval verdict and the count behind it. Both are ABSENT on a month a
analysislist skipped — that purpose bounds its invoice read by execution-dated activity while the errand is dated on the books, so the two disagree and a "none" there would be a claim nothing measured. Absent is not "owes nothing"; read it from acloseorcollectlist.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".daysis empty for every month whose invoice_state is "none" — an unchecked month has no day the tool can call clean — and it is empty for EVERY month on apurpose: "analysis"call, whatever that month's invoice_state, because the reporting axis paints no day. On that purpose an emptydaystherefore says nothing about invoice coverage, and neither does an absent invoice_state. This is calendar detail for a picker to paint; quote the month's own counts, not a day list, when answering in prose.analysis_days: present ONLY for a
purpose: "analysis"call — the DAYS and whether a breakdown can name what each holds, ascending, each{ day, state }over "categorized" / "uncategorized" / "neutral". An "uncategorized" day holds a transaction with no category. It still COUNTS toward a burn total, which filters on no category at all; a cost breakdown just reports it as uncategorised rather than under a named category. Never say a total is short because of it. Unlike the other two axes a quiet day IS listed, as "neutral". Calendar detail for the reporting picker.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, likedaysis 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. On a purpose: "analysis" call it is instead the NEWEST analyzable month, because a figure describes the latest ended period and a month outside the reporting window would be refused by the endpoints that serve it.
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. Pass purpose: "analysis" when a REPORTING SKILL is already running and is choosing the month its figure will cover, so the picker offers only analyzable months and paints the CATEGORIZATION day axis: neither invoice coverage nor close readiness is the decision being made, but an uncategorized day is one a breakdown cannot attribute. A user who merely mentions a report, a burn figure or a cost breakdown is NOT the trigger — naming one of those is phrasing, and phrasing never sets this field. Example: "What months do you have for me? I'm trying to work out my average burn." is a plain listing request that names a reason — it is NOT a reporting skill calling for its own period pick, so this call OMITS purpose. Only a caller that IS the reporting flow itself (an avg-burn/cost-structure/cash-flow-waterfall skill run, already past its own gates, now needing the month to compute against) passes "analysis" — never derive it from words in the user's own message, no matter how closely they match a report. 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. A purpose: "analysis" call pays the same day-coverage read, dated on the execution basis, because it paints the categorization day axis. 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).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | One 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`. | |
| reply | No | One sentence, IN THE LANGUAGE THE USER IS WRITING IN, that the click sends into the conversation as their own message. Write what the PERSON would say about the months they pick, in their words, not an instruction to yourself. You write it BEFORE they click, so you cannot know what they will choose: put {picked} where the pick belongs and the card replaces it with the names they actually picked, one or several. In English it would read "Let's work on {picked}." Write the same shape in the user's language. {picked} is required: a sentence that names a pick itself names the one you guessed, so the card refuses it and sends its own English instead. At most 160 characters. Omitted sends an English sentence the card builds itself, which is wrong for any reader not writing in English. | |
| title | No | Heading for the picker card shown to the user. At most 120 characters. | |
| months | No | How 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. | |
| purpose | No | Why the months are being listed, set by the calling skill's own flow — never inferred from this message. "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. "analysis" is reporting: the card offers only the months a canvas can report on, paints the categorization day axis, counts on the execution date the canvas aggregates measure on, and therefore omits the books-dated errand counts entirely rather than reporting them as 0 — set it ONLY when a reporting skill is already running its own period-pick step, not just because this message names one (a burn figure, a cost breakdown, "my report"). Naming a report is phrasing; it never sets this field on its own. Omit or "collect" for invoice retrieval (the default, and the right choice for a plain "what months do you have" question, even one that mentions why) — this paints the retrieval axis and skips the close-readiness fields. | |
| subtitle | No | Supporting line under the picker card's heading. At most 240 characters. | |
| workspace_id | No | Target 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. | |
| conversation_id | No | 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. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| error | No | ||
| hints | No | ||
| periods | Yes | ||
| success | Yes | ||
| next_step | No | What to do with the card this result renders. Added by the dispatcher when the card asks for a click. | |
| workspace_id | Yes | ||
| base_currency | Yes | ||
| default_period | Yes | ||
| conversation_id | No | The conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation. | |
| navigable_years | Yes | The calendar years a `year` request is answered for. A picker's year steppers stop here. | |
| resolved_workspace | No | The workspace that answered, when the caller named none and the token authorizes several. | |
| conversation_id_note | No | Present only when the server opened a fresh lane, stating that no choice recorded earlier was read. | |
| conversation_id_source | No | Where the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened. | |
| fiscal_year_start_month | Yes |