You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Migrations (0060–0067) run automatically when the container starts. Nothing changes in docker-compose.yml or .env.
The AI chat's memory is on. Where AI is on, the chat may keep notes about the people who use
it (asking them first, unless the mode is Auto), and agents' runs may propose notes for owners
to review. Owners who don't want it turn it off per workspace under Settings → General → AI → AI memory; each person can also turn it off for themselves in the Memory dialog.
Write tokens and MCP apps reach agents. For a workspace owner, an API token or MCP app with pages:write can now change the workspace's agents (pause them, set a monthly token limit) and
ask them for runs, which use the workspace's AI allowance. Give integrations that only read a pages:read token, or let apps only read under Settings → Security.
Apps that reach a workspace show when each app or token last reached it from this version
on; earlier use isn't known.
Added
Memory for the AI chat. The chat keeps short notes about each person in a workspace (who
they are, what they work on, how they want answers) when they tell it about themselves or ask it
to remember something, and drops one when asked to forget, with new remember and forget tools
offered in every mode. Unless the mode is Auto, the chat asks the person (Yes or No) before
it keeps or drops a note, also in Read only, so text it read can't slip in a lasting note; each
note kept, dropped or declined shows among the answer's steps and is kept with the conversation
also when the answer fails, and Answer again carries it to the new answer. Only what the
person says in their questions is kept, never what pages or tool results say. The notes go with
the person's later questions in that workspace as data, never with anyone else's or in another
workspace, and never widen what the chat may read or change. The new Memory dialog (the brain
button in the chat's header and panel) lists them, adds, changes and deletes notes, and forgets
everything. Up to 30 notes of 300 characters per person and workspace; they are deleted when the
person leaves the workspace or deletes their account. Migration 0063_ai_memory adds ai_memory. Covered in scripts/ai-memory-e2e.ts.
Switches for the AI chat's memory.Use memory at the top of the Memory dialog turns the
memory off for the person in that workspace, and owners can turn it off for the whole workspace
under Settings → General → AI → AI memory, which also hides the Memory button. While it is
off, questions carry no notes and the chat isn't offered remember or forget; no note is
deleted, and owners' changes are in the audit log. Migration 0064_ai_memory_switch adds workspace_member.ai_memory. Covered in scripts/ai-memory-e2e.ts and scripts/ai-chat-e2e.ts.
Memory for agents. Agents keep short notes that go with each of their runs (where things go
in the workspace, how a recurring case is handled). Because everything a run reads was written by
someone else, a run only proposes notes, with a new remember tool: each proposal shows among the
run's steps, with credentials masked, and goes with no run until an owner keeps it. The agent's
new Memory tab (and a "notes to review" link in the list of agents) shows proposals with the run's
row and time, to keep as they are or changed, or dismiss; owners also write, change and delete
notes and make the agent forget everything. A proposal from a row an owner can't open is shown to
them without its text, and only dismissed. Runs drop notes at once with forget. Runs no member
stands behind (anonymous or outside form answers, untrusted triggers) get neither tool but still
get the kept notes, which reach the model as data inside <memory> and never widen what it may
change. Up to 30 notes of 300 characters per agent and 10 proposals waiting; an unanswered
proposal goes with its run after 30 days. The workspace's AI memory switch holds for agents
too: off, runs carry no notes and propose none. Changes are recorded in the audit log, counted. MCP's get_agent lists the notes and proposals. Migration 0065_agent_memory adds status and agent_run_id to ai_memory. Covered in scripts/agent-memory-e2e.ts.
Owners hear of an agent's proposed notes. When a run proposes a note, each owner of the
workspace gets one inbox item for that run, pushed too (without the note's text) and never
emailed, whatever their notification choices. It shows the first proposal's text, unless the run
was on a row that owner can't open, and how many more there are; it opens the agent's Memory
tab (?tab=agents&agent=<id>&agentTab=memory), can be snoozed, and goes away once every proposal
of the run is kept or dismissed. Answering an agent's call no longer takes the run's other inbox
items with it. MCP adds keep_agent_memory and dismiss_agent_memory for proposals, and add_agent_memory, update_agent_memory and delete_agent_memory for an owner's own notes,
each answering with the agent's memory as get_agent shows it; list_notifications summarizes
the new item. Migration 0066_agent_memory_notice lets agent_memory notifications have no page
and keeps one per run and owner. Covered in scripts/agent-memory-e2e.ts and scripts/mcp-e2e.ts.
Skills. A page or database row can be marked Use as skill in its ⋯ menu (edit access;
not databases, templates or the pages in them): its body is instructions to reuse, and a bar
under the title says what it is for. The sidebar's new skills button opens the workspace's
skills library (searchable, with New skill). In the AI chat, / at the start of the empty box
picks a skill whose instructions the next question follows, without widening what the chat may
change; the question keeps it, and Answer again and Edit use it again. MCP clients get list_skills, get_skill (which refuses a title several skills share) and set_skill, get_page says whether a page is a skill, and every skill the user can open is also a prompt of
its name, unique across their workspaces. The page
menu and the library export a skill as a ZIP holding <name>/SKILL.md. Skills follow page
access everywhere and leave every list while in the trash. Migration 0060_skills adds page.is_skill and page.skill_description. Covered in scripts/skills-e2e.ts and scripts/mcp-e2e.ts.
Skills for agents. An agent's new Skills tab gives it up to 10 skills of the workspace,
whose instructions each run sends to the model after the agent's own. Only skills no one besides
the workspace's owners can edit (not members, teamspaces, groups, guests or agents, the agent
itself included) can be given; a run checks again and leaves out, saying so in its steps, a skill
someone else can edit by then, one no longer marked as a skill, or one that doesn't fit in what a
run may read (12,000 characters together), and the tab shows each skill's state. A run started
by a member's change or a public form leaves out the skills that person can't open, and a run
that goes on after an approval checks its skills again. MCP clients get set_agent_skill, and get_agent lists the agent's skills. Giving and taking a skill is recorded in the audit log.
Migration 0061_agent_skills adds agent_skill. Covered in scripts/agent-skills-e2e.ts.
Apps that reach a workspace. Settings → Security shows its owners the MCP apps the
workspace's people connected and their REST API tokens for it, with what each may do, who
connected it and when it last reached this workspace (not before this version), the 100 apps
and 100 tokens used here most recently first. An owner can
disconnect one person's app or revoke their token; as both belong to the person, it stops
reaching all of their workspaces, and this workspace's audit log records it with the owner as
who did it. Migration 0062_connected_app_use adds connected_app_use. Covered in scripts/workspace-apps-e2e.ts.
About. Settings (and the account page) have an About tab: the Leafdesk version the server
runs with a link to its release notes, who makes it, the license, the website, the source code,
where to report a problem and the third-party notices. The version is read from package.json,
which the MCP server now reports too. No migration.
Copy ID. A page's, database's or row's menu (also in the row panel) has Copy ID, and a
column's menu, in the table and on a row's page, Copy property ID: the ids the REST API and MCP
clients take, where a property's name may change. No migration.
High contrast. Settings → Preferences → Appearance has Contrast: follow the system (its
"increase contrast" setting, prefers-contrast: more), Standard or High, kept for the
browser in a cookie like the theme and carried by <html data-contrast>. High contrast keeps
the backgrounds and makes, in either theme, secondary text at least 7:1 on the page and 4.5:1 on
hovered and selected rows, faint text (hints, placeholders) at least 4.5:1 everywhere, lines and
control edges at least 3:1, the accent and danger colors stronger and the focus ring more opaque; colored and black page backgrounds get the same lines
and text. The editor follows, as it draws with the same colors. src/lib/contrast.test.ts
checks the ratios from globals.css. No migration.
Agents in the Share menu. Typing in a page's Share menu finds the workspace's agents by name
too (archived ones aren't offered; a paused one says so) for members with full access to the
page; one picked starts at Can view, as from the agent's settings. An agent's row shows its
icon and "Agent", and its levels are view, comment and edit only. The server already let anyone
with full access to a page share it with an agent; the menu now offers it.
Agents over the REST API, and runs owners ask for. New endpoints list a workspace's agents
(GET /workspaces/{id}/agents), read and change one (GET and PATCH /agents/{id}: settings,
pausing and resuming, the monthly token limit), ask one for a task now
(POST /agents/{id}/runs), and read its runs (GET /agents/{id}/runs, GET /agents/{id}/runs/{run_id}) and usage (GET /agents/{id}/usage), owners only except the
list. MCP clients get start_agent_run. A run an owner asks for works on a database row (and may
change and comment on it) or on none (it only reads and answers), held to the owner's access as
well as the agent's; it shows who asked, from where and the task, and each request is recorded in
the audit log. Asking is refused with 409 while the agent is paused or archived or AI is off
(agent_unavailable), once it used its monthly limit (limit_reached), or while 5 runs asked of
it still wait (too_many_runs). Covered in scripts/agent-api-e2e.ts.
Agents' usage and a monthly token limit. Each turn a run takes is added to the agent's usage
for the calendar month (UTC): runs, input and output tokens and cost, kept for 12 months. The
agent's Runs tab shows this month against its limit and the months before; MCP's get_agent
shows them too. An owner can set a monthly token limit in the agent's settings (or with update_agent and PATCH /agents/{id}): once the month reaches it, a run under way stops at its
next turn as limitReached and no run starts until the next month. Migration 0067_agent_usage
adds agent_usage and workspace_agent.monthly_token_limit. Covered in scripts/agent-api-e2e.ts.
Dashboards. The /dashboard block shows numbers, charts and lists from any of the
workspace's databases on one page, in a grid of up to 12 widgets that each take a quarter, half,
three quarters or all of its width (two columns on narrow pages, one on phones), and that can be
moved and removed from their menu. A widget is a database seen through its own view: a new Number chart type gives one value (a count, or a sum, average or other calculation over the
rows its filters keep), charts and lists are worked out on the server for each reader (only the
rows and values they may see, and no rows sent for a chart), and other layouts show as a linked
view. Widgets are set up in place with the linked view's own toolbar, update while their rows
change, say under them how many rows they count, by what, with how many filters and when, and
open the rows behind a number, bar or slice. A widget on a database the reader can't open says
only that. Published pages show numbers and lists, and charts as a table of their figures; a
widget on a database outside the publication shows nothing of it. In Markdown a dashboard is the
line <!-- leafdesk:dashboard <id> -->, which keeps it through a rewrite. MCP's new add_dashboard and update_dashboard_widget add a dashboard and add, change, move or remove its
widgets, and get_page lists dashboards and their widgets. Copies of published pages keep the
widgets whose database was copied too. No migration. Covered in scripts/dashboard-e2e.ts.
Colored dashboard widgets. A widget's menu has a Color row: a widget can take one of the
option colors as its background, the same light tint board columns use, in light and dark
themes. Published pages and the print view show the color too. MCP's add_dashboard and update_dashboard_widget take color ("none" for a plain box), and get_page lists each
widget's color. Covered in scripts/dashboard-e2e.ts.
Changed
Published charts show their figures. A chart view on a published page (a published
database's tab or a linked view in its body) shows its number, or a table of each group's value
(and each stacked series'), worked out on the server from the public properties only, instead of
a table of its rows; no rows are sent. A chart grouped or measured by a property visitors can't
see shows nothing to group by, or counts rows. Covered in scripts/chart-e2e.ts.
Dashboards do less work. An open dashboard used to reload every widget whenever any page in
the workspace was created, renamed, moved or shared. Now a widget reloads when its own database's
rows or properties change. Changes elsewhere in the workspace cost one request for the whole
dashboard, which checks its databases' names, icons, trash state and the reader's access, and
only the widgets of a database that changed reload. Sharing a single row now also refreshes open
views of its database. A published or printed page reads each database once, however many
widgets and database blocks show it, and each widget still applies its own filters, chart and
list length. Covered in scripts/dashboard-e2e.ts.
Fixed
A level set for an agent stays when an automation lets go. An automation that runs an agent
gives it edit access to its database and gives back the agent's previous level once no
automation runs it. A level someone set or removed meanwhile from the Share menu was overwritten
then (only the agent's settings counted as setting it); now any change to the agent's own entry
keeps it. Covered in scripts/agents-e2e.ts.
Sign-in recovers when the database was down at startup. The sign-in library queries the
database when it is set up, and it was set up once, when the server loaded it: if the database
couldn't be reached then, sign-in, sessions, MCP and its keys kept failing until a restart. It
is now set up on first use and again after a failed setup, and next build no longer logs a
failed query from every worker.
list_agent_runs names the waiting status as it returns it. Its description said waiting_for_approval for a run that waits for an owner; runs come back as awaiting_approval.