CMS — Content Management
The CMS module manages collections of structured content — data records that forms, processes and other modules of the platform can reference.
What is a collection?
A collection is a set of records with a defined structure. For example:
- A list of cost centres
- A catalogue of approved suppliers
- A table of products or services
- The document types you accept
Navigating the CMS
- Go to Content → CMS in the sidebar
- You see the collections available to your tenant
- Click a collection to view and edit its records
Who can see and who can change
The CMS screen sits under Content, next to Knowledge Bases, and requires the Manager role or above — anyone without it is sent back to the dashboard. Changing things — creating collections, adding, editing or deleting records, and bulk loading — requires the same role.
The screen is restricted, reading is not
Not seeing the screen is not the same as not reaching the content. Anyone in the company who is signed in can read a collection's records by other routes — a running process, an AI agent, an integration — always limited by the collection's confidentiality level. That is deliberate: the agent and the process read the CMS on behalf of the flow, and that read has to stay open so the flow can look up reference tables without depending on the role of whoever started the instance. Whoever integrates will find the routes in REST API.
Confidentiality levels
Every collection carries a confidentiality level, chosen when it is created and changeable later:
| Level | Who can see it | Examples |
|---|---|---|
| Public | Any user in the tenant | Product catalogue, cost centres, municipality codes |
| Secret | Manager and administrator | Margins, commercial policy, price list |
| Top secret | Administrator only | Payroll, legal, board material |
A collection you are not allowed to see simply does not appear in the listing. Classified collections show a padlock tag on their card.
A manager cannot mark a collection as Top secret — that would create data beyond their own reach. The confidentiality selector only offers the levels you can read yourself.
The full matrix — including how an AI agent and a robot fit into it — is in Roles & Permissions.
Creating a record
- Open the collection you want
- Click New Record
- Fill in the fields of the collection's form
- Click Save
Editing and deleting records
- Use the edit button (pencil) next to the record to change it
- Use the delete button (bin) to remove it. The screen asks for confirmation, and the deletion is permanent: the record does not go to a bin and there is no undo
Large tables and AI agent lookups
Collections are the deterministic source the AI agent queries when it needs an exact value — reference tables with thousands of rows are the typical case. The lookup runs straight against the database, by exact equality on the record's fields: asking for code CAM-0042-P returns that record, wherever it sits in the table.
Because it is exact equality, the value has to be identical to what was stored — there is no partial, fuzzy or range search. If several fields are given in the same filter, all of them must match.
The agent also respects confidentiality levels: each agent has an access level of its own, configured by an administrator and Public by default. If the collection is more restricted than the agent's level, the agent answers that it does not have permission — instead of saying the data does not exist.
Collections that come from the platform
A global process can bring its own reference tables. When an agent looks a collection up, the platform resolves in this order:
- your tenant's collection, if one exists with that name;
- otherwise, the global collection that travels with the process;
- if neither exists, the agent answers that the collection does not exist.
Your collection replaces the global one entirely. If you create a collection with the same name as a global one, the agent uses only yours — records from the two are never mixed. That is the way out when your business's table differs from the one the process ships: instead of asking for an exception, you create your own and it takes precedence.
The choice is per collection, not per record
If you create your version, it has to be complete. The agent stops seeing the global table entirely, so a code that existed only there no longer exists for the agent.
Global collections are created and maintained by the platform administrator. A tenant administrator neither edits nor deletes them.
On the CMS screen they appear alongside your own, flagged as Global. You can open them and read their records, but there is no button to create, edit or delete — neither the collection nor its records.
While your own version of a global table exists, the global one does not appear in the listing: it does not apply to your agent, and showing it as available would be misleading. In its place, your collection displays the note "Overrides a global collection — see which", which opens the global one read-only. That is where you compare what the platform offers against what you created, before deciding whether to keep or drop yours.
Bulk loading
Entering tens of thousands of records one at a time through the screen is not viable. For tables that size there is the bulk load through the integration API, which takes the whole table at once. It requires the same Manager role or above, and whoever builds the call will find the routes and the limits in REST API.
One option of that load is worth knowing even if you never write the call, because it changes the outcome: give it a key field (code, for example) and reloading the same table updates the existing records instead of duplicating them. Without a key field everything sent is inserted, and the collection has to be emptied first to avoid duplicate rows.
Best practices for collections
Use the CMS when the data is looked up by an exact identifier. Product catalogues, cost centres, municipality codes, job title tables, system-to-system mappings. The agent queries by equality — it sends {"sku":"CAM-0042-P"} and gets that row back.
The counterpart is worth stating: the same data does not work in a Knowledge Base. Vector search retrieves by textual similarity, and neighbouring codes usually have nearly identical descriptions — "Blue t-shirt, size S" and "Blue t-shirt, size M" are practically the same text, and generic labels such as "Other" repeat across thousands of rows. Asking for a code would return the wrong row, with full confidence. The rule is: exact identifier → CMS; text that must be interpreted → Knowledge Base.
Field names are the query contract. The agent filters by the field name exactly as it was created. In a cost centre table, code and cost_center_code are not the same thing. Choose short, stable, predictable names, and avoid renaming later — the callers are agent instructions, which are not updated along with it.
Normalise value formats before loading. Lookups are exact equality, with no partial match and no approximation. In a municipality table, if half the rows hold 3550308 and the other half 35.503-08, half the lookups fail. Decide on one format — with or without punctuation, with or without leading zeros — and apply it to the whole table.
One collection per subject. A collection of job titles and one of salary bands, kept separate, are easier to reload and to classify by confidentiality than one generic collection with a "type" field — all the more so when the two carry different confidentiality levels.
Reload using a key field. With a key field set, reloading the same table updates records instead of duplicating them, and the collection is never incomplete during the operation. Without one you must clear it first — and during that window the collection answers "not found" for codes that do exist.
The data: type, case and whitespace all count
The comparison is literal. These are the most common ways an apparently correct load turns out not to be findable — all verified against the database:
| What is stored | What the agent looks for | Match? |
|---|---|---|
{"code": 1234} | {"code": "1234"} | no — a number is not text |
{"active": true} | {"active": "true"} | no — a boolean is not text |
{"center": "01 "} | {"center": "01"} | no — trailing space |
{"state": "sp"} | {"state": "SP"} | no — different case |
{"code": "1234"} | {"code": "1234"} | yes |
The number one trap is a code stored as a number. Spreadsheets convert 1234 into a number on their own and the collection becomes silently unqueryable. Codes are text even when they contain only digits — not least because leading zeros are lost along the way.
A record must answer, not merely identify
There is no join between collections: the agent receives the record that matched and nothing else. If the answer depends on data living in another collection, it never gets there.
// bad — identifies, but answers nothing
{ "code": 123, "desc": "Other" }
// good — the record explains itself and carries what will be asked
{
"code": "00123",
"name": "Marketing — events and sponsorships",
"group": "01 — Commercial expenses",
"owner": "Commercial Board",
"valid_from": "2026-01-01"
}Note the desc: "Other" in the bad example. It is a label that turns up often in reference tables and that, on its own, says nothing — to a person or to the agent. Carry the group and the owner alongside it: with only "Other" to work from, the agent writes its analysis without the group and without the owner.
Prefer flat records. Nested fields work, but they make querying and reading harder for the agent. One row per fact, fields at the top level.
"Not found" is an assertion
In a reference table, a missing row is not a missing answer: the agent concludes that the code does not exist and writes that into its analysis. That is why reloading with a key field matters more here than in other systems.
Using the CMS in forms
Form fields of the "Select" or "Search" type can be bound to a CMS collection. When the user opens the task, the collection's values appear as selectable options, always up to date.
TIP
The administrator decides which collections exist and which fields each one has. If you need a new collection, or a change to the structure of an existing one, talk to your administrator.