Appearance
ts app
Show and change one app as it is placed in a workspace — its title, how users sign in to it, who can use it and from where, and its license and seat reservation there.
Usage
text
ts apps <workspace> [--csv] [--no-trunc]
ts app <id>
ts app <id> <property>
ts app new --file=<path>
ts app set <id> <property> <value>
ts app set <id> --file=<path>
ts app delete <id> [--force]
ts app license <id> [--type=TYPE] [--seats=COUNT]
ts app reservation set <id> --group=GROUP --seats=COUNT [--start=TIME] [--end=TIME] [--days=DAYS]
ts app reservation clear <id>Description
ts apps needs a workspace; there is no default. Give it the workspace ID (the short name in URLs, such as acme) or its GUID, the same way ts workspace accepts one. The listing shows the title, the repository the app comes from, its version, its engine, and the app's ID — the ID is what every ts app action takes. An administrator of the workspace or the server sees every app in it; anyone else sees the apps they can use.
An app placement carries far more configuration than a flag list can express: login mode, license type, seat count and reservation, who can use it and from which locations, server tag rules, launch modes, supported platforms, sort order, and the app's own configuration document. So ts app treats it as a JSON document. ts app <id> prints the document the server holds, verbatim, and ts app set <id> --file= sends one back. The two shapes match, which is what makes the read-edit-write loop safe: nothing is dropped because this version of ts did not know a field existed.
What a Document Saves
The server saves a document in parts, each on its own route. set --file always sends the settings, and each other part only when the document changes it:
- Settings —
appTitle,loginMode, andserverTagRules. Server tag rules the document leaves out keep what is stored; an empty list removes them. - Access —
access, who can use the app and from where, printed only for an administrator.audienceiseveryoneoronlyTheseGroups, with the groups inincludeand the groups refused inexclude.network.scopeisanywhereoronlyTheseLocations, with named locations innetwork.includeandnetwork.exclude. Name a group or location as printed, or by its ID alone; a group can also be named by its name. - Launch modes —
launchModesandlaunchModeDefault. - License —
licenseType,licenseValue, andlicenseReservation, saved as one change. AlicenseReservationofnullclears the reservation.
The access policy is saved first, and only over the revision it was printed at, so a policy someone else saved since is refused rather than overwritten. If a later part is refused, the message says which parts were saved. The rest of the printed document — the config block, supportedPlatforms, sortIndex, and the icon — is read-only through this command; change those in the Administration site. A document that carries ipAccessRules entries is refused: where an app can be used from is the network part of access.
An administrator of the workspace can change everything a document saves, with two exceptions that take a Server Administrator: a new appTitle, because an app's title is shared by every workspace it is in, and a change to access.network.
One Field at a Time
For a single field there is a shorter path. ts app <id> <property> reads one field, and ts app set <id> <property> <value> writes one. The accessor changes one field and leaves the rest of the document as it was, while --file sends the whole document. Reach for the accessor for a one-field change — retitling an app, moving it to a different login mode — and for --file when you are editing structure or several fields at once. Passing a property and value together with --file is refused.
Property names are kebab-case and map to the document's camelCase key, so app-title addresses appTitle. Values are typed from the field being replaced — licenseValue stays a number, a boolean stays boolean — so you never have to know a field's wire type. A field that is currently null is the exception: there is nothing to infer a type from, so the value goes in as a string.
A structured field has no accessor form. access and config are objects and serverTagRules is an array, so all three are refused with a pointer at --file, and so is an unknown property. Both refusals happen before anything is written, so a typo cannot half-apply. After writing, the accessor reads the field back, so naming a read-only field such as sortIndex fails with the value the server kept rather than reporting success.
The accessor is a read-modify-write: it fetches the document, changes the one field, and sends the whole document back. That is safe here because the document round-trips untyped, so a field this version of ts does not know about is preserved rather than dropped.
Licenses and Reservations
license sets how seats are counted (--type) and how many there are (--seats); give either or both, and the one you leave out keeps its value. Changing either gives back every named seat, and a type other than concurrent-users clears the reservation. A seat count below the seats a reservation holds back is refused; lower the reservation first.
reservation set holds --seats of a concurrent-users license for the members of --group, from --start to --end each day in the server's time, on --days. The license needs at least one seat, and the reservation holds at least one and no more than the license has. reservation clear removes it. An administrator of the workspace can set both.
Adding and Removing an App
new attaches an existing app definition to a workspace and takes a Server Administrator. It reads workspaceId, the workspace's GUID, and appConfigId, the GUID of the app definition, then saves the rest of the document to the new placement as set --file does. A printed app names both, so changing workspaceId in a printed document places the same app in another workspace with its settings. If the rest of the document is refused, the app is still added and the message says so.
delete is a soft delete: the app stops appearing in the workspace but the row is retained, and ts has no undo for it. It prompts first unless you pass --force, and where there is no terminal --force is required rather than assumed. Adding and removing an app are both recorded in the audit trail, so ts audit will show who did it.
Options
| Flag | Description | Default/Values | Notes |
|---|---|---|---|
--file | JSON document to send. | Path, or - to read stdin | Required by new. set needs it only for the whole-document form. |
--force, -f | Delete without confirming. | Required when there is no terminal. | |
--type | How the license counts seats. | unlimited, named-users, concurrent-users, named-devices, concurrent-devices, concurrent-devices-per-user | license only. |
--seats | The license's seat count, or the seats a reservation holds back. | Whole number | license and reservation set; required by reservation set. |
--group | The group a reservation holds seats for. | Name or ID | reservation set only, and required there. Where two identity sources hold the name, write CORP\Staff. |
--start | When the reservation starts each day. | HH:mm; default 08:00 | reservation set only. The server's local time. |
--end | When the reservation ends each day. | HH:mm; default 17:00 | reservation set only. The server's local time. |
--days | The days the reservation holds. | Comma-separated, such as mon,wed,fri; default every day | reservation set only. Full day names are accepted too. |
--csv | Tab-separated output, nothing truncated. | ts apps only. | |
--no-trunc | Do not truncate columns. | ts apps only. |
Examples
bash
# What is published in this workspace?
ts apps acme
# The whole document for one app
ts app 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4
# Just one field
ts app 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 app-title
# Retitle it — one field, no file
ts app set 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 app-title "Acme CAD (2026)"
# Who can use it is structured, so it goes through the document round trip
ts app 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 > app.json
$EDITOR app.json
ts app set 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 --file=app.json
# Ten concurrent seats, two of them held for Staff on weekday mornings
ts app license 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 --type=concurrent-users --seats=10
ts app reservation set 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 --group=Staff --seats=2 \
--start=09:00 --end=12:00 --days=mon,tue,wed,thu,fri
# Attach an app definition to a workspace
echo '{"workspaceId":"9b336df2-2599-490b-99bc-e17f2bf50f66","appConfigId":"5d0f6a3e-8c21-4b7a-9e44-1f2a3b4c5d6e"}' \
| ts app new --file=-
# Full titles and IDs, nothing truncated
ts apps acme --csv
# Remove it from the workspace, unattended
ts app delete 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 --forcebash
# The document holds licenseType as a number, so the accessor sends a type
# name as text and the server refuses it. Name the type with ts app license.
ts app set 3f6a1c92-77b1-4a05-9a24-9b0c5f2e18d4 license-type concurrent-usersOutput
print emits the server's JSON document unchanged, so it pipes into jq and back into set. Under --format=json the document is nested as entity inside the standard result envelope, so a script that already parses the envelope reads result.entity — which is not the shape set --file consumes, so keep the default text output for round trips.
A single-field read prints the bare value — Acme CAD, not "Acme CAD" — so it drops straight into a shell variable. Under --format=json that value comes back in the envelope under the document's own key, result.appTitle.
Exit Codes
0 on success. -2 when ts apps is run without a workspace, when license names neither --type nor --seats or names an unknown type, when reservation set lacks --group or --seats or names a day that is not one, when set is given both a property and --file, and when the accessor names a structured field. -6 when the workspace, the app ID, or the --file path does not exist, and when a single-field read or write names a property the document does not carry. -5 when the account does not administer the workspace, or when a change takes a Server Administrator. -1 when the server refuses the document or the license, when an access policy was saved since you printed it, when a field written through the accessor does not read back, and when you decline the delete prompt.
Related Commands
- ts workspace — The workspace an app is placed in, and who can see it.
- ts channel — The channels that group apps within a workspace.
- ts link — Link shortcuts, which sit alongside apps in a workspace.
- ts group — The groups an access policy or a reservation names.
- ts location — The named locations an app's network condition names.
- ts repo — The repositories on the hub that apps are published from.
