What's new

A running log of features and fixes shipped to Dough.

Sunday, October 11, 2026

1 change

New features

  • Agent gym 0.1.26: mark each tab of your workbook core or flexible

    Right after the gym reads your workbook, it now asks which tabs are core and which are flexible. Core tabs are reproduced as you built them and scored exactly as before. Flexible tabs are ones the gym may rebuild as a query, replace or remove: their differences still show in the report, one line per tab, but never fail a period or count against a holdout. A pasted export that a Dough query replaces must still tie to that query. Once you confirm the labels they are locked for that agent. Agents set up before this release are scored as they always were.

Saturday, October 10, 2026

2 changes

New features

  • SOX onboarding: ICFR card 2.1 with system-filled answers and a three-step approval

    The ICFR card now asks people only for the 8 answers Dough can't know: control ID, Asana link, primary and backup owner, SOX in scope, control criticality, SOX risk profile and review pattern. Dough fills the builder, version, error rate (from the gym report), AI base risk, documentation depth and oversight model. Run Log, Change History and Reviewer Certification are gone; an Approvals tab takes the senior manager, the builder and an independent approver in that order, three different people, and the third approval makes the agent Live and locks the card. A new version needs all three approvals again.

Fixes

  • Agent gym 0.1.25: a column with no header in your workbook can be declared

    When a column in your hand-built workbook has no header (an exchange-rate tab whose currency column is unlabelled, say), the gym had no way to say so: declaring the reference's header as blank was read as not declaring it, and the source check then refused every period. A blank header can now be declared, setup finds such a tab's header row (it used to guess the first row) and declares the unlabelled column for you to name, and the check that ties a saved query to the tab it replaces refuses with the fix when a column it needs is not declared, instead of stopping with an error.

Friday, October 9, 2026

1 change

Fixes

  • Agent gym 0.1.24: an agent's code now follows your company's worksheet presentation rules

    When your company publishes its own worksheet presentation rules, the gym copies them into each agent it sets up. Until now, an agent could be built from the gym's generic fallback text without anyone opening your company's copy, and under the copy's old wording the rules exempted every tab the gym declares, which is every tab. The setup step that writes the rules now stops and prints them before anything is confirmed. Building a period is refused until the session writing the agent's code has read the agent's own copy, and the rules apply to every tab: new tabs follow them throughout, and existing tabs follow them wherever they name something, such as divider tabs, title blocks and header rows. An agent set up earlier is pointed to one command that brings it onto the new wording, keeping your company's rules exactly as they were read, and its scored periods are then rebuilt. The gym now also keeps each reference's layout (fills, fonts, column widths and tab colours) when it freezes a period, shows it to whoever writes the agent's code, and lists every layout difference in the report, without ever failing a period over one. A Google Sheet frozen earlier gains its layout when it is re-frozen with --refresh, and stays the same reference.

Wednesday, October 7, 2026

1 change

Fixes

  • Agent gym 0.1.21: a holdout that matches except for accepted changes no longer reads as a failure

    A holdout whose only differences are design changes a person already accepted on the training periods, such as a replaced FX tab, now reads "matched, except 2 differences already accepted in training" in the report and the drafted release notes, instead of "0 of 1 run passed". The report lists holdout runs for the version under review and names earlier drafts' runs in one line, and a sheet never checked for an Apps Script no longer says a script was skipped. On the agent's version page, the holdout's own section and the detailed gym report use the same wording, and each such difference is marked "accepted in training" instead of unjudged.

Tuesday, October 6, 2026

5 changes

Fixes

  • Agent gym 0.1.20: a Google Sheet with an impossible date no longer stops the read

    A date-formatted cell holding a number past year 9999, such as a mistyped date or a pasted export ID, made the agent gym fail to read the whole Google Sheet, so the period could not be frozen. The gym now reads such a cell as the number it holds, as Sheets itself does, and a reference and a candidate holding the same value still match.

  • A published agent's gym summary is kept and shown

    Publishing an agent with `--report report.json --summary report.md` after holdouts now keeps the summary. Before, a report that included holdout results was saved without its summary, so the version showed "No summary available" and `dough agent info` listed none. The summary now appears on the agent page, the version page and in `dough agent info`; versions that lost it are being restored. A gym summary can include holdout results: it is shown for review and is never used to train the agent. The agent page's report card also offers "Reveal holdout values" when a download needs it, instead of only saying so.

Improvements

  • Data Lake: a slow table can sync on its own schedule

    A connected source can now carry an extra sync for one or two expensive tables, refreshed on their own schedule (for example weekly) while the rest of the source keeps its daily sync. Dough sets these up for you. On the Integrations page, those tables appear in the source's table list as “Synced separately” with their schedule, and the table picker leaves them alone. Agents see each such table's own last-synced time, and a source's overall time is the oldest of its syncs; dashboards keep showing the daily sync's time.

  • Release notes you can write when publishing, and fix afterwards

    Publishing an agent draft on its page now has a **Release notes** box, prefilled with the draft's change summary; whatever you write is what version history shows. The agent's owner can add or edit a version's release notes later from its version page; only the notes change, never the published agent. On the command line, `dough agent publish <name>@<version> --release-notes "..."` was always accepted and is now in the help. Agent gym 0.1.19 drafts the release notes for you in the publish command it prints: the periods settled, how the holdouts went, the differences ruled on, and any decision changed after sign-off.

  • Agent gym 0.1.18: a report written for the reviewer, and who agreed each change

    An agent version's gym summary now opens with what the agent does (a short `purpose:` agreed at the shape step), its result and what that result proves. It then shows **what changed from the hand-built workbook**: each tab's new role and why, what took over each function of the workbook's Apps Script (or why it was dropped), each input as it was and is now, and the checklist steps kept and removed. The sources and shape steps now end with the person's sign-off (`--confirm "<name>"`), and the report shows who confirmed each. If a decision changes after it was confirmed, later steps warn and the report lists each change beside the manifest rulings made since; nothing is blocked. Discover no longer asks for a Google re-login to look for an Apps Script on a sheet that never mentions one: it reads the sheet's tabs, checklist and notes first, asks only when they mention a script, and takes `--no-script` for a sheet that has none. The closing note on what the gym sent to Dough is now a short list. Reports written by earlier gym versions keep their old layout.

Monday, October 5, 2026

1 change

Improvements

  • Agent gym 0.1.14: faster transcript audits on Windows

    The agent gym's transcript audit no longer treats a web address such as `https://sheets.googleapis.com/...` as a file path. On Windows each one was looked up as a network share, which stalled the audit for 20 to 30 seconds per address. Results are unchanged; `file:///` paths are still checked.

Sunday, October 4, 2026

1 change

New features

  • Dough CLI 0.3.2: `dough query get` shows a saved query

    `dough query get --saved <id>` prints a saved query's SQL, its declared parameters and a sha256 of the two, without running it; add `--json` for scripts. The agent gym uses the hash to notice when a query it checked has since been edited. Older CLI versions keep working.

Friday, October 2, 2026

2 changes

New features

  • Dough CLI 0.3.0: report summaries, archived agents, and a change to what gets published

    `dough agent draft` and `dough agent publish` can attach a short summary with a report (`--summary`). `dough agent info` now shows whether an agent is archived, and syncing an archived agent tells you so instead of failing with a vague error. The agent gym keeps its files in two folders of their own, `dough_agent_gym_inputs/` and `dough_agent_gym_eval/`, and from 0.3.0 those two folders are never published with the agent. Every other folder, including ones named `inputs/` or `eval/`, is published as before. This release also adds the upload the agent gym will use. It sends what was typed, what the agent said and which tools it called, with their inputs. That includes the contents of files the agent writes. It never sends what a tool returned, and it strikes secrets from your environment first. Older CLI versions keep working.

Fixes

  • Admin: "Add User" removed — teammates join by signing in

    The "Add User" button in Admin failed every time and has been removed. Teammates now appear in Admin → Users automatically the first time they sign in; set their role from the Users table (new users start as Read). Admin errors, such as removing the last admin, now show their reason in place instead of a generic error page.

Thursday, October 1, 2026

1 change

New features

  • Agent drafts: push, evaluate and publish versions safely

    Push a draft of an agent with `dough agent draft` without touching what everyone runs. Drafts get their own version numbers, can carry an evaluation report, and the owner publishes the head draft with `dough agent publish <name>@<version>` or archives it. Publishing straight from a directory is refused while drafts are open, and a stale copy can no longer overwrite newer work. Update to the latest `dough` CLI. Skills keep their review flow.

Monday, September 28, 2026

1 change

New features

Monday, September 21, 2026

2 changes

New features

  • Connect Anaplan to your data lake

    Anaplan is now available under Finance in Add Integration. Connect your account and choose the data to sync into your data lake like any other source.

  • Run a published agent on its own machine, without a git repository

    A hosted agent can now take its code from a version you published to the registry, not only from a git repository. Pin it as name@version in the agent's Code section and every run downloads that exact version — and the skills it pins — onto the machine before the agent starts. The version is fixed, so the code cannot change underneath a scheduled run, and each run records exactly which version it executed. A pin naming something unpublished or archived is refused when you save it rather than failing later on a machine, and archiving a version stops runs already scheduled against it. An agent still takes its code from one place: a repository or a published version, never both.

Saturday, September 19, 2026

1 change

New features

  • Write large Data Lake query results straight to CSV

    The Dough CLI can now run a saved query and page its governed Data Lake results directly into a CSV file with `dough query run`. Saved SQL is resolved fresh on every run, declared parameters are checked before execution, and rows never pass through the agent's conversation or stdout. Ad-hoc SQL and SQL files work too. The command writes atomically and exits non-zero on query, paging, or file errors, so a partial export cannot be mistaken for a complete result.

Wednesday, September 16, 2026

1 change

New features

Tuesday, September 15, 2026

1 change

New features

  • A public docs site at /docs, no sign-in needed

    Getting started with Dough is readable without an account. /docs now opens for anyone — an overview, a one-command Install page for macOS and Windows, and the dough CLI guide covering login, running agents, and publishing agents and skills. /llms.txt is back alongside it, rendering those same pages as one plain-text file for coding agents and MCP clients, and the MCP metadata advertises both again. The old manual MCP setup page is gone: the installer now configures the connection and installs the plugin for you, so walking through it by hand is a step nobody needs. This reverses the 30 August takedown, but not all of it — the Integrations, Tool Discovery and Filesystem pages stay unpublished, so /docs/integrations and its siblings return 404 and their contents appear nowhere in /llms.txt. Nothing changed for signed-in users: Docs is still absent from the sidebar, and no plan grants it.

Monday, September 14, 2026

1 change

Improvements

  • Data Lake table filters respond instantly

    Type, Source, Hidden and the search box on the Data Lake tables page now narrow the list as you click and type, instead of reloading the page and re-listing the lake on every change. Search no longer needs a submit button. The address bar still tracks the current view, so a filtered list stays shareable and survives a reload.

Sunday, September 13, 2026

2 changes

New features

  • Hide tables from the Data Lake catalog

    An admin can now hide a table from the Data Lake catalog, from that table's own page. A hidden table drops out of the four places a table is picked from — the Tables list, the mappings picker, and the two catalogs an agent browses (integrations.tables and mappings.tables) — so agents stop offering tables your team has moved on from, deprecated, or never wanted used. This is curation, not access control, and the distinction matters: hiding takes nothing away. The table stays fully queryable by name, so every saved query, calculated table, mapping, dashboard widget and scheduled refresh built on it keeps working untouched, and an agent told the table's name can still describe and query it. Hiding is admin-only, but everyone in the org can see what has been hidden: the Tables list has a Hidden filter that shows exactly the hidden tables, and unhiding is one click from the table's page. Every kind of table can be hidden — synced, calculated, uploaded, and your own — and hiding a table also hides its mapped companion, since they are the same data. If you need a table to be genuinely off-limits to some people, that is still Sensitive Tables in Admin, which is unchanged and independent of this.

Improvements

  • See which organization owns uploaded proposal evidence

    The Dough CLI now verifies and prints the organization behind a saved login when you run dough status. Evidence uploads include that same organization id beside the evidence id, making it clear when the CLI and an MCP session are connected to different organizations before a proposal tries to consume tenant-bound evidence.

Saturday, September 12, 2026

2 changes

New features

  • Review related proposals as one batch

    Agents can now group up to 25 related writes for one company and action into a single governed submission. The proposal queue shows one batch row, reviewers make one shared decision, and each child write still keeps its own validation, posting result, and failure state. Batch and child pages keep the shared evidence and decision history together without duplicating it across every write.

Improvements

  • Proposal tables keep up with new fields

    Proposal pages still lead with a purpose-built table for each action, including accounting-specific layouts such as debits and credits or before-and-after changes. When a proposal carries a field that its primary table does not yet show, the Table tab now lists scalar values under Additional fields instead of leaving them visible only in the raw payload. Simple nested context such as an account snapshot is flattened into labeled rows, while arrays stay with their purpose-built renderer or in View payload rather than being reshaped by guesswork.

Wednesday, September 9, 2026

4 changes

New features

  • Correct rejected or failed proposals without losing their history

    A correction now becomes a new proposal linked to the rejected or failed one it replaces. The proposal page keeps the complete revision history and earlier evidence visible, while the replacement goes through fresh validation and approval.

  • Explicitly abandon proposals that will not be corrected

    The latest proposer or an organization admin can close a rejected or failed proposal with a required reason. The queue and proposal page show it as Abandoned, while retaining the original rejected or failed outcome for the audit record. Abandoned failures no longer count as writes that still need attention.

Fixes

  • QuickBooks journal entries keep their Location and Class

    A proposed QuickBooks journal entry could name its account and customer or vendor, but it had no way to carry the Location and Class shown on each line in QuickBooks. Those dimensions can now be included on every line by name or id. Dough resolves them against the connected company before the proposal is raised, shows the resolved Location (including companies that relabel it Business) and Class to the approver, and writes both onto the journal entry when it posts.

Improvements

  • See every upload behind a table, not just the last fifty

    Asking an agent what a table was built from returned the fifty most recent uploads and said there were more, with no way to reach them. One production table has eighty-one uploads, so thirty-one of its source files could not be got at that way at all. The answer now carries a marker for the next page when there is one, and an agent can keep asking until it has the whole history. The newest uploads still come first, so the usual question — what went in most recently, and where did it come from — is still answered by the first reply.

Tuesday, September 8, 2026

3 changes

New features

  • Ask an agent where an uploaded table's numbers came from

    When a table is built by uploading spreadsheets, the files behind it are kept — the workbook or document the data was converted from, and the CSV that was actually loaded. Until now you could only reach them in the app, by finding the table and scrolling its Version History. Agents can now ask where a table is populated from and get the same list: every upload, who made it, what they said it was, and a link to each file. So "what is this table built from, and can I see the source spreadsheet" is one question rather than a hunt. The links open in the browser as you — they are ordinary Dough pages, not shareable file links, and they re-check who you are and whether you may read that table every time they are opened — so an agent hands you the link and you click it. This describes what the table as a whole was built from. Nothing changed about what is stored, and the Version History tab is unchanged.

  • Retire an old saved query without deleting it

    Saved queries can now be archived when they are no longer a trustworthy starting point. An archived query disappears from the active Queries list and from Dough's saved-query tools, so an agent will not pull obsolete SQL into a later analysis, but its SQL and version history remain intact. The Queries page has a separate Archived tab where the query can be reviewed and restored. Agents can archive a query through queries.archive; restoring stays a deliberate action in the app. Existing dashboards that use an archived query keep working.

  • Retire a NetSuite vendor

    Dough can now propose retiring a vendor in NetSuite. You name the vendor the way you actually hold it — “Acme Supplies Ltd”, or its internalId — and Dough resolves it against the live account when you propose, so a vendor that does not exist is refused before anyone approves it. NetSuite matches a vendor's name against its company name as well, so one string can answer for several unrelated-looking records; an ambiguous name comes back with the candidates rather than being guessed at, and a vendor that is already retired still resolves — which is what lets re-proposing one be answered honestly. The approval panel shows the resolved name, the internalId behind a link to the record in NetSuite, and the single field being written. This is a retirement, not a deletion. The vendor's bills, payments and history are untouched, the name stays reserved, and a person can undo it in NetSuite by unticking a box; Dough does not offer a NetSuite delete for any record type. It also does not settle anything already in flight — an open bill stays open and a scheduled payment stays scheduled — what changes is that the vendor stops being selectable on new transactions, and the panel says both. Proposing the same retirement twice is safe: Dough reads the vendor first and, if it is already inactive, reports that rather than writing again. As with the other NetSuite master-data actions and unlike a NetSuite journal entry, a vendor record carries no approval field of its own, so approving in Dough is the only gate.

Friday, September 4, 2026

2 changes

Fixes

  • The "your CLI is out of date" message now works on Windows

    When the server turns away a dough CLI that is too old, its reply names the command to fix it. That reply only ever named the macOS one, so a Windows user hit a wall and was handed a curl command their shell cannot run. It now names both, which is what the CLI itself has always printed. This only showed up where the server's own message is what you see rather than the CLI's, which includes an agent relaying the error back to you in a Claude Code session.

Improvements

  • Attaching evidence to a proposal is one command

    When /dough:propose attaches your session and the files behind an entry, it used to take three steps and a hand-assembled file. The agent had to run a script to hash your files, call the server for a set of upload links, then merge those two results into a JSON file itself and hand that back to the script. That middle step was the problem: the links carry a short-lived credential, and an agent writing a shell command that contains one is refused outright by Claude Code's automatic-approval check — so on some machines the evidence silently failed to upload and the proposal went out with its audit trail missing. There is now a single command, dough evidence upload, that hashes, requests the links, and uploads in one go. The upload links never pass through the agent at all, so there is nothing for it to assemble and nothing to refuse. It also states plainly what it is sending — the session transcript always goes, not only the files you name, and it is usually the largest item — and prints each object with its size before it uploads, so what left your machine is visible afterwards rather than implied. Every object is still declared to the server before any bytes move, which is what lets a file that fails to upload be recorded against the proposal as missing and shown to the approver as a gap, rather than quietly disappearing from a record that then looks complete. This needs an updated dough CLI; until you have one, the previous path still runs, and the plugin now tells the agent which tool to write that file with rather than leaving it to guess.

Thursday, September 3, 2026

2 changes

Improvements

  • Setting up Dough on a Mac is one command too

    The macOS install command now does the whole setup, the way the Windows one already did. It used to download the binary and stop, leaving you to check dependencies, install the Claude Code plugin, sign in, and restart the app yourself. It now makes sure python3 and git are usable, installs the CLI and confirms the binary actually runs, puts it on your PATH, registers the Claude Code hooks and checks they landed, installs the Dough plugin, and signs you in — skipping anything already done, so the same command installs, repairs, and updates. Neither dependency is needed by the CLI itself, which is still a single self-contained binary: Python is what Claude Code runs the Dough hooks with. On a Mac both arrive together, from Apple's Command Line Tools, so there is one thing to install rather than two — and if it is missing the installer opens Apple's installer for you and waits for it to finish rather than telling you to come back later. Homebrew is never assumed to be present, and nothing asks for an administrator password. Two Mac-specific traps are handled rather than left to bite. Until the Command Line Tools are installed, python3 and git in /usr/bin are the same placeholder file, so checking whether the command exists reports success on a Mac that has neither — and merely running it pops an Apple dialog. The installer requires a real answer from a real interpreter and checks before it runs anything from /usr/bin, while a Python from Homebrew, pyenv or python.org is used as it finds it. And because /usr/local/bin belongs to the system on a stock Mac, the CLI normally lands in ~/.local/bin, which is not on the default PATH — so the installer adds it to your shell profile, picking the file your login shell actually reads. One thing it deliberately does not do is pretend it can change the terminal you ran it from: an installer piped into a shell runs in its own, so the dough command needs a new terminal window, and the closing message says so. When it finishes there is still one manual step, called out plainly: fully quit Claude Code and reopen it — closing the window is not enough, because the plugin and hooks are read at startup.

  • Setting up Dough on Windows is one command again

    Getting a Windows machine ready was six steps and two of them were the ones people got wrong: install the CLI, verify it, check whether Python was present and install it if not, install the Claude Code plugin, fully restart Claude Code, then go back and install Git. Each was a separate round-trip, and a machine that looked finished could still be missing a dependency nothing had checked for. The PowerShell install command now does all of it, in dependency order, and stops at the first thing it cannot fix rather than leaving you half set up. It installs Python 3 and Git for Windows if they are missing, installs the CLI and confirms the binary actually runs, registers the Claude Code hooks and checks they landed, installs the Dough plugin, points Claude Code at Git Bash, and signs you in — skipping anything already done, so the same command installs, repairs, and updates. Neither dependency is needed by the CLI itself, which is still a single self-contained binary: Python is what Claude Code runs the Dough hooks with, and Git is required by the Claude Code desktop app. Two Windows-specific traps are handled rather than left to bite. Windows ships a Microsoft Store placeholder for python.exe that is on PATH by default, so the usual `python --version` check can report success on a machine with no Python at all — the installer requires a real answer from a real interpreter, and if the placeholder is shadowing a genuine install it says so and names the path. And because a package manager's PATH changes do not reach a program that is already running, the installer rebuilds its own PATH after each install, which is what removes the "now restart PowerShell" step. Installing Git turned out not to be enough on its own: the Claude Code desktop app can open on a machine that has Git and still refuse to run local sessions, because what it needs is the Git Bash that ships with Git for Windows and it has to be told where that is. The installer now checks for bash.exe rather than for the git command — a minimal git passes a version check and leaves the app just as blocked — and writes the path where the app looks for it. When it finishes there is still one manual step, and it is called out plainly: fully quit Claude Code and reopen it — closing the window is not enough, because the plugin and hooks are read at startup. macOS now does the same, in the entry above.

Sunday, August 30, 2026

3 changes

New features

  • Propose a QuickBooks customer with an address

    A proposed new customer can now carry the fields a real customer record actually has. Creating one wrote 8 of QuickBooks' 42 customer attributes, which meant an agent holding an address had nowhere to put it — and an address folded into the notes field is text nobody can print on an invoice or ship to. A new customer now takes a billing and a shipping address as real addresses (five lines, city, state or province, postal code, country), kept independent of each other because QuickBooks does not copy one to the other. Alongside them: a title, middle name and suffix, the name to print on a cheque, four separate phone numbers instead of one — main, mobile, alternate and fax — and a website. Editing a customer accepts the same contact details; changing an address is not offered yet, and says so with the reason rather than failing on an unrecognised field. Everything set is shown to the approver before they decide, addresses included, because a write nobody can see is not a write anyone can authorise. Two limits were also wrong against Intuit's published reference and are corrected: a customer note was capped at 4000 characters where QuickBooks allows 2000 — so a long note passed every check and then failed when it posted, after the approval — and a company name was capped at 50 where QuickBooks allows 100. A website is also checked properly now: it must be a full URL with http:// or https://, because QuickBooks refuses a bare domain — and finding that out at approval time is a wasted decision. QuickBooks additionally checks the domain against a list of its own and will still refuse one it does not recognise when the write posts, which Dough cannot check for you, so the field says so plainly.

Improvements

  • The Docs section has been taken down

    Docs is gone from the sidebar, and /docs no longer opens for anyone — every organization, on every plan. The pages had drifted from the product, and a set of instructions that is wrong in places is worse than none. Two related things went with it: /llms.txt, which served the full text of those same pages to anyone on the internet with no sign-in and no plan check, now returns 404, and the MCP metadata no longer advertises a documentation URL that would only bounce you back. Nothing else changed — a bookmark to /docs now sends you to your usual starting page. The reference that matters for the tools themselves is still live and still the source of truth: tools.list and tools.describe over MCP, and dough --help on the CLI.

  • The table picker no longer offers you a fraction of a source

    Adding a source and choosing tables could show you a partial list and present it as the whole thing. A Coupa connection offered 20 tables; the source had 84, and the other 64 were simply never imported — no warning, no error, and the full list appeared later under Manage tables as if it had always been there. Two things caused it. The check meant to catch this read a field that was never populated, so it had never once fired since it shipped; and a catalogue that Polytomic had begun filling on its own — with nothing reporting that work as in progress — was taken for a finished one. Both are fixed, and the picker now tells you what it knows: while a source is still being read it shows the tables found so far with "Still discovering — N found so far" above them, and keeps adding to the list as they arrive, rather than either hiding them or making you wait behind a spinner. A large source can take several minutes to enumerate fully. There is also a new choice at the top of the picker: "Sync all tables from this source", which covers tables discovered after you save — including ones the source gains later. Without it a selection is a snapshot of the tables that existed at the moment you saved, which is what made a still-growing catalogue such a trap. Existing sources keep the tables they already sync until you re-open Manage tables and change something.

Saturday, August 29, 2026

1 change

New features

  • Connect your own BigQuery project as the data lake

    An organization that already has its data in BigQuery no longer needs Dough to provision a lake alongside it. You point Dough at your own project, list the datasets it may read, and nominate exactly ONE of them as the write dataset — the only place Dough ever creates anything. Calculated tables, uploaded tables, and mapped companions all land there; every other dataset you list is read-only, and nothing Dough does can write to it. The agent-facing side follows from the same setup rather than being described separately: the tool descriptions an agent reads are now generated from your organization's actual layout, so `integrations.tables`, `integrations.query`, `tables.create`, and `tables.update` name YOUR datasets and say plainly which one is written to, instead of teaching the layout of a Dough-provisioned lake that a brought-along project does not have. Nothing changes for an organization on a Dough-provided lake: it is described as the single dataset it is. The rule that was already there still holds either way — query the `name` a tool gives you, verbatim, and never assemble one, because how tables are laid out differs between organizations.

Friday, August 28, 2026

3 changes

New features

  • Create a NetSuite department

    Dough can now propose creating a department in NetSuite — the first of the three segments a OneWorld close is built on. Name the department, name the subsidiary it belongs to, and optionally name a parent to nest it under; both the subsidiary and the parent are resolved against the live account when the proposal is raised, so one that does not exist is refused before anyone approves it, and an ambiguous name comes back with candidates rather than a guess. Three things the approval panel is explicit about, each because it was measured against a real account rather than read off NetSuite's record model. The subsidiary is required by Dough although NetSuite does not require it: a department created without one is accepted and silently scoped to whichever subsidiary NetSuite picks, which is a decision nobody would have seen. A department name is capped at 60 characters and cannot contain a colon, because NetSuite writes a department's full path as “Parent : Child” and a name containing one could not be told apart from a path. And a name already in use is refused by NetSuite at post time, after approval, reported with the same code it uses for a retry of the same proposal — so Dough tells the two apart by the idempotency key it stamped, and never settles a proposal against a department it did not create. There is no second gate: a NetSuite department carries no approval field, so approving here creates it live immediately, and the panel says so. Whether child subsidiaries may use the department is left at NetSuite's default and is listed among the things this action does not decide.

  • Create a NetSuite location

    Dough can now propose creating a location in NetSuite — one of the three segments a OneWorld close is built on. Name the subsidiary however you have it (“Groupon, Inc.” or its internalId) and Dough resolves it against the live account when you propose, so a subsidiary that does not exist is refused before anyone approves. The name is checked against NetSuite's 60-character ceiling at the same moment, rather than being refused after approval. Location names are unique across the whole account, and NetSuite reports a name already in use with the same code it uses for a replay of Dough's own write — so Dough looks the record up before deciding: re-running your own proposal settles as already posted, and somebody else's location holding the name is refused with a sentence you can act on. Approving creates the location immediately: unlike a journal entry, a NetSuite location has no approval field, so there is no second gate and the approval panel says so. The panel also shows the scope Dough decides on your behalf — the named subsidiary only, not its children. Not offered yet: a parent location, a second subsidiary, an address or a timezone.

  • Create a NetSuite class

    Dough can now propose creating a class in NetSuite — one of the segments a OneWorld close is built on, and the first NetSuite action where nothing on the approval panel is an unchecked id. You give the class a name and say which subsidiary it belongs to, and optionally which existing class it sits under. Both of those are resolved against the live account when you propose, so a subsidiary or a parent that does not exist is refused before anyone approves it rather than failing afterwards. Because class names are not unique in NetSuite — six classes in one account we work with are called AE, each under a different parent — naming a parent ambiguously is refused with the candidates and their full paths, so you can say GPLS : AE or give the id instead. What the panel will not tell you is whether the new name is free: a class name only has to be unique among its siblings, and NetSuite decides that when the class posts, after the approval. Two things about a class Dough creates are worth knowing before approving one. It carries none of the custom fields your existing classes have — in particular the reporting-parent fields that decide where a class rolls up — so it can be perfectly usable and still not appear where the people reading your reports expect it, and the panel says so rather than leaving you to find out. And it is always shared with child subsidiaries, which is what every class in the accounts we have looked at does and what makes a class usable on a line posted in a child subsidiary; that is shown as a row on the panel rather than left implicit, because Dough sets it and your payload never mentioned it. Like the NetSuite vendor actions and unlike a NetSuite journal entry, there is no second gate: a class has no approval field, so approving here creates it live and it becomes selectable on transactions immediately.

Thursday, August 27, 2026

5 changes

Improvements

  • A first publish writes the manifest for you

    A first publish used to fail with a raw `ENOENT: no such file or directory, open 'my-skill/skill.yaml'` — a path, and no hint that the file was something you were supposed to write. Now `publish` writes it for you from the markdown that is already there: `SKILL.md` for a skill, `CLAUDE.md` for an agent. A skill's frontmatter already carries its name and description, so nothing is invented; an agent's come from the `# heading` and the first paragraph. The owner is filled in from whoever you are logged in as. It then STOPS without publishing, and names any field it could not fill. That pause is deliberate: a first publish permanently fixes the `name` the registry knows the item by and the `owner` who is the only account allowed to publish it afterwards, and published versions are immutable, so neither can be taken back. Agents always stop with `examples` outstanding — they are the prompts shown on the agent's registry page, and nothing in a CLAUDE.md implies them.

  • Publishing can no longer go backwards, or over someone else

    Two guards, one on each side. The server now refuses any version that is not strictly greater than an item's current latest, so a registry entry can no longer move backwards — previously `latestVersion` was overwritten on every publish with no comparison at all, and there was no version comparison anywhere in the codebase to make one with. And `publish` now refuses to run when the version in your `agent.yaml` or `skill.yaml` is BELOW the registry's latest. That means somebody published while your copy sat there, and publishing would have quietly produced a new latest built from work that never contained theirs — with version numbers that looked perfectly sequential. The error names both versions and tells you to sync first, and it is blunt about the cost, because sync is destructive in different ways: for an agent it overwrites every file the agent ships (files you added yourself survive), and for a skill it replaces the whole `~/.claude/skills/<name>/` folder, deleting anything you put there. Copy your work aside before you run it. A checkout that is AHEAD of the registry is not stale and still publishes, so retrying after a failed upload still works.

  • `publish --version` is rejected, not ignored

    `dough agent publish` and `dough skill publish` no longer accept `--version` — they say so instead of quietly doing something else. The flag never worked: publish packs the folder from disk, so what got published was whatever `agent.yaml` or `skill.yaml` already said, and the number you typed was discarded without a word. That also made it the one way the CLI could move a registry entry BACKWARDS — with a yaml at 0.0.5 and a published latest of 0.1.0, `publish --version 9.9.9` shipped 0.0.5 and set it as latest, so anyone syncing without a pin got the older bundle. Nothing you could previously do is gone, because the flag had no effect; a script passing it now gets a clear error rather than an unexpected version. The version is still derived the same way it always actually was: the registry's latest with the patch bumped, written back to the yaml, or the yaml's own number on a first publish.

  • `dough skill install` is now `dough skill sync`

    The command that was `dough skill install <name>` is now `dough skill sync <name>`, finishing the change that removed `dough agent install` alongside it. The behaviour is unchanged, and the new name describes it accurately: it has always REPLACED `~/.claude/skills/<name>/` wholesale rather than adding to it, so a version that drops a file drops it from your machine too, and anything you edited in that folder by hand is overwritten. `install` reads like a one-time step you can skip once it is done; `sync` is the thing you re-run. `dough skill install` no longer exists at all. Existing dough://install/skill/... links keep working unchanged. Separately, the Install button on a registry page had a copy-the-command fallback offering `dough agent install`, a command removed in the previous release; both surfaces now copy the command the button itself runs.

  • One way to get an agent, instead of three

    `dough agent install` and `dough agent upgrade` are gone. `dough agent run` opens an agent in a Claude Code session, and `dough agent sync` just fetches the files — between them they did everything the older two commands did, and one thing those never did: remove files an agent stopped shipping. Running `upgrade` left them behind indefinitely, so anyone still using it was getting a worse result than the command that replaced it. There is no install step to skip and no upgrade step to remember, because both commands overwrite the agent's folder whether or not it is already there — while leaving anything you created inside it untouched. Links of the form dough://install/agent/... still work and now fetch the same way. `dough skill install` is unchanged. (It followed in the next release, renamed to `dough skill sync` — see the entry above.)

Wednesday, August 26, 2026

2 changes

Fixes

  • An expired connection now says so

    When a credential cannot be resolved because your own connection to that provider expired, Dough now says so at the moment the agent needs it. The server had always reported it and the agent had always discarded the report, so the only symptom was the credential quietly missing — surfacing later as an unexplained "not set" from whatever tool needed it. The credentials that did resolve still arrive; the one that did not is named, along with where to reconnect it.

Improvements

  • Agents fetch their own credentials

    An agent's credentials no longer arrive in the session it runs in. Its scripts fetch them from the vault themselves, when they run. If you are used to checking with something like `env | grep TOKEN` inside a session, that now comes back empty even when everything is working — the credential goes straight to the script that asked for it and nowhere else. Three things follow. A token is no longer inherited by every command the agent runs, so it cannot be printed by accident. A credential file lasts only as long as the script using it, rather than the whole session. And a credential that cannot be resolved now says why at the moment it is needed — not signed in, a provider your admin has not configured, or your own connection to that provider having expired — instead of surfacing later as something that simply was not set. This also replaces a short-lived approach that attached credentials to every command an agent ran: it worked, but it meant approving every single command, because the approval system could no longer recognise commands you had already allowed. Agents that read their credentials from the environment need an update before they will work again.

Tuesday, August 25, 2026

6 changes

New features

  • Agents can update a NetSuite vendor

    A new proposable action, netsuite/update_vendor, changes a vendor that already exists — its name, company name, category, currency or payment terms. It is the first write Dough makes to a record it did not create, and two things follow from that. Only the fields you name change: a NetSuite update is partial, so everything else keeps its current value and there is no need to send current values back. And nothing resolves a vendor name to an internal id — there are hundreds of thousands of vendors, so the lookup that resolves accounts and subsidiaries does not apply — which means Dough cannot check that the id you gave is the vendor you meant. The approval panel says so and links straight to the record, and an edit that changes nothing is refused before anyone is asked to approve it. Like creating a vendor, there is no second gate: a NetSuite vendor has no approval field, so approving applies the change to the live AP master immediately. Dough never writes a vendor's external id on an update — that field is your own sync identity, and NetSuite would accept an overwrite silently.

  • Run an agent without hunting for its directory

    `dough agent run <name>` fetches the latest version of an agent and opens a Claude Code session already inside it, so you never have to know or type where the agent lives. Being in that directory is what loads the agent's instructions and skills and lets it receive its credentials — adding a directory to a session registers its skills but does not load its instructions, which is not the same thing. `dough agent sync <name>` does the fetch on its own when you only want the files. On Windows it launches the `claude.cmd` shim that npm installs, instead of reporting Claude Code as missing.

Fixes

  • Connect and reconnect your own accounts

    Agents can act with your personal Google account rather than a shared service credential. The page that manages those connections is now reachable for organizations with the vault entitlement — it previously existed but nobody could open it. That mattered most when a connection expired: Dough correctly stopped using the stale credential and told you to reconnect, but the page it named could not be opened by anyone outside Dough, so there was no way to fix it yourself. Where enabled, Connections appears in the sidebar and shows each provider as connected, not connected, or needing reconnection, with a one-click reconnect. The separate Connections page under the admin area is unchanged — that one holds credentials shared by the whole organization, this one holds only your own.

  • A NetSuite proposal whose post never landed can now settle

    When a post to NetSuite was interrupted, Dough asks NetSuite whether the write actually landed before deciding anything. That question had two possible answers and only one of them worked: "yes, here it is" was handled, and "no, there is nothing there" was raised as a failure instead of returned as an answer. A proposal in that state stayed in Posting, and the sweep that reclaims interrupted posts had nothing it could settle on — so it stayed there. The cause was NetSuite's own vocabulary: it reports a missing record with one code when you look it up by its internal id and a different one when you look it up by the reference Dough stamps on its own writes, and Dough only ever looks it up the second way. Both codes are now understood. The visible effect elsewhere is on vendors: proposing a vendor whose name another vendor already holds now says so in a sentence you can act on — use the existing vendor, or pick another name — where it used to surface NetSuite's "The specified key is invalid."

  • Downloaded agents are verified, and logout stops discarding your settings

    Three CLI fixes. Agent downloads are now checked against the fingerprint recorded when the agent was published, and refused when they do not match — skills were already verified this way, agents were not. `dough logout` no longer discards the agents directory you set with `dough init`, which used to send later installs to the wrong tree. And a command authenticating with DOUGH_API_TOKEN but no configured server now says so, instead of quietly sending your token to http://localhost:3000; set DOUGH_API_URL or run `dough login`.

Improvements

  • Updating an agent no longer leaves stale files, or eats your own

    An agent's folder is also its workspace — outputs, .env, and whatever the agent wrote last run sit beside its code. Updating now replaces exactly the files that came from the agent and removes the ones its new version dropped, leaving everything you created untouched. Previously an upgrade extracted over the top, so a file deleted between versions lingered indefinitely. The registry records what each published version contained, so this works on the first update even for agents installed before the change — and a file Dough could never have published, such as a .env or a spreadsheet, is never removed no matter what the registry says.

Sunday, August 23, 2026

5 changes

New features

  • Install the Dough plugin from the command line

    The Dough plugin for Claude Code can now be installed from the command line, not just updated. Before, `dough plugin refresh` on a machine that had never had the plugin refused and told you to add it inside Claude Code — which is the surface you are stuck on, and on Windows may not be drivable at all. `dough plugin install` now sets up everything Claude Code needs, including the marketplace directory the plugin is resolved through; without that directory Claude Code reports "failed to load" however correct the rest of the install is. `dough plugin refresh` installs too when nothing is there, so either name works. It needs no git, no credentials and no other tooling, so it runs from PowerShell. A first install registers the plugin in your settings.json and keeps a timestamped backup of the previous file; `--check` reports what would happen and writes nothing at all. There is also a new /dough:plugin_version command, which reports the version this session loaded alongside the one on disk — they differ until you restart, and telling those apart used to require reading the plugin store by hand.

  • /dough:refresh updates the Dough plugin, on any machine

    Claude Code users could get stuck on an old version of the Dough plugin with no way out. Uninstalling and reinstalling it in the desktop app did not help, because the app reinstalls from a local copy of the plugin repository that it has no way to advance — so it faithfully reproduced the same stale version. Running /dough:refresh now fixes it: the Dough CLI downloads the current plugin straight from its public repository and writes it into Claude Code's plugin store, needing no git, no credentials and no other tooling, which is what makes it work on Windows as well as macOS. /dough:status and /dough:propose refresh in passing too, and the same thing is available from a terminal as `dough plugin refresh` — with `--check` to see whether an update exists without installing it. One catch worth knowing: a refresh never applies to the session that requested it, so Claude Code has to be restarted before the newer plugin is actually in effect, and the command says so whenever it changes anything.

Improvements

  • NetSuite proposals resolve in seconds, and the approver sees the names

    Two fixes to NetSuite reference resolution, both found by running a real proposal. Raising an entry that named an account used to take over a minute and could time out before anything was created, because Dough fetched the whole chart of accounts — four thousand of them — to find one row. It now looks up the account directly and the same proposal resolves in about three seconds. Separately, the approval page showed internal ids where Dough already knew the names: a line now reads "Expenses (6000)" beside its id rather than just "58", the subsidiary and each department, class and location are named, and the one reference Dough does not resolve — the customer or vendor a line is tagged to — still shows as a bare id on purpose, so it is visible that nothing checked it.

  • NetSuite entries can name an account instead of its internal id

    A NetSuite journal entry proposal no longer has to carry NetSuite internal ids. An account can be named by the number an accountant reads off a report (`{ "number": "21040" }`), by its name, or by its full path; the subsidiary, department, class and location can be named too. Dough resolves them against the live account when the proposal is raised and re-checks before anyone approves, so an account that does not exist is refused up front rather than by NetSuite after approval — and a name that matches more than one record comes back with the candidates and their full paths instead of a silent guess. Internal ids still work everywhere. One field is deliberately not resolved: the customer or vendor a line is tagged to, which stays an internal id and says so.

  • NetSuite journal entries can carry a reversal date

    A NetSuite journal entry proposal can now set reversalDate, the date NetSuite automatically reverses the entry. That is how a month-end accrual is normally written: one entry, booked in the period it belongs to, unwinding by itself on the first of the next — until now an agent had to propose the reversal as a second entry, and a person had to remember to approve it. The date must be after the entry's own date, and it appears on its own line of the approval panel rather than folded in with the identifiers: a reversing entry writes a second, opposite set of postings that nobody approves separately, so an approver who cannot see it is authorising one entry and getting two.

Saturday, August 22, 2026

3 changes

New features

  • NetSuite entries can carry departments, classes, locations and a memo

    A NetSuite journal entry can now carry the things a real month-end close needs. Each line takes an entity, department, class and location — the customer or vendor it is tagged to, and the three classification dimensions a OneWorld subsidiary reports on — and the entry itself takes a memo, so what Dough writes is explained on your own record rather than appearing there unlabelled. All of them are optional and all are named by NetSuite internal ID; nothing is resolved for you, so a wrong id posts into the wrong report without complaint, and the approval page shows every one on the line it belongs to so it can be checked before anyone approves. One rename: the payload's `currency` is now `subsidiaryCurrency`. It was never sent to NetSuite — an entry takes its currency from its subsidiary — and the old name read as though setting it changed what posts. Sending the old name now returns an error that names the new one.

Fixes

  • A NetSuite proposal's receipt now names the account it writes to

    When an agent raised a proposal against a NetSuite account, the reply came back without naming the connected account — the field an agent reads to confirm WHICH client's books it just wrote to was blank. The proposal itself was bound correctly the whole time, and the queue and the proposal page both showed the right account; only the agent's own receipt was missing it. It is now filled in for NetSuite exactly as it always was for QuickBooks. Separately, proposals.propose now says out loud that its list of available actions is fixed at the moment your session connects: if proposals.actions reports an action that propose does not describe, reconnecting is what picks it up.

Improvements

  • Connecting a NetSuite account fails faster, and explains a collision

    Two things are better when an admin connects a NetSuite account. Dough now gives up on an unresponsive account after fifteen seconds rather than a minute — a successful check takes about four, so a long wait almost always means the account id is wrong, and waiting a full minute to be told so just invites reloading the page and re-pasting the credential. And if two admins happen to connect the same NetSuite account at the same moment, the one who loses the race is now told exactly that, with the suggestion to reload and look for it, instead of being told to try again — which could never have worked, since retrying just finds the connection the other admin created.

Friday, August 21, 2026

1 change

New features

  • Post journal entries to NetSuite

    The Action Gateway can now write to NetSuite as well as QuickBooks. Connect a NetSuite account under Connections, then build a gateway for it: the wizard's first step is a real product picker now, and picking NetSuite lists the actions available for it. The first one is a journal entry — a balanced set of debit and credit lines against one subsidiary, with accounts named by their NetSuite internalId. An approver sees the lines, the totals and whether the entry balances before deciding, and once approved the posted entry links straight into NetSuite. Two things are worth knowing before you use it. Dough creates the entry UNAPPROVED: it does not reach the general ledger until someone inside NetSuite releases it, so approving here authorises the entry to be prepared, not posted. And unlike the QuickBooks equivalent, nothing is resolved for you at propose time — an account or subsidiary id that does not exist is refused by NetSuite when it posts, after approval, rather than when the proposal is raised. Re-posting is safe: every entry carries the proposal's id, and NetSuite refuses a second entry bearing one it has already seen, so a retry can never duplicate a write.

Thursday, August 20, 2026

1 change

Improvements

  • Drafts have their own tab on the Dashboards list

    The Dashboards list now has two tabs: Published, which is what it always showed and what the rest of your workspace reads, and Draft, which lists the dashboards nobody has published yet. Until now a draft was reachable only by its link — if you closed the tab and lost the URL, the only way back was to ask Claude for it. Drafts are still kept clear of the published list, so a work in progress is never mistaken for the team's agreed view; they are simply findable now. The page opens on Published, /dashboards?tab=draft opens straight on drafts, and each tab shows how many dashboards are in it. Publishing a dashboard from its page moves it across; unpublishing moves it back.

Wednesday, August 19, 2026

3 changes

New features

  • More ways to chart a dashboard widget

    Dashboard bar and line widgets can do more now. A bar widget can group several series side by side or stack them, and a combo widget can put bars and a line together on two axes, so a series measured in dollars and one measured in a count can share a chart without one flattening the other. A widget can mark one or more reference lines across the plot for a target or a budget, and a stacked area can be shown as a 100% share of the total to compare mix over time instead of absolute size. A waterfall widget breaks a total down into the pieces that built it, with gains and losses shaded automatically. A banded-range widget shades the space between a low and a high series, useful for a forecast range or a prior year's high and low. Stat tiles — the single-number KPI widgets — can now carry a small sparkline under the headline value and its delta, so the recent trend is visible without opening the full chart.

Improvements

  • An upload that names a source file now has to carry it

    A table's version history could show a row saying it came from "July 2026 Inventory EOM.xlsx" with no such file to download — the name was only ever text someone typed, and attaching the real file was optional. Now, when an upload describes its source as a file (.xls, .xlsx, .xlsm, .xlsb, .xltx, .xltm, .tsv, .ods, .numbers, .pdf or .docx), that file is required: the upload is refused until the file itself comes with it, and it then appears as a download beside the row in version history. Claude can attach it directly. The web upload form cannot — it takes a CSV and has no way to send a second file — so if you upload there, describe the spreadsheet you converted rather than naming its file. Naming a .csv is always fine: Dough already keeps every CSV you upload, exactly as you sent it. The check reads the description literally, so a file you merely cited as background counts as one you named; drop the name if the rows did not come from it. Versions uploaded before this change are unaffected, and their original files cannot be recovered.

  • Dashboard charts move to a six-tone colour ramp

    Dashboard line and bar charts used to pick series colours from a four-tone ramp; two of those tones sat too close together to tell apart at a glance. They now draw from six tones (accent, bronze, steel, ochre, sky, sand), each checked to stay legible from its neighbours under normal and colour-vision-deficient vision. Every dashboard built before this change has been migrated onto the new names automatically, so its colours may look slightly different: the old "muted" tone in particular now renders as bronze rather than steel, so it stays distinct from any series that was already steel. A bar chart's tail row also moves off the old pale-accent tone onto the same neutral ink used elsewhere for non-series marks.

Tuesday, August 18, 2026

1 change

New features

  • Dashboard refresh runs in the background

    Refreshing a dashboard used to run every widget's query in the click, so the page froze until it finished. It now queues as a background job and returns immediately: a banner tracks the refresh while it runs, and the previous figures stay readable the whole time. Clicking Regenerate while a refresh is running attaches you to the same one instead of starting a second. If a refresh fails, the previous figures stand and the banner carries the error; if it stops reporting back, the banner says so rather than spinning forever. Over MCP, dashboards.refresh behaves as before and returns the same result. dashboards.get now also reports the latest refresh's status, so an agent building on dashboards can poll it to see a refresh land.

Monday, August 17, 2026

4 changes

New features

  • Dashboards you can open and share

    A dashboard Claude builds for you now has a page. Open it at its own URL and paste that link to anyone in your workspace — they see the same figures you do. New dashboards start as drafts: reachable by link and marked as such, but kept off the Dashboards list until you publish them, so you can get a second opinion before the whole team sees it. Controls declared on a dashboard (a date range, say) appear above the widgets, and Regenerate re-runs every query behind it. Because one set of figures is shared by everyone, changing a control and regenerating asks you to confirm first. The page is deliberate about what it does not know. A widget whose query returned no rows says so rather than showing a zero; one whose result is missing a column names the column; one whose saved query was deleted names the query instead of quietly showing you last week's number. Table totals recompute ratios from their parts, so a margin total is the margin of the totals, not the average of the rows — a different, wrong number. Alongside how fresh the figures are, the page shows how fresh the underlying data was, because those are two different questions. Deleting a saved query now warns you which dashboards read it, by name, before you go ahead.

  • Claude can now build dashboards

    Ask Claude to put together a dashboard and it can now do it directly: it finds or writes the saved queries that answer your question, picks a stat, line, bar, or table for each one, and saves the result as a named dashboard. A dashboard is a spec, not generated code — every widget names a saved query it reads, so what it shows is auditable and re-runnable, never a one-off script. Widgets can share controls (a date range, a region) that bind by name to every query that declares a matching parameter, so changing one control updates every widget built on it, without the queries silently disagreeing about what value they ran with. Refreshing re-runs the underlying queries and stores the results as a snapshot, so a bad or denied query only costs that one widget, not the whole dashboard, and a widget reading a table your role isn't allowed to see is refused the same way any other query is. This ships the saving and refreshing tools; an actual page to view a dashboard on is coming next.

  • Saved queries keep their history

    Editing a saved query used to overwrite it. The row was its own only copy, so the SQL you replaced was simply gone — no way to see what a query used to compute, or who changed it. Saved queries now keep a version history, the way calculated tables do. Every save that actually changes something records an entry with the SQL, the name, the description, and who saved it, and each entry is tagged with what it changed — SQL, name, description — so you can find the edit you are looking for without reading every version. Saves made by Claude through the queries.save tool are recorded too, attributed to whoever was calling. History is read-only: you copy an old version's SQL back into the editor yourself, so reverting a query your whole workspace shares is always a deliberate save rather than one click. Queries that existed before this show their current state as v1 and start accumulating history from their next save. The query page was rebuilt to match a table's detail page while we were there: a header with the name and who last touched it, an editable context box for the name and description, and the SQL and the history each on their own tab.

  • Retire a class

    Dough can now propose retiring a class. QuickBooks has no delete for one, so this is the only way to take a class out of use — and it is not a delete: the class keeps its history, every transaction already tagged with it stays tagged, and it keeps its name, which stays unavailable to a new class among the same siblings. Retiring something to free up its name does not work, and the approval panel says so rather than letting anyone find out afterwards. The class is resolved against the company's live list when you propose, including classes that are already inactive — so re-proposing one you have already retired is answered with “already inactive” rather than “no such class”, and a class QuickBooks renamed on its way out is still found under the name you know it by. A class that is already inactive is refused rather than posted again. What the panel will not tell you is what happens to any classes beneath the one being retired: QuickBooks may refuse the write, or retire the whole subtree along with it, and Dough has not verified which. So it shows the count instead — every active class beneath this one at any depth, not just its direct children — and states both possibilities plainly rather than implying it knows. Retiring a class writes nothing else: the nesting is preserved, so a retired class does not quietly become a top-level one and regroup every report that splits by class.

Sunday, August 16, 2026

1 change

Fixes

  • Dropdowns now name the thing you picked

    "Copy policy" on the Connections page asks which company to copy a set of gateways onto — approvers and all — and once you picked one, the control stopped saying the company's name and showed an internal id instead. The list said "Meridian US"; the closed control said a string of letters and digits that appears nowhere else in Dough. Worse, the list opened directly on top of the control rather than below it, so with the two or three companies an organization actually has there was nothing that looked like a menu — just a box whose text changed under the cursor, apparently cycling between a name and an id. Between the two it was genuinely unclear what was about to be written to. The list now drops below the control, and the control names the company you chose. The same fix reaches the role dropdown in the admin console, which had been reading back the internal role name — "sensitive_write" — in place of the description it offered when you opened it.

Saturday, August 15, 2026

4 changes

New features

  • Refund a customer

    Dough can now propose a refund receipt — money paid back to a customer, as opposed to a credit memo, which only reduces what they owe. The difference is where the money comes from, so that is what Dough checks. You name the account the refund is paid out of, and Dough confirms when you propose that QuickBooks will accept it — it must be a bank or other current asset account — rather than letting the write be refused after somebody has already approved it. Each line names a product or service from your item list and the customer comes from your customer list, both resolved when the proposal is raised, so a name that does not exist is refused up front instead of failing later. Amounts are written positive: a refund receipt already pays money out, so a negative line would be a charge hidden inside a refund, and Dough refuses it and says an invoice is the instrument for that. The refund number your customer sees is yours to set or to leave to QuickBooks — Dough never puts its own tracking token there. The same limit the other sales forms carry is stated just as plainly here: sales tax is not included in the figure shown. QuickBooks computes tax itself after the write, so the amount that actually posts may differ from the sum of the lines, and the panel calls the figure a line total rather than a total because that is what it is. The refund date is required — QuickBooks would default it to today, but Dough uses the date to recognise its own work if a write fails without an answer, which is what stops a lost response refunding the same customer twice. Item lines only for now: a discount or subtotal line cannot be expressed yet.

Improvements

  • A quieter proposal page

    The page an approver reads before authorizing a change had grown a layer of text explaining itself rather than the change. The approval flow carried a second line under every stage — "raised by an agent, unattended", "Open queue · any permitted approver except the proposer", "Posts to QuickBooks · retry-safe, cannot double-post" — which read identically on every proposal and said nothing about the one in front of you. Those are gone. What is specific to a proposal still shows: the reviewer's and approver's notes, why it was rejected, and the error if a write did not land. The "In-force policy · stamped at propose" panel at the foot of the approval flow is gone too, since the policy and who it waits on are already stated at the top of the page. The gate checks panel no longer lists what it does not cover, and its heading now says what it actually tested: "Gate checks — payload valid" rather than "all passing". Those checks read only the change itself, so a green panel means the entry is well-formed — not that the accounting period is open or that a name is still free in QuickBooks. A failed write also now reads as failed on the approval flow itself, instead of showing a green "Executed" with the failure noted a row below.

  • Open the record a proposal wrote, whatever kind it was

    A posted proposal has always recorded exactly which record it created in QuickBooks, but only journal entries offered a link to go and see it. Everything else — a customer, a vendor, an invoice, an estimate, a sales receipt, a credit memo, a refund receipt, a transfer — showed "No link available for this record", so confirming a write meant finding it in QuickBooks by hand. Those all link straight to the record now: from the proposal's page, from the queue, and in what an assistant reads back. Records QuickBooks has no address we can send you to — accounts, products and services, classes, locations, payment methods and employees — still say so plainly rather than sending you somewhere that is not the record we wrote.

  • Query results now say how fresh the data behind them is

    When an assistant queries your data lake it gets rows back, and until now nothing in that answer said when those rows last arrived. A figure pulled from a source that stopped syncing three weeks ago looked exactly like one from this morning, and would be quoted with the same confidence. Every query result now opens with the list of your connected sources and when each one last finished importing, so the assistant can tell you a number is three weeks old instead of presenting it as today's. Paging through a large result repeats it, so the context does not get lost on page four. A source that has never finished an import is reported as unknown rather than guessed at, and if the freshness cannot be established at all the rows still come back exactly as before.

Friday, August 14, 2026

14 changes

New features

  • Connect more than one QuickBooks company

    An organization can now keep several QuickBooks companies connected at once, instead of one. Connecting a second company no longer replaces the first: each is listed on the Connections page with its own name, and you can rename them, choose which one is the default, and reconnect or disconnect each independently. The name is what an assistant uses to say where a change goes — ask it to propose against “Meridian US” and that is the ledger it writes to. Leave the company out and it uses your default; if you have several connected companies and no default, it asks rather than guessing, and lists the companies to choose from. Approvals are per company, deliberately: a gateway governs one action on one company file, so each client's controller approves that client's ledger and nobody else's. That does mean configuring an action for one company does not configure it for another — the gateway wizard has a step for picking the company, and “Copy policy” carries a company's whole set of gateways, approvers included, onto another. Approvers now see which company a change lands in before they approve it, on both the queue and the proposal itself; with one connected company that was never in doubt, and with several it is half of what is being authorized. Disconnecting keeps the connection listed, greyed out, rather than removing it. That is what stops a company name being reused later — a saved instruction naming “Meridian US” can never come to mean a different set of books — and it keeps the record of every change already made through it intact. Reconnecting the same company revives it, with its name and its gateways.

  • Rename a class, or move it under a different one

    Classes are how a QuickBooks file splits its reporting — by department, by site, by programme — and Dough could read them but never change one. You can now propose editing a class: rename it, or move it under a different parent so the numbers group where they belong. Both are shown as a before-and-after, so an approver sees what it says today rather than only what it would become. Two things the panel is explicit about, because neither is obvious from a one-line diff. Moving a class takes every class beneath it along, and re-groups every report that splits by class. And moving one back to the TOP level is refused rather than attempted: QuickBooks may quietly ignore a cleared parent and report success anyway, and reporting a change that did not happen is worse than declining it. Name the class whichever way you have it — "Events" or the full path "Marketing:Events" — and a name that matches nothing is refused with the near misses while you can still fix it, not after someone has approved it. There is no way to CREATE a class through Dough, and that is a limitation with a reason: QuickBooks gives a class no free-text field, so Dough cannot mark one it created and could not tell its own retry apart from a duplicate.

  • Edit a department — what QuickBooks usually calls a Location

    If your QuickBooks file tracks locations, this is the endpoint for them: the API calls the entity a Department, and most companies see it on screen as a "Location" — or as a Division, Property, Store or Territory, because the label is a setting each company picks. Dough cannot tell which one your file uses, so it says so plainly rather than guessing. You can now propose renaming one, or moving it under a different parent so reports group it where it belongs, and the approval panel shows the change as a before and after rather than only the new value. Name the department whichever way you have it — "Portland" or the full path "West:Portland" — and a name that matches nothing is refused with the near misses while you can still fix it, not after someone has approved it. Two things it is careful about. Moving one takes every department beneath it along and re-groups every report that splits by location, so the panel says so. And moving one back to the TOP level is refused rather than attempted: QuickBooks may quietly ignore a cleared parent and report success anyway, and reporting a change that did not happen is worse than declining it. The physical address is not settable here and is not disturbed — whatever QuickBooks holds is sent back untouched. There is no way to CREATE a department through Dough, for the same reason there is none for a class: QuickBooks gives it no field Dough can mark, so it could not tell its own retry apart from a duplicate.

  • Retire a product or service

    QuickBooks has no delete for an item, only retirement, and Dough could add and edit one but never take it out of use. You can now propose deactivating a product or service, named by its name or by its full path ("Consulting:Onsite"). The approval panel does not show a before-and-after, because the only field changing is one nobody names — it shows what the item IS instead: its type, its path, its default rate and its description, which is what someone needs in order to judge whether this is the right record. Four things it is careful about. Retiring does not free up the name: a retired item keeps it, so this is not the way to fix a typo — edit the item instead. Anything that still sells it, such as a recurring invoice or a saved estimate, will start failing once it is retired, and QuickBooks does not report those in advance, so the panel says plainly that Dough has not checked. An item that is already inactive is refused with "already inactive" rather than posted a second time. And Inventory, Bundle and Category items are refused outright, for the same reason editing one is: the write replaces the whole record, so it would echo back quantities and inventory accounts whose behaviour Dough has not verified against a real company.

  • Rename a payment method

    The payment method is the entry someone picks when recording how a payment came in — Visa, Cash, Cheque — and a badly-named one shows up on every report that splits by it. You can now propose renaming one, and the approval panel shows it as a before and after rather than only the new name. This endpoint renames and does nothing else, which is the entity rather than a shortcut: QuickBooks gives a payment method a name, an active flag, and a type. The TYPE is refused rather than quietly ignored — it decides whether QuickBooks treats payments recorded against the method as credit-card payments, and what changing it does to payments already recorded has never been verified, so the refusal names the workaround instead. One limitation worth knowing before you hit it: Dough refuses names longer than 15 characters. That ceiling is Dough's rather than QuickBooks' — Intuit's published model has been read as 15 and as 31, neither reading has been checked against a real company, and the lower is used deliberately, because being told the limit now is fixable in one step while being refused by QuickBooks after someone has approved the change is not. If a name QuickBooks would have accepted is refused, that is why. There is no way to CREATE a payment method through Dough: QuickBooks gives the entity no field Dough can mark, so it could not tell its own retry apart from a duplicate.

  • Move money between your own accounts

    You can now propose a transfer: money out of one of the company's accounts and into another — bank to bank, or bank to a credit card to pay it down. The approval panel shows it as a direction rather than a list of fields, because what somebody is approving is that THIS much leaves THAT account and lands in the other one, and getting the two the wrong way round is the mistake worth catching. Name each account however you have it — by name, by number, or by id — and Dough resolves both against the live chart of accounts when you propose, checks that each one is a type QuickBooks will actually transfer between, and refuses a transfer whose two ends are the same account. All of that happens before anyone approves, rather than as a rejection afterwards. Two things it is deliberate about. The date is required, even though QuickBooks would fill it in for you: a transfer carries no document number, so if a post fails without an answer Dough finds the transfer again by its date — and a date QuickBooks chose is one that search cannot use. Stating it is what stops a lost response becoming a second transfer. And the panel says plainly what it did not check: Dough does not read account balances, so it cannot tell you whether the money is there.

  • Correct an employee's details

    Dough can now propose editing an employee: rename them, fix the name a cheque is made payable to, or correct their email, phone and employee number. It is shown as a before-and-after, so an approver sees what the record says today rather than only what it would become, and a change that would alter nothing is refused before it costs anyone a decision. Two limits are deliberate and the panel states both. The personal data — social security number, date of birth, gender — is NOT settable here: a proposal is stored as a JSON payload and rendered on an approval screen, and neither was built to hold any of it, so this corrects who someone is on the record and never what payroll needs in order to pay them. Nor are the pay and employment fields, because a bill rate silently changes what customers are invoiced for every later time entry and a release date is a termination rather than a correction. The employee number is flagged where it is shown, because it is often the key tying this record to an HR or payroll system outside QuickBooks — changing it can break a join Dough cannot see. And if the company runs QuickBooks Online Payroll the write may be refused outright; that is said up front rather than discovered after approval. There is no way to CREATE an employee through Dough, for the reason there is no way to create a vendor: QuickBooks gives an employee no free-text field, so Dough cannot mark one it created and could not tell its own retry apart from a duplicate.

  • Bill a customer

    Dough can now propose an invoice: who is being billed, what for, and how much. Each line names a product or service from your item list and a customer from your customer list, both resolved when the proposal is raised — so a name that does not exist is refused before anyone approves it, rather than failing after. The approval panel shows the lines as a table with the customer, the date and any due date, and a line description is marked as the text your customer will read, separately from the internal memo that stays inside QuickBooks. One limit is stated plainly on the panel rather than buried: sales tax is not included in the figure shown. QuickBooks computes tax itself after the write, so the total that posts may be higher than the sum of the lines. The panel says so, and calls the figure a line total rather than a total, because that is what it is. The invoice date is required — QuickBooks would default it to today, but Dough uses the date to recognise its own work if a write fails without an answer, which is what stops a lost response becoming a second bill to your customer. Item lines only for now: a discount or subtotal line cannot be expressed yet.

  • Credit a customer

    Dough can now propose a credit memo: what is being credited back to a customer, and how much. Each line names a product or service and an amount, written as a positive figure — the credit memo is itself the reduction, so a negative line would charge the customer more and is refused, naming an invoice as the right instrument instead. It is the invoice's approval panel with one row absent, because a credit is never owed: a credit memo has no due date and none is shown. Three things the panel says plainly rather than leaving an approver to assume. It does not move money — it reduces what the customer owes, so a customer who has already paid and expects cash back is left with an unused credit. It names no invoice, but your company's QuickBooks may be set to apply credits automatically, in which case the balance of open invoices changes the moment it posts and Dough can neither read that setting nor report which invoices were touched. And the sales tax being reversed is QuickBooks' to compute after the write, so the figure shown is the sum of the lines and the posted total may be higher — the same open question the invoice shipped with. A lost response cannot credit anyone twice: Dough stamps its own tracking line into the internal memo and looks for it before writing, which is why the credit memo's date is required rather than left to QuickBooks.

  • Record a paid sale

    Dough can now propose a sales receipt — a sale the customer has already paid for, as opposed to an invoice they still owe. It takes the same shape as an invoice: each line names a product or service from your item list, the customer comes from your customer list, and both are resolved when the proposal is raised, so a name that does not exist is refused before anyone approves it rather than failing after. There is no due date, because nothing falls due. What a receipt adds is where the money lands. You can name the deposit account, and Dough checks when you propose that QuickBooks will accept it — it must be a bank or other current asset account — rather than letting the write be refused after approval. If you name none, the approval panel says so in words instead of leaving the row blank: QuickBooks posts to the company default, usually Undeposited Funds, and that is a real destination nobody chose rather than a non-choice. You can also record how the customer paid. The same limit an invoice carries is stated just as plainly here: sales tax is not included in the figure shown. QuickBooks computes tax itself after the write, so the total that posts may be higher than the sum of the lines, and the panel calls the figure a line total rather than a total because that is what it is. The receipt date is required — QuickBooks would default it to today, but Dough uses the date to recognise its own work if a write fails without an answer, which is what stops a lost response recording the same payment twice. Item lines only for now: a discount or subtotal line cannot be expressed yet.

  • Quote a customer

    Dough can now propose an estimate: what you are quoting a customer, and for how much. It works like the invoice — each line names a product or service from your item list, the customer comes from your customer list, and both are resolved when the proposal is raised, so a name that does not exist is refused before anyone approves it rather than failing afterwards. The approval panel shows the lines as a table with the customer, the date, an expiration date if you set one, and the internal memo kept separate from the line descriptions your customer will read. Two things are particular to a quote. An estimate never touches your books — it is a price, not a posting — and the panel says so, but it also says why that is not the same as harmless: the figure goes to a customer as a commitment, so a number that moves after approval is a price nobody authorised. Which is the second thing: sales tax is not included in the figure shown. QuickBooks computes tax itself after the write, so the total quoted may be higher than the sum of the lines, and the panel calls the figure a line total rather than a total because that is what it is. You can set the status — Pending, Accepted, Closed or Rejected — and it is shown in bold on the approval panel when you do, because Accepted records that the customer agreed to a price they may never have seen. Leave it out and QuickBooks starts the quote as Pending, which is what a new one normally is. The estimate date is required: QuickBooks would default it to today, but Dough uses the date to recognise its own work if a write fails without an answer, which is what stops a lost response becoming a second quote to your customer. Item lines only for now — a discount or subtotal line cannot be expressed yet.

Fixes

  • A misspelled field in a proposed change is refused, not silently ignored

    Ask for a change and name one of the fields slightly wrong — an underscore instead of a capital, a name borrowed from a different kind of record — and that part of the request was quietly thrown away. The rest of the change went through, the proposal reached an approver describing something smaller than what was asked for, and nothing anywhere recorded the difference: not the confirmation, not the summary on the approval screen, not the audit trail. Someone could approve a rename and a new phone number and have only the phone number happen. Dough now refuses a key it does not recognise at the moment the change is raised, names the key, and writes nothing — so the mistake costs one correction instead of an approval spent on the wrong change. The case that mattered most is a journal entry's date: misspell it and the entry used to post dated today, landing in the wrong period on books somebody had already signed off. Everything documented still works, including the shorthand ways to name an account, a customer or a vendor by id, and a field explicitly set to nothing still means "leave this alone" rather than reading as a mistake.

Improvements

  • Each connected source now says when it last synced

    The Integrations page told you how many rows a source has in the data lake, but not when that number was last refreshed — so a count that had not moved in a week looked exactly like one that had just landed, and the only way to tell was to sync again and watch. Each connected source now reads "Synced 3 h ago · 107 rows", using the finish time of its last completed run, with the exact timestamp on hover. A source that is importing right now still shows its live progress instead, and one whose last run failed still says so.

  • A change that needs no approval is written straight away

    Some actions are set up to need neither a review nor an approval — the gateway already says who authorized them, so a change of that kind is approved the moment it is raised. It was still waiting up to two minutes to actually reach QuickBooks, because the only thing that wrote it was a job that runs every other minute. Now it is queued the instant it is raised, so it lands in seconds. The difference shows up most when an assistant raises a change and then checks on it: for that couple of minutes it saw an approved change that had not been written, which looks exactly like a change that failed. Nothing about safety moved — a change that needs a person still waits for that person, and the every-two-minute job remains the backstop, so a change is still written even if the fast path never runs.

Thursday, August 13, 2026

15 changes

New features

  • Agents can read your chart of accounts before proposing an entry

    An agent building a journal entry had no way to see which accounts your QuickBooks company actually has, so it guessed a name and hoped — and where the guess was not close, the only way forward was asking you to type the name in. Dough now lists the accounts, filtered by type or by a search, read live from the connected company. When a name does still miss, the suggestions that come back are much better at finding what you meant: they now work whether your guess was longer or shorter than the real name, and a plural no longer hides a match. An account number you pass against a company that does not use account numbers says so, rather than implying you had the wrong number.

  • Agents can propose an edit to an existing QuickBooks account

    Dough could add accounts to your chart of accounts and never correct one, which stopped being theoretical quickly — the first account it created was filed under a detail type QuickBooks chose, and fixing it meant opening QuickBooks by hand. An agent can now propose an edit: rename an account, renumber it, fix its detail type or description, or move it under a different parent. Fields you do not mention are left exactly as they are. The approval screen shows a before and after for each field that changes, so you can tell a correction from a no-op, and an edit that would change nothing is refused rather than sent for approval. Two things are deliberately not editable: an account's type and its currency, because QuickBooks refuses to change them once an account has been used — refusing up front beats approving something that fails afterwards. Moving an account back to the top level is not supported yet.

  • Journal entries can post to Accounts Receivable and Accounts Payable

    An entry touching Accounts Receivable or Accounts Payable could not be proposed at all. QuickBooks requires a customer on any line hitting AR and a vendor on any line hitting AP — it refuses the whole entry otherwise — and there was no way to say who. A line can now name one, the same way it names an account: by name or by id, resolved against the connected company when you propose, so a customer who does not exist is refused before anyone approves rather than after. The requirement is checked at the same moment: propose an accrual against AR without naming the customer and you are told so immediately, with the account type quoted back, instead of finding out from a failed post once it has already been authorised. Naming a vendor where a customer belongs gets its own answer rather than being lumped in with naming nobody. The approval panel shows who each line is tagged to and whether they are a customer or a vendor, because those are different records that can share a name.

  • Retire an account you should not have created

    Dough could add an account to your chart of accounts and had no way to take one back out. That mattered most for the mistake it cannot otherwise fix: an account created with the wrong type, which QuickBooks will not let anyone change once the account has been used. The answer is to create the right one and retire the wrong one, and only the first half was possible. You can now propose retiring an account, with the approval panel showing what that account currently is — its type, detail type, number and description — because unlike an edit there is no before-and-after to read, and what matters is judging what stops working. Three things it is careful about: retiring an account does not delete it, and QuickBooks renames it to end in "(deleted)" rather than removing it; proposing to retire an account that is already inactive tells you exactly that, instead of claiming no such account exists, and it still finds the account under the name you know rather than the renamed one; and an account with active sub-accounts is refused when you raise the proposal, because QuickBooks will not retire one — the sub-accounts have to be retired first, and finding that out after someone approved it is too late.

  • Add a customer

    Dough could write to your chart of accounts but not to your customer list, so an agent that needed a customer — to raise an invoice, or to put a name on an Accounts Receivable line — had to stop and ask someone to add one by hand. You can now propose a new customer: a name, and optionally a company name, contact details and a note. The name is what QuickBooks uses to identify the customer everywhere else and has to be unique across the whole company, which the approval panel says out loud, because QuickBooks only refuses a duplicate when the write actually posts. Two things it does not do yet, and says so rather than quietly dropping them: it cannot set an address, and it cannot create a sub-customer (a job).

  • Correct a customer's details

    Adding a customer was possible; fixing one was not, so a typo in a name or an email that had stopped working meant leaving Dough and editing it in QuickBooks. You can now propose an edit to an existing customer — rename them, correct the company name, or update the contact details — and the approval panel shows it as a before and after, because the new value on its own does not tell an approver whether it is a correction or a no-op. Set only what you want to change; anything you leave out is left exactly as it is. Four things it is careful about: a proposal that would change nothing is refused when it is raised, rather than costing someone a decision about a write with no effect; the currency is refused with the reason, because QuickBooks will not change it once a customer has transactions; if Dough created the customer, the tracking line it wrote survives an edit that was not about it, and the panel says so when you do replace it; and renaming is not checked against QuickBooks’ shared customer, vendor and employee name list before it posts, which the panel states rather than implying a check nobody ran.

  • Retire a customer you no longer bill

    Dough could add a customer and correct one, and had no way to take one out of use — so a client you stopped billing a year ago stayed in every picker and every report as though they were current. You can now propose retiring a customer. QuickBooks has no delete, so this makes them inactive: their history is untouched and their name stays taken, which means retiring someone to free up their name does not work — the approval panel says so rather than letting anyone find out afterwards. Because there is no before-and-after to read on a retirement, the panel shows what the customer currently IS, led by what they still owe, which is the one number that changes the decision — and where sub-customers carry a balance of their own, the panel shows the total beneath them as well as the customer's own, because a parent whose jobs owe the money reads zero on their own record. Two more things it is careful about: proposing to retire a customer who is already inactive tells you exactly that instead of claiming no such customer exists, and it still finds them under the name you know; and when sub-customers (“jobs”) sit beneath the customer, the panel shows how many and states plainly that Dough has not verified whether QuickBooks refuses the write or retires them too — rather than implying a check that has not been made.

  • Correct a vendor's details

    Dough could edit a customer but not a vendor, so a supplier whose legal name changed after an acquisition — or whose cheques kept coming back — had to be fixed by hand in QuickBooks. You can now propose an edit to an existing vendor: rename them, correct the company name or contact details, fix the name a cheque is made payable to, or update the account number the vendor uses to identify you. The approval panel shows it as a before and after, because the new value on its own does not tell an approver whether it is a correction or a no-op, and it names each field in English rather than in payload keys — “Our account number”, not “acctNum”, because that one is the vendor’s number for you and not one from your chart of accounts. Set only what you want to change; anything you leave out is left exactly as it is, and a blank is refused rather than quietly erasing the field. Two limits stated plainly rather than discovered: the currency is refused with the reason, because QuickBooks will not change it once a vendor has transactions; and renaming is not checked against QuickBooks’ shared customer, vendor and employee name list before it posts, which the panel says rather than implying a check nobody ran. There is still no way to ADD a vendor — QuickBooks gives a vendor no free-text field, so Dough cannot mark one it created and could not tell its own retry apart from a duplicate.

  • Retire a supplier you no longer buy from

    Dough could correct a vendor but not take one out of use, so a supplier you stopped ordering from a year ago stayed in every picker and every report as though they were current. You can now propose retiring a vendor. QuickBooks has no delete, so this makes them inactive: their history is untouched and their name stays taken, which means retiring someone to free up their name does not work — the approval panel says so rather than letting anyone find out afterwards. Because there is no before-and-after to read on a retirement, the panel shows what the vendor currently is, led by what you still OWE them — labelled that way round on purpose, because a vendor balance is money going out, not coming in, and retiring the record does not settle or cancel unpaid bills. It also shows the name their cheques are made out to and the account number they file you under, which are the two fastest ways to confirm it is the right supplier. Proposing to retire a vendor who is already inactive tells you exactly that instead of claiming no such vendor exists, and still finds them under the name you know.

  • Add a product or service you can invoice for

    An agent could add customers and accounts but not the thing you actually bill for, so raising an invoice for new work meant stopping to create the service item by hand first. You can now propose a new product or service: what it is called, whether it is a service or a non-inventory product, the income account its sales post to, and optionally a default rate and a description. The income account is the part worth knowing about — Dough resolves it against your live chart of accounts when the proposal is raised and checks that it really is an income account, so a proposal pointing at an expense account is refused up front instead of being approved and then rejected by QuickBooks. A rate of zero is allowed, because that is how a placeholder billed per job is spelled. Two limits stated plainly rather than discovered: inventory items cannot be created here — they need quantities, a start date and an inventory asset account, and creating one posts an opening balance, which makes it a write that moves money rather than a name added to a list; and taxability, purchasing details, SKUs and sub-items are not settable, so a payload naming them is refused rather than silently accepted.

  • Correct a product or service

    Adding a product or service was possible; changing one was not, so a rate rise meant editing every item by hand in QuickBooks. You can now propose an edit to an existing item — rename it, change its default rate or description, or repoint its revenue at a different income account — and the approval panel shows it as a before and after, because the new value on its own does not tell an approver whether it is a correction or a no-op. Set only what you want to change; anything you leave out is left exactly as it is, and a blank is refused rather than quietly erasing the field. Three things it is careful about: the item type cannot be changed, and is refused with the reason, because QuickBooks accepts that change on an item that has never been used and rejects it on one that has — so the same request would behave differently depending on history nobody can see; a repointed income account is still checked to be an income account before anyone approves it; and if Dough created the item, the tracking line it wrote survives an edit that was not about the description.

Fixes

  • Org admins can see every proposal, including ones no gateway member could

    The proposal queue showed each gateway only to the people who review or approve it. That works until a gateway needs neither — an auto-approve gateway posts without consulting anyone, so it has no members, so nothing it did appeared on anyone's queue. Writes reached your books with no record anyone could find, and a write that FAILED to post was just as hidden as one that succeeded. Org admins now see every proposal in their organization on the All tab, and the "approved writes did not complete" banner counts all of them. Nothing changes for anyone else: who can act on a proposal is untouched, and non-admins see exactly the gateways they belong to.

  • Editing an account no longer clears its description, number or parent

    Correcting one field on an account quietly erased the others. Change a detail type and the account's description, its account number and its place under a parent were all wiped — the edit landed, the approver saw exactly what they had authorised, and nothing reported a problem. QuickBooks turns out to treat an account edit as a replacement of the whole record rather than a change to one field, and it accepts the flag that is supposed to say otherwise while ignoring it, so a successful edit and a destructive one look identical from the outside. Account edits now send the account back in full, so everything you did not change stays exactly as it was — including the tracking note Dough writes when it creates an account, which is what lets a failed post be retried without creating a duplicate. Verified against a real company rather than inferred: the check reads the account back afterwards and compares every field, and it refuses to pass unless it actually compared the ones that were being lost.

  • A failed proposal now means nothing was written — and says so

    When a proposal failed, the page hedged: most failures mean nothing reached QuickBooks, but a response can be lost after a write lands, so check before re-proposing. That hedge was honest, because the system genuinely could not tell the two apart — if it could not verify a failure it recorded one anyway. The risk was real: re-proposing after a write that had actually landed would post a second copy. Now an unverifiable failure is not recorded as a failure at all. It stays in progress and settles once QuickBooks can be read again, which for the most common cause — a connection needing reconnect — is one click. So a proposal marked failed has genuinely written nothing, the page says that plainly, and re-proposing cannot duplicate. Also fixed: a failed account proposal no longer talks about document numbers, which accounts do not have, and the progress stepper no longer tells a failed write that it is retry-safe.

Improvements

  • A failed proposal now tells you what QuickBooks objected to

    When a proposal failed to post, the reason recorded against it was a bare status code — you could see that QuickBooks refused the write, but not why, and working it out meant reproducing the call by hand. QuickBooks usually explains itself clearly ("When you use Accounts Receivable, you must choose a customer in the Name field"), and that explanation is now kept and shown on the proposal, along with Intuit's error code. Sign-in and token errors are still recorded without detail, because those messages can contain credentials. Separately, a new account is no longer left to QuickBooks' own choice of detail type: for the four "Other" account types Dough now sets a neutral one, because QuickBooks would otherwise file an Other Current Asset as an employee cash advance. The approval screen shows the detail type that will be written, marked when it is Dough's default rather than yours.

Wednesday, August 12, 2026

8 changes

New features

  • Ask what happened to a proposal after you raised it

    Raising a proposal gave you a reference and nothing else — there was no way to ask what became of it, so an agent could put a write in front of you and then had to rely on someone reading the queue and saying what happened. You can now look one up by its PROP- reference and see where it is, who it is waiting on, and — once approved and posted — the record it created, with a link to it. Approval and posting stay separate: only a posted proposal has actually reached your books.

  • Agents can propose a new QuickBooks account, not just a journal entry

    The Action Gateway governed exactly one kind of write: a journal entry. Adding an account to the chart of accounts still meant someone doing it by hand in QuickBooks. An agent can now propose one, and it goes through the same approval queue — a name and an account type, optionally a number and a parent to nest it under. The parent is named however you have it (by name, by account number, or by id) and is resolved against your live chart of accounts when the proposal is raised, so a parent that does not exist is refused before anyone approves it. Set who approves it under Action Gateway, where the wizard now asks which action you are configuring. Two things worth knowing: creating an account is close to irreversible, because QuickBooks has no delete for accounts — only deactivation, and a deactivated account still holds its name. And a duplicate name is only caught when the proposal posts, not when it is raised, so the approval panel says so rather than implying it checked.

  • Name the account on a journal entry instead of hunting for its id

    A proposed journal entry can now say which account it posts to by name or account number — whichever you actually have — and Dough resolves it against your live chart of accounts. Previously it demanded QuickBooks' internal id, which appears on no report or statement, and an entry naming an account that did not exist was only refused after someone had already approved it. A name matching more than one account is refused with the candidates listed rather than guessed at, and the approver now sees the account's name rather than a bare number.

Improvements

  • Delete a saved query from the query itself

    Deleting a saved query meant leaving it and hunting for its row back on the Queries list. The query's own page now has a Delete button, with a confirmation that says what actually goes: the query is removed for everyone in your workspace and can't be recovered, while the tables it reads are untouched.

  • Proposal gate checks say what they did and did not verify

    The checks panel read "all passing" while having verified nothing about the connected system, so an entry that QuickBooks would reject could show three green ticks to the person approving it. It now names what it could not check — currently whether the accounting period is still open — and reports separately whether the entry's accounts were resolved against your company.

  • A table's link no longer repeats the dataset it lives in

    A table page used to live at /datalake/tables/<dataset>/<table>. For a workspace whose lake is one BigQuery dataset, the dataset half of that was the same value on every table — it told you nothing and made every link longer than it needed to be. Those workspaces now get /datalake/tables/<table>. Links you had already saved keep working, because the old two-part form still resolves, and a workspace whose lake spans several datasets still shows both parts, since there the dataset is real information about where the table lives.

  • A connected source's name is fixed once it has imported tables

    You name a source when you connect it, and that name is what its tables are filed under. Renaming it afterwards was never offered in the app — the name step only appears before the first import — but the underlying request was not actually refused, so it could still happen and left the source pointing at a name none of its imported tables use: every one of them would show as your own data rather than the integration's, and the renamed source would look empty. Renaming after the first import is now refused outright, with a message saying why. Nothing changes before the first import: you can still rename a source you have just connected as many times as you like.

  • Data Lake tools now tell an agent the exact name to query

    The Data Lake's agent tools used to teach a naming convention and let the agent assemble table names from it — a mapped table was `<integration>_mapped.<table>`, a calculated one lived in `dough_calculated`. Every listing and every "here is your new table" response now states the queryable name outright, and the tool descriptions say to use that name verbatim rather than deriving one. Two visible changes if you read the raw tool output: `integrations.tables` groups tables by the integration they came from, so a mapped companion appears inside its source's group with `mapped: true` rather than in a separate `<integration>_mapped` group, and every table carries a `name` field — that field, not the group name joined to the table name, is what belongs in SQL. Calculated tables are flagged `calculated: true` for the same reason. Nothing about your tables, queries or mappings changes, and every name that worked before still works; this is the tools describing the lake as it is rather than as a spelling rule.

Tuesday, August 11, 2026

1 change

Improvements

  • "Stray" is now "Client" in the Data Lake's Type filter

    A table sitting in your warehouse that Dough has no record of used to be labelled "Stray" in the Data Lake's Type filter. It is now labelled "Client" — it is your data, sitting in your own warehouse, not debris Dough left behind. If you have a saved or bookmarked link with `?type=STRAY` in the URL, that value no longer matches anything, so the filter quietly stops narrowing the list rather than erroring; re-apply the filter and it will save as `?type=CLIENT` going forward.

Monday, August 10, 2026

3 changes

New features

  • Keep the spreadsheet a table was made from

    When an agent turns a spreadsheet into a table, the spreadsheet itself is now kept. It converts the workbook to CSV as before, but uploads the original alongside it, and the table's Version History offers that file for download next to the CSV and the table snapshot — so “where did this number come from” ends at the workbook somebody actually edited, not at a conversion of it. Put the sheet name in the upload's label, since a workbook cannot say which tab became these rows. Deleting the table deletes those workbooks too, and the confirmation says so. Uploads made from the browser are unaffected — there is no workbook to keep — and uploads from before this shipped have none.

  • Download the CSV a row came from

    Dough now keeps the CSV you uploaded, not just the table it became. Every entry in an uploaded table's Version History offers two downloads, and they are different things: “Original CSV” is the file you handed over — that upload's rows, in your own column order — while “Table after this upload” is the whole table as it stood once that upload landed, earlier uploads included. The link you recorded for each upload is shown in full as well, rather than hidden behind the label, so a pointer that isn't a web address (an s3:// path, say) is finally visible; those are shown as text rather than as clickable links. Every row in an uploaded table carries the id of the upload it came from, and that id now opens the history straight to that upload — so “where did this number come from” ends at the file itself. Two things to know: uploads from before this shipped have no stored copy, and deleting a table still deletes everything, the stored CSVs included — the confirmation says so.

Improvements

  • Agents upload a CSV's bytes instead of retyping them

    An agent loading a table used to have to write the whole CSV out inside the tool call, value by value. That is reliable for a short, narrow table and much less so for a long or wide one — and only half of what can go wrong is catchable: a missing comma changes a row's field count and is rejected, while a changed digit passes every check and lands as data nobody can tell is wrong. Agents can now upload the file's bytes straight to storage and hand back a pointer, the same way they already keep a source workbook, so a file that exists on disk is copied rather than regenerated. Nothing changes for uploads made from the browser, and the old inline path still works for small data an agent is composing itself. The 5 MB limit per upload is unchanged.

Sunday, August 9, 2026

3 changes

New features

  • Every upload to a table, and what it changed

    An uploaded table now has a Version History tab: every upload listed newest first, with where it came from, how many rows it wrote, and how many rows it added, changed and removed. You can download any version's snapshot too — the table exactly as it stood after that upload, as the CSV it was stored as. Some uploads show no comparison rather than zeros, and say why: the first upload has nothing before it, and an upload whose snapshot was skipped or could not be written has nothing to compare with. When an upload changed which columns identify a row, it says so — that alone can make a large number of rows count as removed and re-added even though the data did not change.

  • Upload a CSV from the browser, not just through Claude

    Creating an uploaded table no longer needs an agent. From Data Lake, choose a CSV, then for each column confirm what it is — Dough pre-selects a starting guess from the file's values, but the type you pick is the type that's checked — and choose the columns that identify a row. Every upload also asks where the file came from: a source label and an optional link, stamped on every row it writes. An uploaded table's page now has Append and Replace next to Delete. Append can bring a column the table hasn't seen before; a column an append leaves out is simply blank for those rows already there. Replace takes the same typed-name confirmation as Delete. One thing this does not do: appending a file whose rows repeat keys already in the table is accepted as-is, not checked against what's already there — only duplicate keys within the same file are caught.

Improvements

  • Uploads keep a copy of the table, count what they changed, and refuse repeated keys

    A successful upload now keeps a CSV snapshot of the table as it stood once that upload had landed, and records against that upload how many rows it added, changed and removed. It also closes the gap the previous entry admitted to: an append whose rows repeat keys already in the table is now refused before anything is written, and the message names the keys, instead of the duplicates quietly landing. Two limits worth knowing. A snapshot is skipped for a very large table — the load still succeeds and the table is fine, but that upload keeps no snapshot, and without one its added/changed/removed counts are not worked out either. And the repeated-key check compares against the previous upload's snapshot, so for a table that predates this, or one whose last snapshot could not be written, there is nothing to compare with: the check is skipped and recorded as skipped rather than claimed. Where the snapshot was merely missing this time, the next successful upload restores the comparison; where the table is over the size limit it stays skipped, since adding rows only makes it larger. One case is refused rather than skipped: if an earlier upload to the same table is still loading, its snapshot does not exist yet, so this upload is turned away with a message asking you to retry in a moment. That is what keeps the repeated-key check working when you upload several files one after another — without it, every upload after the first would find no snapshot and land unchecked. And where the check genuinely is skipped, the upload now tells you so, rather than leaving you to assume it ran. The counts are left blank rather than guessed whenever there is nothing to compare against — a table's first upload after this ships has no earlier snapshot, so it shows none.

Saturday, August 8, 2026

1 change

New features

  • Uploaded tables record where their rows came from

    Every CSV upload now carries a source label and an optional link, recorded against the upload and against every row it writes. Uploads keep a numbered history, appends can bring new columns, and each table declares the columns that identify a row.

Thursday, August 6, 2026

1 change

New features

  • Proposals carry the files and the session behind them

    A proposal can now arrive with its evidence attached: the invoices, exports and workpapers an entry was built from, plus the full session that derived it. They show up on the proposal page as a list you can download, each with the agent's one-line note on why it is there. Anyone who can open the proposal can read them — an approver who cannot see the backing cannot evaluate the entry. The bytes travel out of band rather than through the agent, so size is not a limit and nothing is retyped in transit. If something a proposer meant to attach never uploaded, the proposal says so plainly instead of quietly looking complete: the missing file is listed by name, and the record is flagged incomplete above the list so it is read before anyone approves, not after.

Wednesday, August 5, 2026

2 changes

New features

  • See, rename, reconnect, and actually disconnect the QuickBooks connection

    Action Gateway has a Connections page. It shows the QuickBooks company file Dough is authorized to write to, and every gateway that posts through it. You can rename the connection to whatever your team calls that company, reconnect if it needs re-authorizing, or disconnect it entirely. Disconnecting used to only be possible by hand in the database — it now goes through Intuit properly: Dough asks Intuit to revoke the grant before removing the connection, so access is actually withdrawn rather than just forgotten locally, which was previously impossible.

  • Connect BILL to your data lake

    BILL (formerly Bill.com) is now available as a source integration. Find it under Finance in Add Integration and pick the tables to sync into your data lake like any other source. Connecting it is not a one-click authorize: BILL uses credentials rather than OAuth, so have your developer key, organization ID, and an AP & AR sync token ready — generating them in BILL needs an administrator, and a token issued for Production will not work against Sandbox.

Monday, August 3, 2026

1 change

New features

  • Delete an uploaded table too

    Deleting arrived last time for calculated tables only, which left the more common mess untouched: CSVs uploaded to try something out, or loaded once under the wrong name, stayed in the catalog for good and were visible to everyone in your workspace. An uploaded table's page now has the same Delete button, with the same typed-name confirmation and the same safeguards — it refuses if a calculated table is built on the CSV and tells you which one, refuses if the table has a mapping applied, and refuses while an upload is still loading. The one difference is what deleting costs you. A calculated table keeps its query history, so its SQL survives; an uploaded table's rows exist nowhere else, because Dough does not keep a copy of the file you uploaded. Restoring one means uploading the CSV again, and the confirmation says so.

Sunday, August 2, 2026

2 changes

New features

  • Delete a calculated table you no longer want

    Calculated tables could be created and edited but never removed, so a table made with a typo in its name, or half a dozen left over from trying the feature out, sat in the catalog for good — and because the calculated dataset is shared across your workspace, everyone saw the clutter. A calculated table's page now has a Delete button. You type the table's name to confirm, and it drops the table and removes its definition so nothing rebuilds it later. Two things it will not do. It refuses if another table is built on this one, and names them, so you remove them from the bottom up rather than leaving tables that quietly fail on their next refresh; and it refuses while a rebuild is running, since that rebuild would recreate the table after it was deleted. Your query history survives the delete: create a table with the same name again and its earlier versions are all still there, so deleting does not throw away the work that went into the SQL. Deleting is available on the web only and is not something an agent can do, because there is no undo on a deleted table.

  • See what a table is built from, and what depends on it

    Every table in the Data Lake now has a Lineage tab. It shows what the table reads from and what is built on top of it, so you can answer "where do these numbers come from?" and — the harder one — "what breaks if I change this?" without tracing SQL by hand. It is there for synced tables too, not just calculated ones: a table straight from QuickBooks or Campfire reads from nothing, but seeing the four things downstream of it is the whole point before you touch it. Each entry says what kind of table it is and links straight to it. On a calculated table's Query tab, editing now tells you by name which tables saving will rebuild, because they are rebuilt for you automatically.

Saturday, August 1, 2026

1 change

New features

  • Set a gateway's approval policy and its reviewers and approvers

    The New gateway flow used to stop after picking an action, so the only way a gateway existed at all was for someone to write one directly into the database. It now goes the whole way. Pick how much sign-off the action needs — post immediately, let the proposer approve their own, one approver who is not the proposer, or review then approve — then choose who holds each capacity, then enable it. Two things worth knowing before you press Enable. The lists replace whoever holds each capacity today rather than adding to it, so removing someone here removes them; and emptying a capacity the policy requires stops anything new being proposed through that gateway AND leaves proposals already waiting at that stage stuck, since they can no longer be actioned or rejected by anyone. Both are allowed and both are spelled out on the screen, with a count of exactly how many proposals are already waiting. Clicking a gateway on the index opens the same flow on its current configuration, so changing a policy later is the same screens. Reconfiguring never retouches proposals already raised — each one carries the rules that applied when it was raised. Admin only.

Thursday, July 30, 2026

4 changes

New features

  • See which writes are governed, and by whom

    Action Gateway has a Gateways page. It lists every action your team can propose, the approval policy that governs it, who holds each capacity, and how many proposals it has taken in the last 30 days. Status is worth reading: a gateway whose required capacity has nobody in it is shown as needing one, because that is a gateway the propose path will refuse — emptying an approver list is allowed, and until now the only way to find out you had done it was for someone's proposal to be turned away. The New gateway flow opens with the product and action pickers; the products and endpoints Dough cannot write to yet are listed but greyed out, so it is clear what exists today rather than what is missing. Choosing a connection, setting the policy and enabling the gateway land next — the flow stops after the action step for now. Admin only.

  • Bring your own data: upload a CSV straight into the data lake

    Some numbers have no system behind them — a budget, a headcount plan, an allocation key, a mapping someone keeps in a spreadsheet. You can now ask Claude to load a CSV directly into your data lake, where it lands as a real table alongside everything your integrations sync and can be queried, mapped and joined the same way. Add more rows later by uploading again, and the columns are matched by name so their order in the file does not matter. You tell Claude what each column is — a date, a whole number, an amount — and the values are checked against that before anything is written, so a stray "N/A" in an amount column is reported with the row and column named rather than failing silently somewhere downstream. Columns that do not match the table are refused outright rather than quietly filled in, and replacing a table's contents takes an explicit confirmation.

Improvements

  • Calculated and mapped tables now rebuild themselves when their sources refresh

    A table built from other tables used to go quietly out of date. When an integration synced new rows, anything calculated from it kept serving the previous run's numbers — the page still said everything had succeeded, and the only way to find out was to notice the figures were wrong. Dough now works out what each table is built from and rebuilds the ones downstream after a sync lands, in the right order, so a source is always refreshed before the things that read it. The same applies when you edit a calculated table's query by hand: its mapped version is rebuilt too, which matters because once a mapping exists, the mapped version is the row the catalog shows you. Rebuilds run in the background within a few minutes of a sync completing, and never displace a build you asked for yourself.

  • Clearer table types in the Data Lake, and mapped tables keep their source

    The Data Lake list now says where a table's rows actually come from. "Integration" is now "Synced", because it describes the table rather than the connection behind it. Applying a mapping no longer changes what a table IS — a calculated table with a mapping still reads Calculated, with a small "Mapped" chip beside it, where before it dropped out of the Calculated filter entirely. A mapped table also keeps its original source, so filtering by QuickBooks or Salesforce now finds it. And a table sitting in your warehouse that Dough has no record of is labelled "Stray" instead of being presented as one of your integrations.

Wednesday, July 29, 2026

2 changes

New features

  • Claude can see who approves a write — and you can name them by email

    Claude can now ask which changes it is allowed to propose for your organization and who reviews or approves each one, before it builds anything. Previously the only way to find out was to name the wrong person and read the error. It also tells you when an action cannot be raised at all — because no one has configured who approves it, or because a required approver seat is empty — so you hear that up front rather than after preparing an entry. And when you want a specific person to handle something, you can say their email instead of an internal id.

  • See every proposal, not just the ones waiting on you

    The Proposal Queue only ever showed work you could act on right now, so anything you had already approved or rejected vanished the moment you decided it, and a write that posted — or silently failed to — could not be found anywhere. A new All tab shows every proposal raised against a gateway you belong to, in whatever state, most recent activity first, with a status filter for narrowing to Posted, Failed or anything else. A posted proposal links straight to the journal entry it created in QuickBooks, and a failed one now shows why it failed instead of disappearing. Failures are also counted at the top of the queue on every tab, because an approved write that never landed is the one thing nobody should have to go looking for. The two pending states are renamed to say what they are waiting for — "Awaiting review" and "Awaiting approval" — replacing "Queued", which read as though the entry were already on its way to being posted.

Tuesday, July 28, 2026

1 change

New features

  • Claude can read a query result that doesn't fit in one answer

    A read-only query stopped at 5,000 rows and said nothing useful about what it had left behind, so a larger pull had to be hand-split into pieces and stitched back together. Claude can now ask for a result set of up to a million rows and read it a page at a time, and every response reports how many rows the full result actually has — so it can tell up front when summarising in SQL beats reading every row. Only the first page runs the query; the rest re-read the finished result and cost nothing, and a query may now run for up to 60 seconds rather than 15. Nothing changes unless it's asked for: a query that doesn't request more still comes back in one call, the same 5,000-row ceiling as before.

Monday, July 27, 2026

1 change

Fixes

  • A write that could never post no longer reaches an approver

    Proposals are now checked when Claude raises them, not when Dough tries to post them. An entry whose debits don't equal its credits — or that has one line, sub-cent amounts, a malformed date, or a missing account — is refused immediately, with the offending line named, and never enters the queue. Before this, such an entry could be reviewed by one person and approved by a second before failing on the way to QuickBooks: two sign-offs spent on something that was never writable, and a failed record nobody could fix without starting over.

Sunday, July 26, 2026

4 changes

New features

  • Claude can propose a write instead of telling you to make it

    Claude can now raise a change to a connected system — a QuickBooks journal entry, to start — straight into the Proposal Queue, where a person reviews and approves it before anything is written. It cannot write on its own: who approves each action is configured per organization, and Claude is told which stage its proposal landed in and who it is waiting on. Naming an approver who isn't one comes back naming who is, and Claude can attach the conversation behind a proposal so whoever approves it can see the reasoning rather than a one-line summary.

  • Claude can now rewrite a calculated table's query

    Agents could create calculated tables but never change one — reworking a query meant doing it in the app or creating a second table under a new name. The new tables.update tool rewrites an existing table's SQL and rebuilds it in place, keeping the name. It won't touch a table the person's role can't already read, it requires Claude to record an explicit confirmation that you approved the change — which lands in the audit trail — and every rewrite appears in the table's Version History with who made it and whether the rebuild succeeded — so a bad change is visible and attributable.

  • See how a calculated table's query has changed

    Calculated tables now keep a history of their defining query. A new Version History tab shows every saved version — who changed it, when, and whether that version's build actually succeeded — with the full SQL one click away. Because a version is recorded when it's saved rather than when it's built, you can also spot the case where a table is still serving data from an older query than the one it now stores.

Fixes

  • Pages respond the moment you click them

    Navigating to a list — Tables, Queries, Files, Agents, Logs, Connections — used to sit on the previous page until all of its data had loaded, which read as a freeze on the slower Data Lake screens. Those pages now show a loading placeholder immediately and fill in as the data arrives, and the app reuses your identity within a request instead of re-reading it for every section of the page.

Saturday, July 25, 2026

1 change

New features

  • Give your tables the names and context your team actually uses

    Every table in the Data Lake now has an "Also known as" and a "Team notes" field. Record the names your team calls a table and the things its schema can't say — which rows to exclude, what a column really holds, who owns it — once, for everyone. Aliases are searchable on the Tables page, and Claude reads both back over MCP: it can resolve "deals" to the right table, and it's told to follow your notes when it writes SQL.

Monday, July 20, 2026

2 changes

Fixes

  • Agent observability self-repairs its hooks

    If the observability hooks ever get pointed at a stale or missing directory, the CLI now detects and repairs that on the next session instead of silently stopping capture, and it no longer writes throwaway test directories into your global hook config. Update to the latest dough CLI to pick this up.

  • Agent session logs capture reliably again

    The observability hook now refreshes its own access token, so per-agent telemetry and session transcripts keep flowing instead of silently stopping about 12 hours after the last CLI command. Update to the latest dough CLI to pick this up.

Sunday, July 19, 2026

2 changes

New features

  • Web access now follows each person's role

    Data Lake actions in the app — running queries, previewing, creating calculated tables, and editing mappings — now respect the role you set in Admin. Read-only roles can view but not create or edit, and sensitive tables are reachable only by roles with sensitive access, matching what agents already enforce over MCP.

  • Control what each teammate can access

    The Admin screen now sets access by role instead of per-tool checklists. Give each person Read or Read & write, and the sensitive variants for people who should reach sensitive data. Mark tables sensitive on the new Sensitive Tables tab — only sensitive roles can query them (and their mapped output); everyone else can read every other table. Admins manage this for their own organization.

Tuesday, July 14, 2026

2 changes

New features

  • Read your action log from an agent

    The logs.* tools are now available over MCP, so an agent can list, search, and fetch entries from your action log — the same log the Logs page shows. Scoped to your organization, like every other tool.

Fixes

  • Your AI client now lists only the tools you have

    Dough was handing every connected AI client the full tool catalog, including tools your organization does not have. They were never usable — calling one returned "not enabled for your organization" — but your agent could not tell that until it tried, so it would pick a dead tool and waste a turn discovering it. Your client now sees only the tools your plan includes. If Dough is already connected, reconnect it to refresh the list.

Monday, July 13, 2026

5 changes

New features

  • Agents can turn a query into a table

    Connected agents can now create calculated tables over MCP. An agent that has worked out the right SQL can materialize it as a real table in your data lake, where it shows up in the app next to your integration tables and can be queried, mapped, and joined like any other one — so the analysis becomes something your team builds on instead of a result that scrolls away. The table is built by a background BigQuery job the agent polls until it lands. Agents can create tables but never replace or drop them; other queries and mappings may already depend on a table, so dropping one stays in the app.

  • Connect Ramp to your data lake

    Ramp is now available as a source integration. Find it under Finance in Add Integration, authorize it, and pick the tables to sync into your data lake like any other source.

  • Agents can build and maintain your mappings

    Mappings are now available to connected agents over MCP. An agent can see which tables and columns can be mapped, read a mapping as a spreadsheet-style CSV, fill it in, and apply it — which rebuilds the mapped table in BigQuery just as it does in the app. It works on the same CSV you download and upload yourself, so an agent can pick up a mapping you started, or you can pick up one it started. A file that would clear values or drop a column says so before it is applied, and an agent can preview any change without writing anything. Agents can create and update mappings but never delete them; deleting stays in the app.

  • Agents can read and write your saved queries

    Saved queries are now available to connected agents over MCP. An agent can list your workspace's saved queries and read their SQL — so it learns how your team actually computes its metrics instead of guessing from table names — and it can save new analysis back for you to find in the Queries page. Agents can create and update queries but never delete them; deleting stays in the app. Only read-only SELECT queries can be saved, and each tool must still be granted to a user before they can use it.

Fixes

  • Dough shows up as Dough in your AI client

    The MCP connector now carries Dough's name, icon, and website, so it appears with the Dough logo instead of a blank placeholder. It had also been identifying itself to every client under the old pre-rebrand name. If you already have Dough connected, remove and re-add the connector to pick this up — clients read a connector's identity once, when it is added.

Sunday, July 12, 2026

6 changes

New features

  • Run and save SQL queries

    A new Queries section under Data Lake. Write read-only SQL, run it to preview up to 100 rows (paged 20 at a time), and save it with a name so anyone in your workspace can open and re-run it later. Only SELECT queries are allowed — writes and schema changes are rejected before anything reaches the warehouse.

  • Fill a mapping in Excel and upload it back

    Download a mapping as a CSV, fill the output columns in Excel or Sheets, and upload it back. The file replaces the mapping's values and columns, with a summary of exactly what changes before anything is applied — and nothing is saved until you click Save Draft or Apply Mapping.

Fixes

  • Agents can discover available tools again

    tools.list, tools.describe, and tools.schema were being rejected for every user, so an agent following its own instructions to look up a tool first would hit a permission error. They now work for anyone connected over MCP.

Improvements

  • Your workspace now shows only what your plan includes

    Navigation, documentation, and tools are tailored to the features your organization has enabled, so you no longer see pages and tools you can't use. Docs now list only the guides relevant to your plan.

  • Sidebar sections expand in place instead of navigating away
  • New Dough logo in the sidebar and app icon

Saturday, July 11, 2026

2 changes

Breaking changes

  • Dashboards, Pivot Tables, Financial Plans, and Campfire retired

    These features have been removed, along with their pages and saved data. Dashboards and templates, pivot tables, financial plans (/plans), and the Campfire integration are no longer available. Data Lake tables, mappings, and agents are unaffected.

Improvements

  • Map columns with up to 1,000 distinct values

    Mappings used to reject any column with more than 100 distinct values. The limit is now 1,000, and the fill screen pages through them 20 rows at a time so a large mapping stays workable.

Friday, July 10, 2026

1 change

Improvements

  • Map calculated tables too

    Mappings now work on calculated (SQL-defined) tables, not just integration tables — pick one in the Create Mapping table list just like a Salesforce or Campfire table. Only mapping-output tables are excluded, since a mapped table can't itself be mapped.

Thursday, July 9, 2026

2 changes

Improvements

  • Map any integration table — no primary key required

    Creating a mapping no longer requires the source table to have a primary key, so any integration table (Salesforce, Campfire, …) can be mapped.

  • Mapped tables get clean names and take priority for the assistant

    Custom mapping columns now materialize into a per-integration dataset with the plain entity name — e.g. salesforce_mapped.opportunity. And when a table has mappings, the assistant's data-lake catalog surfaces the mapped version (your raw columns plus the rollup columns) and hides the raw source table, so the assistant reads your mapped values by default.

Wednesday, July 8, 2026

3 changes

New features

  • Preview a column's unique values from a table's schema

    On a Data Lake table's Schema tab, each column now has a “Load values” link that fetches its distinct values on demand — up to 10, with “more…” when there are others. It runs a bounded query, so even high-cardinality columns like IDs stay fast.

  • Create tables from SQL

    Build a calculated table by writing a SQL SELECT. From the Data Lake, click Add Table, name it, then write and preview your query in the new SQL editor. Creation runs in the background — the table shows as "Creating…" and settles into a browsable Calculated table with its row count when done (or a Failed row you can retry).

Improvements

  • Tables & Integrations moved under Data Lake

    The Tables section and the Integrations page now live under a single Data Lake area in the sidebar, with the Data Lake table list as its home. Old links still work — they redirect automatically.

Tuesday, July 7, 2026

1 change

Improvements

  • MCP integration tools now read the data lake

    The assistant can list connected integrations, browse data-lake tables and schemas, preview rows, and run read-only SQL across all your sources (Salesforce, NetSuite, Campfire, …), replacing the Campfire-specific tools.

Monday, July 6, 2026

1 change

New features

  • Connect 40+ data sources, with logos

    The Add Integration picker now offers 40+ data sources — accounting (NetSuite, QuickBooks, Xero), warehouses (Snowflake, BigQuery, Redshift, Databricks, ClickHouse, and more), CRMs, ad accounts, HR, and productivity tools — grouped by category with searchable brand logos. BigQuery can now be connected as a source, so you can move data from your own BigQuery into your Data Lake.

Sunday, July 5, 2026

2 changes

New features

  • Data Lake resolves per workspace

    The Data Lake and mappings now read each workspace's own BigQuery project instead of a shared warehouse. Workspaces without a Data Lake see a clear "not set up" state.

  • Data Lake sets itself up on first Connect

    Once an operator provisions a workspace's BigQuery project, the first Connect click creates the workspace's Polytomic org and BigQuery destination automatically — no second setup step. Failed setups surface on the Integrations page with a retry.

Saturday, July 4, 2026

3 changes

New features

  • Integrations — choose which columns sync

    Expand a connected source and open "Columns" on any synced table to pick exactly which columns land in your Data Lake. Import the whole table (the default) or narrow it to just the fields you need; the primary key is always kept. Unchecking a column stops it from importing but keeps data already in your Data Lake.

  • Integrations — change which tables a source syncs

    Already connected a source but need more (or fewer) tables in your Data Lake? Open a connected source's menu and choose "Manage tables" to add tables to the sync or stop syncing ones you no longer need. Removing a table stops future imports but keeps the data already in your Data Lake.

  • Integrations — live sync status and disconnect

    Connected sources on the Integrations page now show live import progress: watch a sync move from importing to done, expand a source to see per-table row counts for the latest run, and disconnect a source you no longer need. Disconnecting stops future imports but keeps the tables already imported into your Data Lake.

Friday, July 3, 2026

4 changes

New features

  • Integrations — import tables into your Data Lake

    Connect a source from the Integrations page, pick the tables you want, and Dough imports them into your workspace's Data Lake. Once imported, sync a source's tables on demand with a "Sync now" action on its row.

  • Integrations page — see your connected data sources

    A new Integrations page (under Tables in the sidebar) lists the data sources connected to your workspace's data lake, alongside a catalog of sources available to connect (Salesforce, Stripe, QuickBooks, HubSpot, NetSuite, Snowflake). This first release surfaces connected sources and the available-to-connect catalog; connecting a new source from the app lands in the next update. It will ultimately replace the existing Tables → Integration page.

Improvements

  • `dough skill install` installs to a fixed user-scope location

    `dough skill install <name>` now installs into `~/.claude/skills/` (user scope) instead of a `.claude/skills/` folder in whatever directory you happened to run it from — so an installed skill is available in every Claude Code session regardless of your working directory, matching how `dough agent install` resolves a fixed location. Override the target with the `DOUGH_SKILL_DIR` env var or the `skillsDir` CLI config key. Agent-pinned skills are unaffected — they still vendor into each agent's own `.claude/skills/`. Requires the latest `dough` CLI.

  • Mapping rebuilds recover automatically

    Background mapping rebuilds that stall now recover on their own instead of showing a stuck "Syncing" state — a reconciliation pass re-runs missed rebuilds and times out ones that never finished.

Thursday, July 2, 2026

2 changes

New features

  • SOX agents get an ICFR review each time you publish a new version

    Publishing a new version of a SOX-tracked agent now creates a pre-filled ICFR review for that version — carrying the previous version's answers forward so you only review what changed. Pending reviews appear in the SOX Agents list (with a "Needs review" tag) and as a count badge on the sidebar.

Improvements

Wednesday, July 1, 2026

1 change

New features

  • Mapping transform

    Applying a mapping now materializes a BigQuery table (`<dataset>__<table>_mapped`) with your rollup columns joined onto the source rows, rebuilt automatically whenever the mapping changes. The Mappings list shows live Syncing → Synced status with row counts.

Tuesday, June 30, 2026

2 changes

Improvements

  • Page through a table's row preview

    The Data Lake table Preview now loads up to 100 rows and pages through them 20 at a time, and the Schema tab shows how many time-dimension (date/timestamp) columns the table has.

  • Data Lake "Refresh all schemas" shows feedback

    The "Refresh all schemas" button on Tables → Data Lake now shows a spinner while it runs and a confirmation toast when it finishes.

Monday, June 29, 2026

3 changes

Improvements

  • Data Lake lists tables across all datasets

    Tables → Data Lake shows every table across all datasets in the BigQuery project, with a Dataset column.

  • Data Lake tables: Preview and Schema tabs

    The Data Lake table detail view now splits into Preview and Schema tabs. The Schema tab lists each column's type, nullability (NOT NULL / NULLABLE), and description.

  • Browse your datalake tables

    Tables → Data Lake lists every table in the connected datalake (BigQuery). Open a table to see its schema (column name, type, mode) and a 10-row preview. Use "Refresh all schemas" to re-read the latest tables.