Development Workflow
A custom front-end is a C# library that the Transpose compiler transpiles into a JavaScript bundle. The Curiosity CLI uploads the bundle to a workspace, which then serves it instead of (or alongside) the default UI.
Prerequisites
Install both global dotnet tools:
dotnet tool install --global Transpose.Compiler
dotnet tool update --global Curiosity.CLI
Verify:
tps --help
curiosity-cli --help
The compiler must be 26.8.3806 or newer: that is the first version whose tps.json resource globs recurse into sub-folders, which is how the Curiosity front-end package ships its assets (see Assets that come from the package). Check what is installed with dotnet tool list --global.
1. Download the project template
Inside your workspace, go to Management → Interfaces → Download template. The zip contains:
- A .NET project referencing
Tesserae,Mosaik.FrontEnd.Core, and the Curiosity component package. - A
wwwroot/folder for static assets. Program.cswith a stubbedAppinitialization.
The template pins the Transpose version that matches your workspace — don't bump it manually unless you've upgraded the workspace too.
2. Build locally
dotnet build
Transpose emits the JS bundle into bin/Debug/netstandard2.0/tps/. That tps/ directory is the unit of deployment.
Assets that come from the package
The Curiosity front-end package (Curiosity.FrontEnd) carries the assets its components reference — icons, illustrations, animations, the variable web fonts and the favicon — embedded in the assembly, including everything in nested folders such as assets/img/icons/logos and assets/webfonts/monaspace. Your build extracts them into the tps/ output in the same layout, so an application consuming the package renders with the same icons and typography as the workspace's own UI.
Nothing arrives through MSBuild's copy-to-output any more: an asset that no project's tps.json declares does not reach the site. If your own project ships assets, declare them in its tps.json — a ** segment (tps/assets/img/**) picks up sub-folders and reproduces them in the output.
An older compiler silently drops the nested assets
Recursive resource globs need Transpose 26.8.3806 or newer. Older compilers read ** as * — .NET's own search patterns collapse it — so they match one directory, build without an error, and leave everything below it out of the bundle. The symptoms are broken icons wherever the package's components use them, missing illustrations, and text falling back to a system font because the @font-face sources 404.
Fix it by upgrading the compiler, then rebuilding:
dotnet tool update --global Transpose.Compiler
serve --watch compiles in process rather than through tps, so upgrade the CLI as well (dotnet tool update --global Curiosity.CLI) if you iterate that way.
3. Serve and iterate against a remote workspace
Use the CLI's serve command to host your local bundle while connecting to a running workspace (local or remote):
curiosity-cli serve -s http://localhost:8080 -p bin/Debug/netstandard2.0/tps
This:
- Serves the
tps/folder over HTTP. - Patches the served HTML so it loads your bundle instead of the deployed one.
- Forwards API calls — including server-sent events and WebSocket connections — to the workspace.
For this to work, the target workspace must allow CORS from the dev server. Set MSK_CORS to a list including http://localhost:5000 (or whichever port the CLI prints) and restart the workspace.
Compile and reload automatically
Pass --watch with the project instead of --path with its output, and the CLI compiles the project itself, serves what it produced, and rebuilds on every save:
curiosity-cli serve -s http://localhost:8080 -w .
The project's own sources and those of every project it references are watched, so editing a shared front-end library rebuilds the app too. After each rebuild the page reloads itself; a change confined to stylesheets swaps the CSS in without a reload, so the app keeps its state. A compile error leaves the previous build in place and prints the errors.
The compiler runs in process, so tps doesn't need to be installed for this path — and step 2's dotnet build becomes unnecessary while watching. See serve → Watch mode for the full option list.
4. Deploy
When the local iteration is done, upload the bundle:
curiosity-cli upload-front-end -s https://workspace.example.com -t $CURIOSITY_TOKEN -p bin/Debug/netstandard2.0/tps
Under the hood the CLI calls graph.UploadNewApplicationInterfaceAsync(path, autoPatch: false) — the same method you can invoke from a connector or admin script if you'd rather deploy the bundle as part of CI.
Flags you'll use:
| Flag | Default | Meaning |
|---|---|---|
-s |
- | Target server URL. |
-t |
- | An API token with permission to manage interfaces. |
-p |
pwd |
Local path to the tps bundle folder. |
-a |
false |
Auto-patch: rewrite asset URLs at upload time (set when assets live at a different prefix). |
-i |
false |
Ignore TLS certificate errors (dev only). |
Multi-node deployments
If the target workspace runs read-only replicas, upload once against the primary. The primary replicates the bundle to every replica automatically — no separate upload per replica.
5. Promote across environments
Treat the bundle as a build artifact:
- CI builds the bundle (
dotnet build -c Release) and uploads to dev. - On promotion to staging, re-run
curiosity-cli upload-front-endagainst the staging workspace. - After validation, promote the same artifact to production.
Don't rebuild between staging and production — upload the byte-identical bundle so the only variable is the target workspace's data and configuration.
Troubleshooting
| Symptom | Likely cause |
|---|---|
serve returns CORS errors |
MSK_CORS doesn't include the dev-server origin; restart the workspace after change. |
| Routes 404 after upload | Router.Register ran before the route was needed; check the App.DefaultRouting.Define() ordering. |
| Stale UI after upload | The browser cached the previous bundle. Hard reload, or bump the MSKWWWHash query string. |
tps: not found |
Add ~/.dotnet/tools to PATH. |
| Icons render broken and fonts fall back to a system font | Transpose compiler older than 26.8.3806, so the package's nested assets were left out. Run dotnet tool update --global Transpose.Compiler and rebuild. |
| Workspace says interface upload requires admin | The token used must have admin scope; create one under API integrations with Admin ticked. |