Changelog
Project to Workspace rename and authentication audit logs
This release renames the core Project resource to Workspace — a breaking change — and adds engine-side audit logging for authentication events, alongside a batch of Studio and API improvements and fixes.
Project is now Workspace
monospace_project_<name>_meta and _data schema to monospace_workspace_<name>_…. The whole script runs in one transaction and takes an ACCESS EXCLUSIVE lock, so run it during a maintenance window.ROLLBACK;
BEGIN;
SET LOCAL lock_timeout = '10s';
LOCK TABLE
monospace_system.monospace_projects,
monospace_system.monospace_project_members,
monospace_system.monospace_invitations,
monospace_system.monospace_migrations,
monospace_audit.audit_logs
IN ACCESS EXCLUSIVE MODE;
-- System tables and columns
ALTER TABLE monospace_system.monospace_projects
RENAME TO monospace_workspaces;
ALTER TABLE monospace_system.monospace_project_members
RENAME COLUMN project_id TO workspace_id;
ALTER TABLE monospace_system.monospace_project_members
RENAME TO monospace_workspace_members;
ALTER TABLE monospace_system.monospace_invitations
RENAME COLUMN project_id TO workspace_id;
ALTER TABLE monospace_system.monospace_invitations
RENAME COLUMN project_roles TO workspace_roles;
ALTER TABLE monospace_system.monospace_migrations
RENAME COLUMN last_project_migration TO last_workspace_migration;
ALTER TABLE monospace_audit.audit_logs
RENAME COLUMN project_id TO workspace_id;
-- Indexes
ALTER INDEX monospace_system.monospace_projects_id_primary
RENAME TO monospace_workspaces_id_primary;
ALTER INDEX monospace_system.monospace_projects_api_name_unique
RENAME TO monospace_workspaces_api_name_unique;
ALTER INDEX monospace_system."monospace_project_members_userId_projectId_unique"
RENAME TO "monospace_workspace_members_userId_workspaceId_unique";
ALTER INDEX monospace_system.monospace_migrations_last_project_migration_unique
RENAME TO monospace_migrations_last_workspace_migration_unique;
ALTER INDEX monospace_audit.audit_logs_project_id_idx
RENAME TO audit_logs_workspace_id_idx;
-- Foreign-key constraints
ALTER TABLE monospace_system.monospace_workspaces
RENAME CONSTRAINT "MonospaceProject_logo_fkey"
TO "MonospaceWorkspace_logo_fkey";
ALTER TABLE monospace_system.monospace_workspace_members
RENAME CONSTRAINT "MonospaceProjectMember_project_fkey"
TO "MonospaceWorkspaceMember_workspace_fkey";
ALTER TABLE monospace_system.monospace_workspace_members
RENAME CONSTRAINT "MonospaceProjectMember_user_fkey"
TO "MonospaceWorkspaceMember_user_fkey";
ALTER TABLE monospace_system.monospace_invitations
RENAME CONSTRAINT "MonospaceInvitation_project_fkey"
TO "MonospaceInvitation_workspace_fkey";
-- Handle installations stopped exactly on renamed migrations
UPDATE monospace_system.monospace_migrations
SET last_system_migration = CASE last_system_migration
WHEN '_20260217_110409_project_settings'
THEN '_20260217_110409_workspace_settings'
WHEN '_20260307_000638_project_timestamps'
THEN '_20260307_000638_workspace_timestamps'
ELSE last_system_migration
END;
-- Rewrite historical audit vocabulary
UPDATE monospace_audit.audit_logs
SET action = CASE action
WHEN 'user.join_project.v1' THEN 'user.join_workspace.v1'
WHEN 'user.remove_project.v1' THEN 'user.remove_workspace.v1'
ELSE action
END
WHERE action IN (
'user.join_project.v1',
'user.remove_project.v1'
);
UPDATE monospace_audit.audit_logs
SET payload = jsonb_set(
payload - 'project_roles',
'{workspace_roles}',
payload -> 'project_roles',
true
)
WHERE payload ? 'project_roles';
-- Rename workspace metadata/data schemas and repair persisted metadata
DO $migration$
DECLARE
item RECORD;
old_data TEXT;
new_meta TEXT;
new_data TEXT;
BEGIN
FOR item IN
SELECT nspname AS old_meta
FROM pg_namespace
WHERE nspname LIKE 'monospace\_project\_%\_meta' ESCAPE '\'
ORDER BY nspname
LOOP
old_data := left(item.old_meta, -5) || '_data';
new_meta := regexp_replace(
item.old_meta,
'^monospace_project_',
'monospace_workspace_'
);
new_data := regexp_replace(
old_data,
'^monospace_project_',
'monospace_workspace_'
);
IF octet_length(new_meta) > 63 OR octet_length(new_data) > 63 THEN
RAISE EXCEPTION
'Workspace schema name exceeds PostgreSQL 63-byte limit: % / %',
new_meta,
new_data;
END IF;
IF to_regnamespace(new_meta) IS NOT NULL
OR to_regnamespace(new_data) IS NOT NULL THEN
RAISE EXCEPTION
'Target workspace schema already exists: % or %',
new_meta,
new_data;
END IF;
EXECUTE format(
'ALTER SCHEMA %I RENAME TO %I',
item.old_meta,
new_meta
);
IF to_regnamespace(old_data) IS NOT NULL THEN
EXECUTE format(
'ALTER SCHEMA %I RENAME TO %I',
old_data,
new_data
);
END IF;
EXECUTE format(
'UPDATE %I.monospace_namespaces
SET db_name = CASE db_name
WHEN $1 THEN $2
WHEN $3 THEN $4
ELSE db_name
END
WHERE db_name IN ($1, $3)',
new_meta
)
USING item.old_meta, new_meta, old_data, new_data;
-- Rename persisted entitlement values
EXECUTE format(
$sql$
UPDATE %I.monospace_policies
SET content = replace(
replace(
content::text,
'"projectMembers:',
'"workspaceMembers:'
),
'"projectSettings:',
'"workspaceSettings:'
)::jsonb
WHERE content::text LIKE '%%"projectMembers:%%'
OR content::text LIKE '%%"projectSettings:%%'
$sql$,
new_meta
);
END LOOP;
END
$migration$;
COMMIT;
The resource you create inside an organization is now a workspace. In the Studio, "Project" becomes "Workspace" everywhere — the navigation selector, settings, members, and invitations. The change is uniform on the wire:
- REST and MCP — the workspace-scoped path is
/api/{workspace}/…(items, assets,openapi,mcp), and the system endpoints move from/api/system/projectsto/api/system/workspaces. - SDK —
createClienttakes aworkspaceoption instead ofproject, and the generator config inmonospace.config.tsusesworkspacetoo. - Fields and payloads —
projectIdbecomesworkspaceId, and invitationproject_rolesbecomeworkspace_roles. - Entitlements —
projectbecomesworkspace,projectMembersbecomesworkspaceMembers, andprojectSettingsbecomesworkspaceSettings. - Audit log —
user.join_project.v1anduser.remove_project.v1becomeuser.join_workspace.v1anduser.remove_workspace.v1.
See Organization for the resource hierarchy and REST API for the request shape.
Shipped byRijk van ZantenAudit logs for authentication events
Monospace now records authentication activity in the audit log: successful and failed logins, logouts, token refreshes, and password reset requests, confirmations, and changes. Each entry captures the actor, their IP address, and the outcome — and failures are recorded without revealing whether an account exists.
See Audit Logs for the full list of actions and how to query them.
Shipped byMaxence Maire- The PostgreSQL connector supports AWS IAM authentication for RDS and Aurora: set an
aws_iamobject (with at least aregion) on the connection instead of a password, and each connection mints a short-lived token. It is configured in the connector config only — there is no Studio UI for it yet. That will come in a subsequent release. - The Studio shows the server's maximum file upload size in the upload UI, and over-limit uploads fail with a clear message instead of a generic error.
- Paginated Studio views use the engine's
meta.totalCountfor exact total-item counts instead of estimating from the last page. - Hide or show a collection directly from its actions menu in the Data Model.
- Listing layouts appear in a consistent order — Table, then Cards, then Calendar — in the view options.
- A to-many relational filter must use exactly one of
_some,_every, or_none; invalid combinations are rejected with a clear message. - When no AI provider is configured, anyone who can set up AI sees a "Set Up AI Assistant" prompt instead of an empty panel.
_eqand_neqon a JSON field compare by JSON value instead of raw text — object key order is ignored, while array order and value types are significant — across PostgreSQL, MySQL, and MariaDB.- An expired session cookie no longer blocks login, invite signup, or password reset; the request proceeds instead of failing with an invalid-token error.
- Introspecting an unknown data source returns a 404 with a clear message instead of a 500.
- The AI chat panel shows an error when a response stream fails, instead of failing silently.
- Editing a date or date-time field in a form enables the Save button.
- The calendar layout loads events for the exact week or day in view, including multi-day events and events that span a month boundary.
- In-browser filtering and sorting compare date-time values by their actual instant and numeric fields by value, so those columns behave correctly.
- File preview text and action buttons are legible over the dark-theme overlay.
- Long links wrap instead of overflowing narrow containers such as the code panel.
API request panels and AI tool approvals
This release adds an API Request code panel to every collection, a tool-approval workflow for the AI assistant, many-to-many file fields, and a total-count option for read queries.
API Request Code Panel
Reproducing a Studio view in code meant hand-writing the request. Now every content collection has an API Request panel that turns what you're viewing — your fields, filter, sort, and pagination, or the open item and its values — into ready-to-run SDK and cURL snippets you can copy in one click. Open it from the code button in the header; it docks beside your content on wide screens and slides in as a drawer on narrow ones.

See SDK and REST API for client setup.
Shipped byGuillaume Chau
Shipped byHugo Torzuoli
Shipped byHannes KüttnerAI Assistant Tool Approvals
The AI assistant used to run deletes and schema changes without a checkpoint. Now it pauses first: deleting items or changing the schema surfaces a Tool approval required panel where you approve, deny, or send back a different instruction. Tool inputs and outputs render as readable YAML instead of raw JSON, and approval never grants access beyond your own permissions.

See AI for the assistant and its tools.
Shipped byRijk van ZantenMany-to-Many File Fields
A File field held a single file, so attaching several meant modeling a junction collection by hand. Now picking the Multiple Files option when adding a File field creates a many-to-many relation to your asset library from just a field name — the junction collection is generated and hidden for you, and attached files show as thumbnails in the item form and table.
See Data Model for fields and relations.
Shipped byMarc BackesTotal Count for Read Queries
Getting a total count used to mean a second query — or fetching every matching item just to count them. Now you can pass a meta option with totalCount on a read query to get the total number of matching items — ignoring limit and offset — alongside the data in one request. It's a top-level option; nested relation reads don't accept it.
See Get the Total Count for the request and response shape.
Shipped byKirill Bulatov- UUID fields can default to an engine-generated random UUID, in either v4 (random) or v7 (time-ordered) form.
- Change a relation's on-delete and on-update referential actions with a migration, instead of only when the relation is first created.
- The field type picker is sorted alphabetically by its translated label.
- New fields adopt their type template's preferred type, so a JSON-template field is created as JSON instead of text.
- Icon and color inputs on select options can be cleared again, and color inputs gain a "Remove color" action.
- Hiding or re-adding a column in the table layout updates the header and grid immediately, without a reload.
- Markdown content renders with the correct text colors in dark mode.
- Creating a custom page connects it to its space.
- The interface color mode follows your saved appearance preference on load.
- The display-template input stays open when a template segment contains a
/. - Onboarding consent links to the End User License Agreement.
- Edits to items in a repeater field register as you type instead of being dropped.
- The secondary header no longer overlaps content when a long description wraps.
Stricter query validation and access fixes
This release tightens API query validation, makes the policy "All" access override grant full access, and fixes Studio issues across permissions, filtering, and the schema visualizer.
Stricter Query Validation
Invalid field selections on a primitive field used to be accepted silently. Now the query engine rejects them: selecting nested subfields on a primitive field — or passing arguments to one — is rejected as an invalid query. Nested selections and arguments still work on relation fields, where they apply.
See Field Selection for valid field, relation, and nested-query syntax.
Shipped byMaxence MaireAccurate "All" Access Override
A filter left on a single action used to survive the "All" access override, so "All" didn't actually grant full access. Now, in the policy editor, a collection's "All" override grants genuine unrestricted access — it clears any custom per-action filters and opens create, read, update, and delete together.
See Access Control for how policies and collection permissions combine.
Shipped byFlorian Wachmann- Permissions load reliably right after you create the first project on a fresh instance, instead of showing a "couldn't load your permissions" error.
- Newly created collections are arranged automatically in the schema visualizer instead of stacking in the corner.
- The organization dashboard shows a project you just created without a manual refresh.
- The Policies page no longer occasionally loads blank until you refresh.
- Numeric values in an "is one of" or "isn't one of" filter are preserved instead of dropped.
- The permission rules editor stays usable on narrow screens, scrolling sideways instead of clipping the delete action.
A refreshed Studio, onboarding, and native JSON
This release refreshes the Studio, adds guided onboarding and a project connection screen, moves JSON fields to native JSON, introduces branded data source presets and permission-aware controls, and ships configurable CORS, query-parameter authentication, and anonymous usage telemetry.
Refreshed Studio Design
The Studio interface is restyled from the chrome inward. Project headers, the sidebar, and footers use consistent heights, spacing, and typography. Breadcrumbs now show the item you're viewing on a detail page, and the collection back control is labeled with the collection name.

Shipped byHugo Torzuoli
Shipped byReza Baar
Shipped byFlorian WachmannOnboarding
New instances walk you through first-run setup. When no user exists yet, Monospace prompts you to create the first administrator — name, email, password, and terms acceptance. When an administrator was provisioned automatically, you confirm your details and accept the terms the first time you sign in.

Shipped byMarc BackesConnect to Your Project
Connecting a client to a project used to mean assembling the base URL and minting a key by hand. A new connection screen now gathers everything in one place: tabbed setup instructions for the SDK, MCP server, and REST API, an API key generated on the spot — personal or through a service account — and deep links to add the project's MCP server to supported tools.

See SDK, MCP, and REST API for client setup.
Shipped byMarc BackesNative JSON Fields
JSON fields used to travel as encoded strings you had to parse and re-stringify yourself. Now they use native JSON end to end: the API returns and accepts raw JSON, and in the Studio new JSON fields default to the native JSON type, edit in a pretty-printed code editor, and display as compact single-line JSON in tables.
{ filter: { metadata: 2 } } is rejected; use { filter: { metadata: { _eq: 2 } } }.
Shipped byFlavian Desverne
Shipped byGuillaume Chau
Shipped byHannes KüttnerBranded Data Source Presets
The data source picker listed only raw database engines. Now it opens on a branded connector picker: alongside PostgreSQL, MySQL, MariaDB, and SQLite, you can pick managed providers like Neon, Aiven, PlanetScale, and Aurora — each with its own name, logo, and setup notes. The preset is display metadata; the underlying connector still determines how the source connects.

See Connectors for supported databases.
Shipped byHannes KüttnerPermission-Aware Studio
The Studio didn't reflect your permissions — it showed controls and navigation you couldn't actually use. Now it reflects them throughout: controls you can't use are disabled with a tooltip explaining why, role and policy pickers list only the values you may assign, and navigation entries you can't access are hidden. Opening a restricted page by URL redirects you to one you can reach.
Shipped byHannes KüttnerDedicated Project Schemas
User collections used to share the public schema, where separate projects could collide. Now each project uses two dedicated schemas on the system data source: monospace_<project>_meta for system metadata and monospace_<project>_data for the collections you create. When a data source exposes more than one namespace, the Add Collection form also lets you choose which namespace a new collection belongs to.
monospace_<project> is renamed to monospace_<project>_meta, and user collections move from public into monospace_<project>_data. Back up your database before updating.
Shipped byFlavian Desverne
Shipped byMarc BackesConfigurable CORS
Browser apps on another origin couldn't call your API. Now the engine can send CORS headers so they can. CORS is off by default — enable it with MONOSPACE_CORS__ENABLED and set the allowed origins with MONOSPACE_CORS__ORIGIN.
See CORS for the full configuration.
Shipped byHannes KüttnerAccess Tokens in Query Parameters
Passing an access token used to require the Authorization header. Now you can pass it as an access_token query parameter too, alongside the header and the session cookie — for clients that can't set request headers. Sending more than one of these at once is rejected with a 400.
See Authentication for all token sources.
Shipped byRijk van ZantenAnonymous Usage Telemetry
Monospace sends anonymous usage telemetry to guide development. Pings carry a random install ID, the version, a configuration snapshot, and operation counts — never credentials, connection details, or your data. Disable scheduled telemetry with MONOSPACE_TELEMETRY__ENABLED=false. Instance-owner details captured during onboarding sync separately; opt out with MONOSPACE_INSTANCE_OWNER_SYNC_ENABLED=false.
See Telemetry for the opt-out variables.
Shipped byHannes Küttner
Shipped byBram Geron- Choose the engine log format with the new
MONOSPACE_LOG_FORMATvariable (compact,full,pretty, orjson); it defaults tojson. - Listing views are shared across users, with each person's filter, search, and layout changes saved automatically and a "Save for everyone" action to publish them.
- The Calendar layout reopens on the date and view you were last using.
- Auto-generated many-to-many junction collections are hidden from content navigation by default.
- Data model collections use list cards, matching the data sources list.
- The organization projects dashboard shows an empty state with a create action when you have no projects.
- The add-source form names the missing fields when a pasted connection string is incomplete.
- Many-to-many relation displays link to the related item instead of the junction record.
- Deleting the file you're viewing redirects to the asset listing instead of leaving an empty panel.
- Schema migrations normalize their operation order, so they apply regardless of how the operations are listed.
- Custom detail pages load the item from the URL, so the form opens populated.
- Data table rows with taller content render at full height without clamping.
- CA certificate and mutual TLS settings reach the engine for PostgreSQL, MySQL, and MariaDB sources.
Single sign-on, MCP, and the AI assistant
This release adds single sign-on, an MCP server for AI agents, audit logging, MySQL and MariaDB data sources, and an in-Studio AI assistant.
Single Sign-On
Let members sign in with your organization's identity provider instead of a Monospace password. Set up Google, GitHub, Microsoft Entra, Okta, and other OAuth 2.0 providers from Settings → Sign-in Providers — common providers come with presets.

See Configure SSO to connect a provider.
Shipped byReza Baar
Shipped byFlavian DesverneMCP Server
Connect AI agents to your project through a Model Context Protocol server. Each project exposes its own endpoint at /api/{project}/mcp over streamable HTTP. Agents authenticate with an API key and can query, create, update, and delete items, inspect and modify the schema, and list data sources. Every call runs under the permissions of the key you connect with.

See Configure MCP for setup and client configuration.
Shipped byRijk van ZantenAudit Logs
Monospace now records key activity — user and account changes, invitations, project membership, and schema migrations — to an audit log. Each entry captures who made the change, the outcome, and when it happened. Administrators can read and filter the log through the system API.

See Audit Logs for the event catalog and how to query them.
Shipped byMarc Backes
Shipped byFlavian DesverneMySQL & MariaDB
Connect MySQL and MariaDB databases as data sources, alongside PostgreSQL. Add a connection from Data Model → Data Sources using the connection parameters or a connection string, with optional TLS.
See MySQL and MariaDB for connection options.
Shipped byBram GeronAI Assistant
Chat with an AI assistant directly in the Studio. It can query your data, create, update, and delete items, and read or change your schema — all under your own permissions. Configure an AI provider under Settings → AI.

See AI for the assistant and the MCP server.
Shipped byRijk van Zanten- Assign an organization role when inviting a member.
- Set fields to default to the current date or the acting user.
- Filter for empty or non-empty values with the
_nulloperator. - Control where nulls appear in sorted results with
NULLS FIRSTandNULLS LAST. - Pick date ranges with a new date range picker.
- Expand rows in data tables to view more detail.
- Preview images inline with image quick look.
- Data table columns auto-size to their content, up to a maximum width.
- The last-used sign-in method is highlighted on the login screen.
- Refreshed email templates to match the sign-in screen.