Skip to main content
These examples assume an authenticated active saved profile with the intended organization and project. Confirm it with tp context show before running commands. Add root --json before the command when machine parsing needs JSON output; use root --profile <name> only to override the active profile.

CLI context and preparation

Use the installed tp --help and tp apps publish --help when checking version support. Select the intended profile, organization and project through the usual global CLI options; do not copy credentials into the source tree. Examples below assume that context is already selected. The current publication API requires a companion HTML Dynamic UI in the same project. Create or select it with tp dynamic-ui or client.canvas.dynamic_ui. It is an access/resource anchor; the container provides the actual app UI:
Use the returned uiId as --ui-id. Inspect the returned mapping rather than guessing an ID. Provision needed Tables with tp db tables create --body @table.json or reuse a suitable existing Table. Do not change existing column contracts to fit an unrelated demo.

Publish source or an existing image

Generate a UUID once for a new publication; retain it before submitting. A wait limit or temporary transport error does not establish that a build failed. Resume with the same source, options and --request-id; inspect the recorded state before creating another request. --wait 0 advances one step without polling. Do not automatically resubmit an operation explicitly reported as terminally failed. For a prebuilt image replace --source with --image registry.example/projects/p4/apps/my-app@sha256:<digest> using the actual organization Registry address. tp registry push returns an immutable digest when pushing from a Docker-capable environment. Source publication combines remote build, push and deployment; an Agent Workspace does not need Docker-in-Docker. The compressed context is limited to 50 MiB. The CLI archive does not interpret .dockerignore: in Git it includes tracked files and nonignored untracked files, subject to built-in exclusions for common credential/cache paths. Use .gitignore for local-only files and inspect tracked files separately. Outside Git, stage a dedicated source directory containing only intended build inputs. Keep .dockerignore for Docker’s own context handling. Build the production frontend in a Docker stage rather than uploading node_modules. Include a wheel only when needed by the app; do not embed package-feed passwords in the Dockerfile. Optional SDK permissions:
  • Repeat --table-read / --table-write for exact Table IDs.
  • --lakehouse-read allows the delegated read-only statement API for the project.
  • Repeat --project-permission for supported Canvas, Flow or Module read scopes; inspect CLI help for the current accepted values.
For updates, inspect tp apps show my-app, then publish using a new request UUID and --replaces "$OLD_RELEASE". Use --replaces-stopped only if that exact release is stopped. --replace-current is a convenience for the initial submission; retain the resolved previous release for retries. Stop an exact release with:

Canvas application page

Use the existing configured SDK client to create a dedicated app page:
Use the returned page ID in /canvas/<page-id> on the selected TP host. For an existing HTML-only app the source is {"kind": "dynamic-ui", "uiId": "<ui-id>"}. A dashboard/document embedding instead uses a widget of kind hosted-app with config: {"appId": "my-app"}. Dedicated application pages have no widget frames or document blocks.

Backend Python SDK

Install the released ThinkPlatform client available in the target environment. The private ThinkPlatform package also includes the SDK. Keep imports independent of Agent/Flow runtime modules.
TABLE_ID is app configuration and must match the declared permissions. The headers include a short-lived invocation handle and bound org/project; retain neither headers nor client in global state or background jobs. The SDK routes via the platform-injected broker. The application receives no TP user access token. Use tp.db.rows.create(TABLE_ID, values) and tp.db.rows.update(TABLE_ID, row_id, values) for writes, following the installed method signatures. For a project Lakehouse read:
Poll within the current authenticated request or make another authenticated app request; use the returned statement ID and inspect its status. SQL result values follow the native API’s representation, which may contain numeric strings. Read-only Lakehouse permission does not allow SQL writes, and SDK method existence does not imply that the delegated transport admits that operation.

Verify the delivered app

Verify publication readiness, launch through TP, the requested app action, and persisted readback after reload. For data apps include a denied operation outside the declared resource scope when a suitable test exists. Report separately any untested multi-user or revocation scenario; one successful operator request does not prove the user’s app invocation path.