All docs

Hand-build an app

Goal: without depending on “create from conversation”, using only this directory’s docs + a template walkthrough, hand-build a workspace app you can open, click, and optionally fet

Source docs/en/site/sdk-appsdk-build.md

Goal: without depending on “create from conversation”, using only this directory’s docs + a template walkthrough, hand-build a workspace app you can open, click, and optionally fetch data. Suggested reading order: README.


0. What you will build

Pick one of two paths:

PathResultMust-read
A. Minimal notebookNew on top, list below, can deleteApp UI description · App package layout
B. Do work + history (simplified profile style)Form triggers a script; list shows resultsPlus App actions · App data pipeline

Complex visual operations console → read App views first; you should usually take pluginsdk.


1. Prep

  1. Local or test Cadau can open, and you are in a workspace.
  2. You know the runtime app directory (after create app):

{RUNTIME_DIR}/workspaces/{workspaceId}/apps/{appSlug}/

  1. If you will fetch: the workspace already has a data connection and usable predefined queries.
  2. After editing files, refresh the app page; custom scripts take effect on the next invoke (do not start a conflicting backend).

You can also use the “app-development assistant” to change a draft then publish; hand-editing the pack and the assistant change the same file conventions.


2. Path A: minimal notebook (30 minutes)

2.1 Create the shell

On the apps desktop, create a blank/notes-style app from a template, or copy an existing minimal pack. Confirm you have app.json, data/app.db, logic/handlers.py (may be a stub).

2.2 Write app.json

Requirements:

  • version: 1
  • ≥1 entities (fields have label/type)
  • views: one form (mode: "create") + one list
  • No custom actions (unless you are about to do path B)

Full field rules: App UI description §7 notes example.

2.3 Mental validation list

  • Entity names, field names: lowercase + underscore
  • form/list entity points at a real entity
  • List columns use existing field names

2.4 Verify

Open the app → submit one row → it appears in the list → delete (if allow_delete is not off). The whole path is built-in CRUD; handlers need not implement business.


3. Path B: add a “do work” action

On path A, add “input params → script → (optional) attachment/history”.

3.1 Change the UI description

  1. Add an actions item: id, label, impl: "script", params (source of form controls).
  2. Add an action_form to views, action = that id.
  3. If you want history: add fields such as status, upload_id on the entity; keep list columns in sync.

Note: action-form controls = actions[].params, not views[].fields.

3.2 Change logic/handlers.py

Implement handle with a branch for that action:

  • Validate params
  • Need fetch → ctx["platform"].query_run (or call your generate_*.py)
  • Need a report → save_upload, return upload_id
  • Need history → write ctx["app_db"]

Template-level notes: App actions.

3.3 Optional: pipeline fetch

  1. Prepare query_ids on the data connection.
  2. Add references/pipeline.json.
  3. Add logic/generate_*.py to run step by step.
  4. When you need a layout, add assets/*.html + scripts/assemble_*.py.

Details: App data pipeline. Walkthrough implementation: the workspace “employee profile” app pack, or the built-in template backend/internal/skillfromchat/bundled/employee-profile/.

3.4 Verify

  • Submit the action: success hint / error copy matches expectations
  • With upload_id: can open or download
  • List status and notes update
  • Intentionally wrong query_id: you should see a clear error or warnings, not a blank success

4. How “UI from a picture” lands in a hand-build

Picture contentWhat to do
Result-report samplePath B + HTML template (App views §4A)
Complex operations-console sampleDo not force the three views → pluginsdk
Only tweak an existing form/listChange app.json; or give the picture to the app-development assistant and describe intent

5. From-scratch checklist (complete app)

UI

  • [ ] Only list / form / action_form
  • [ ] Each action_form id is found in actions
  • [ ] Action-form fields are on params
  • [ ] User-visible copy is all in label

Pack

  • [ ] app.json is valid (check whether platform save/publish errors)
  • [ ] With script actions, handlers.handle covers every id
  • [ ] Scripts only access external data via the platform bridge
  • [ ] Templates/pipelines live in assets / scripts / references / logic

Fetch (if needed)

  • [ ] Predefined queries match the pipeline
  • [ ] Main-step failure has a clear error; optional steps go into warnings
  • [ ] Return value includes frontend-agreed fields

Experience

  • [ ] Can open from the apps desktop
  • [ ] Main path clicked through by hand
  • [ ] (Optional) whether conversation skills need a matching register action such as profile.register

6. Document map

QuestionDocument
How to write fields/viewsApp UI description
Why no layout, UI from a pictureApp views
What in the directory is requiredApp package layout
Code behind a buttonApp actions
Multi-step query and reportsApp data pipeline
Mechanism and HTTPWorkspace apps

7. Common stuck points

StuckWhat to do
Changed views[].fields and the action form did not changeChange actions[].params
Local py change seems not to take effectConfirm you edited the current workspace runtime pack; submit the action again
Validation “need at least one entity” but you only want a buttonKeep a placeholder entity + list/form, or reuse a history-table entity
Want a wizard overlay / multi-step UINot supported today → plugin, or split into several action forms