dsp-cli 0.1.1

AI-agent-friendly command-line interface for the DaSCH Service Platform (DSP)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
---
name: dsp-cli
description: Use when interacting with the DaSCH Service Platform (DSP) — listing projects, exploring data models, inspecting resource types and their fields. Prefer dsp-cli over manual DSP-API curl calls for any DSP read operation that fits a command.
---

# dsp-cli — agent quick reference

`dsp-cli` is an AI-agent-friendly command-line interface for the DaSCH Service Platform (DSP).
It abstracts DSP-API's verbose RDF surface into a small set of high-level verbs that match domain-expert vocabulary.

## Invocation

```bash
dsp <area> <noun-group> <verb> [--flags]
```

Locate the binary with `command -v dsp`. If not found, fall back to `$HOME/.cargo/bin/dsp`. If that is also missing, see *Installation* at the bottom.

`-v` / `--verbose` is a global flag on every command (`-v` = info, `-vv` = debug, `-vvv` = trace; `RUST_LOG` overrides). Diagnostics go to stderr; stdout stays data-only.

## When to use this CLI

Use `dsp` when the task is a per-command, agent-readable operation against DSP — e.g. "list projects on the test server", "describe a data model", "find a resource type".
Prefer it over direct DSP-API calls (which return verbose RDF/JSON-LD) and over `dsp-tools` (which is file-driven and bulk-oriented).

Do not use `dsp` for: bulk data ingestion, file-based project schema round-tripping, or anything where the natural input/output is a declarative file in `dsp-tools`' format.
Those belong to `dsp-tools`.

## Top-level groups

- `dsp auth ...`   — authentication management (login, set-token, status, logout, token)
- `dsp vre ...`    — Virtual Research Environment operations
- `dsp docs ...`   — embedded end-user documentation

## v1 commands (VRE)

```bash
# Projects
dsp vre project list [--filter <text>]                            --server <s>
dsp vre project describe -p <shortcode|shortname|iri>             --server <s>

# Project dump (download a full project archive)
dsp vre project dump -p <shortcode|shortname|iri>                 --server <s>
                     [--skip-assets] [--output <path>] [--force]
                     [--cleanup] [--timeout <seconds>]
                     [--replace [--discard-other-project] | --delete]
                     [--format <f> | -j | -l]

# Data models (within a project)
dsp vre data-model list       [--include-builtins] [--filter ...]  --project <p> --server <s>
dsp vre data-model describe   --data-model <name-or-iri>           --project <p> --server <s>
dsp vre data-model structure  --data-model <name-or-iri> [--include-builtins]
                                                                   --project <p> --server <s>

# Resource types (within a data model)
dsp vre resource-type list      [--include-builtins] [--filter ...] --project <p> --data-model <m> --server <s>
dsp vre resource-type describe  --resource-type <name-or-iri>       --project <p> --data-model <m> --server <s>

# Resource instances (within a project)
dsp vre resource list  --resource-type <name-or-iri> [--data-model <m>]
                       [--page N | --all] [--filter <text>] [--order-by <field>]
                       [--format <f> | -j | -l] [--columns ...] [--no-header | --header-only]
                       -p <shortcode|shortname|iri> --server <s>
dsp vre resource describe  --resource <internal-iri>
                           [-p/--project <shortcode|shortname|iri>]
                           [--values]
                           [--format <f> | -j | -l] [--columns ...] [--no-header | --header-only]
                           --server <s>
```

`describe` on a resource-type returns the full field list (name, value-type, cardinality, label).
It is the v1 leaf — agents should not need to drill further to inspect a data model's structure.

`dsp vre project describe` fetches the full detail of a single project: shortcode, IRI, status (active/inactive), keywords, description,
and a data-models summary (count + names sorted alphabetically).
`--project` / `-p` accepts a shortcode, shortname, or IRI. Authentication is optional — public project metadata is returned without a token. Example:

```bash
dsp vre project describe --project 0801 --server https://api.dasch.swiss
dsp vre project describe -p beol       --server prod     # same project, by shortname + shortcut
dsp vre project describe -p 0801 -s prod -j              # JSON output
```

`dsp vre data-model list` lists the data models of a single DSP project. Columns (`--columns`): `name`, `iri`, `label`, `last_modified`, `is_builtin`.
Built-in platform data models (`knora-api`, `standoff`, `salsah-gui`) are omitted by default; pass `--include-builtins` to include them.
`--filter` matches case-insensitively against name and label. Authentication is optional — public project data models are returned without a token. Example:

```bash
dsp vre data-model list --project 0801 --server https://api.dasch.swiss
dsp vre data-model list -p beol        --server prod            # same project, by shortname + shortcut
dsp vre data-model list -p 0801 -s prod --include-builtins -j   # JSON output including built-ins
```

`dsp vre data-model describe` describes one data model and summarises its resource-types —
the middle step of schema exploration (`data-model list` → `data-model describe` → `resource-type describe`).
`--data-model` accepts the short name (e.g. `beol`, case-insensitive) or the full IRI.
Prose shows the data-model's label, IRI, and last-modified date, then an aligned `name  label` list of its resource-types under a `Resource-types (N):` header —
the `name` of each is what you pass next to `resource-type describe`.
JSON returns a single object with a `resource_types` array (each carrying `name`, `iri`, `label`).
It does **not** list the resource-types' fields (use `resource-type describe` for those) nor the link relations between resource-types.
Authentication is optional — public project schemas are returned without a token. Example:

```bash
dsp vre data-model describe --project 0801 --data-model beol --server https://api.dasch.swiss
dsp vre data-model describe -p beol --data-model beol -s prod          # by shortname + shortcut
dsp vre data-model describe -p 0801 --data-model beol -s prod -j       # JSON output
```

`dsp vre resource-type list` lists the resource-types defined in one data model of a project. Columns: `name`, `iri`, `label`, `is_builtin`.
By default only resource-types defined in the project's own data model are shown; `--include-builtins` appends the four user-instantiable platform built-ins
(`Region`, `AudioSegment`, `VideoSegment`, `LinkObj`) to the output — these are the DSP base resources a researcher can use without declaring them in a project schema.
`--filter` matches case-insensitively against name and label. Authentication is optional — public project schemas are returned without a token. Example:

```bash
dsp vre resource-type list --project 0801 --data-model beol --server https://api.dasch.swiss
dsp vre resource-type list -p beol --data-model beol -s prod                              # -p = project shortname, --data-model = data-model name, -s = server shortcut
dsp vre resource-type list -p 0801 --data-model beol -s prod --include-builtins -j        # JSON output including built-ins
```

This command does **not** return the field list for each resource-type — use `resource-type describe` for that.

Caveats:
- `--include-builtins` appends exactly the four user-instantiable built-ins listed above.
  The deprecated `knora-base:Annotation` built-in is **not** listed even with `--include-builtins`  in current DaSCH tooling, annotation-style resources are expressed as `Region`, `AudioSegment`, or `VideoSegment`.
- Naming a built-in platform data model (e.g. `knora-api`) directly as `--data-model` is **not supported in v1**  the command resolves the data model via the project's own data-models, which excludes built-in platform data-models.
  Use `--include-builtins` to see the four instantiable built-ins regardless of which project data model you are inspecting.

`dsp vre resource-type describe` is the v1 leaf and the final step of the schema-exploration chain: `data-model list` → `data-model describe` → `resource-type describe`.
It returns the full field list for a single resource-type.

**Full signature:**
```bash
dsp vre resource-type describe \
  -p <shortcode|shortname|iri> \
  --data-model <name-or-iri> \
  --resource-type <name-or-iri> \
  [--include-builtins] \
  [--format <f> | -j | -l] \
  --server <s>
```
`-p` is a short alias for `--project`. `--resource-type` accepts the local name (e.g. `manuscript`, case-insensitive) or the full IRI.

**What it shows:**
- A header block: `Resource-type:`, `Label:` (when present), `Extends:` (project superclass local name — the inner-project inheritance hint, comma-separated when multiple),
  `Representation:` (e.g. `still-image` — only when the resource-type is an asset type), `IRI:`, `Data-model:`.
- `Fields (N):` — an aligned table of every project-defined field: `name`,
  `value-type` (`text`, `integer`, `decimal`, `boolean`, `date`, `time`, `uri`, `color`, `geoname`, `list-item`, `link → TargetType`, `still-image`, …),
  **cardinality** (`1` exactly-one / `0-1` optional-single / `0-n` optional-repeatable / `1-n` required-repeatable), `label`,
  and a `[from <dm>]` tag for fields whose definition lives in a sibling data-model of the same project.
- `--include-builtins` appends the platform fields every resource-type inherits (arkUrl, hasPermissions, creationDate, isDeleted, rdfs:label, …) with a `(built-in)` marker.
  Off by default — the common case is project fields only.

**Auth:** auth-optional (bearer forwarded when present). Private project data-models require a valid token; public schemas are returned without one.

**What it does NOT do:** does not show the link-relation graph between resource-types — use `dsp vre data-model structure` for that (see below).
For the field inventory of all resource-types at once, use `data-model describe` (name + label summary) combined with individual `resource-type describe` calls.

Example:
```bash
dsp vre resource-type describe -p 0803 --data-model incunabula --resource-type page --server prod
dsp vre resource-type describe -p 0801 --data-model beol --resource-type manuscript --server prod -j
dsp vre resource-type describe -p 0801 --data-model beol --resource-type manuscript --server prod --include-builtins
```

`dsp vre resource list` lists the resource instances of a specific resource-type within a project.
This is the first instance-side read command — it returns actual data records, not schema definitions.

**Full signature:**
```bash
dsp vre resource list \
  -p <shortcode|shortname|iri> \
  --resource-type <name-or-IRI> \
  [--data-model <name-or-IRI>] \
  [--page N | --all] \
  [--filter <text>] \
  [--order-by <field>] \
  [--format <f> | -j | -l] \
  --server <s>
```
`-p` is a short alias for `--project`. `--page` and `--all` are mutually exclusive.

**Resource-type addressing (how `--resource-type` is resolved):**
- **Full IRI** (value contains `://`) — used directly; the data-model scan is skipped entirely.
- **Bare name** (no `://`) without `--data-model` — the command scans all data-models of the project (fetching each in turn) and matches the name case-insensitively.
  If the name appears in more than one data-model (ambiguous), the command exits with a usage error listing the conflicting data-models
  and suggesting `--data-model` to narrow the scope.
- **Bare name with `--data-model`** — only the specified data-model is scanned; resolves cross-data-model ambiguity.

**Pagination:**
- Default (no flag) — fetches page 0 (the first page).
- `--page N` — fetches the specified zero-based page.
- `--all` — fetches all pages in sequence (page 0, 1, 2, …) until the server reports no more results, and accumulates them into a single result.

**`--order-by <field>`:** sort results server-side in ascending order by a project-defined field.
`<field>` is either a field name (resolved to its field IRI by scanning the resource-type's schema) or a full field IRI
(value contains `://`; used directly without resolution — bypasses the schema lookup).
Ordering is ascending-only. Resources with no value for the field sort first.
Pass the full IRI for efficiency when it is already known (e.g. from `resource-type describe`).

**Output columns** (for `--columns`, `csv`, `tsv`, `lines`): `label`, `iri`, `ark_url`, `creation_date`, `last_modified`, `resource_type`.

The command uses the full resource representation, so creation and last-modification dates are included in the output.
`creation_date` is populated for every resource. `last_modified` is present for resources that have been modified after creation;
it is absent (empty in tabular formats, `null` in JSON) for resources that have never been modified.

**Pagination in JSON `_meta`:**
- Single-page mode: `_meta.page` (int) and `_meta.may_have_more_results` (bool).
- `--all` mode: `_meta.pages_fetched` (int) and `_meta.may_have_more_results` (always `false`).

**Filter disclosure:** because instance-side results may be silently filtered by permissions, every invocation appends a disclosure note:
- Anonymous: "results may be filtered; login to see private resources"
- Authenticated: "results limited to your permissions"

In prose, this appears on the footer line. In JSON, it appears as `_meta.note`. In `lines`/`csv`/`tsv`, it appears appended to the stderr disclosure line.

**Auth:** optional — public projects return resources without a token. Private projects or restricted resources require authentication.

**`--filter`:** matches case-insensitively against the resource label (client-side, after the server fetch).

Example:
```bash
dsp vre resource list -p 0801 --resource-type letter --server prod
dsp vre resource list -p 0801 --resource-type letter --server prod --all -j
dsp vre resource list -p 0801 --resource-type http://api.dasch.swiss/ontology/0801/beol/v2#letter --server prod
dsp vre resource list -p 0801 --resource-type letter --data-model beol --server prod --page 2
dsp vre resource list -p 0803 --resource-type page --server prod --order-by seqnum    # sort by field name
dsp vre resource list -p 0803 --resource-type page --server prod \
  --order-by 'http://api.dasch.swiss/ontology/0803/incunabula/v2#seqnum'              # full IRI bypass
```

`dsp vre resource describe` fetches the metadata envelope of a single resource by its internal IRI.
By default it returns only identity and admin metadata — label, resource-type, IRI, ARK URL, creation date, last-modification date, attached project, owner,
and two translated permission facets.
Pass `--values` to also include the resource's field values — in prose/json this *adds* a values section on top of the metadata envelope;
in tabular formats (`csv`/`tsv`/`lines`) it instead renders one row per value, replacing the metadata row (see below).
ARK-based addressing is not supported in v1; use the internal IRI (the `iri` column from `resource list`).

**Full signature:**
```bash
dsp vre resource describe \
  --resource <internal-iri> \
  [-p/--project <shortcode|shortname|iri>] \
  [--values] \
  [--format <f> | -j | -l] \
  --server <s>
```
`--resource` (required) is the internal IRI of the resource. `-p`/`--project` is optional; when supplied it acts as a cross-project guard —
the command fails with a usage error if the resource's attached project does not match the supplied project.
This is a safety check, not a filter: the resource is fetched by IRI regardless.

`--values` (optional, default off) extends the output with the resource's field values. Each field is shown with its human label (when resolvable), field name, and value(s).
A value's comment (a free-text per-value annotation, when the server set one) is also shown: always in prose (indented under the value) and json
(a `comment` key, present only when set); in tabular formats only via `--columns …,comment` (see below).
In **prose** and **json**, `--values` adds a values section on top of the metadata envelope (both are present).
In **tabular formats** (`csv`, `tsv`, `lines`), `--values` instead renders **one row per value**, replacing the metadata row entirely for that invocation
(omit `--values` to get the metadata row back). Tabular columns: `label`, `iri`, `field`, `field_label`, `value_type`, `value`, `comment`;
the compact default (no `--columns`) is `field, field_label, value_type, value` — the resource's `label`/`iri` and the value's `comment` are opt-in via
`--columns` since `label`/`iri` repeat identically on every row of a single-resource describe and `comment` is empirically rare.
Resolving field and list-item labels requires additional server requests (deduplicated; graceful degradation to local name or node IRI on failure).

**Output fields:**
- `label` — the resource's human label.
- `resource_type` — the local name of the resource-type (e.g. `page`).
- `iri` — the resource's internal IRI.
- `ark_url` — the ARK persistent identifier (present for most resources).
- `creation_date` — ISO-8601 timestamp of creation.
- `last_modified` — ISO-8601 timestamp of last modification; absent for resources never modified.
- `attached_project` — IRI of the project the resource belongs to.
- `owner` — IRI of the user who created the resource.
- `visibility` — translated facet: who can see this resource (`public`, `public (restricted view)`, `logged-in users`, `project members only`). Omitted when undeterminable.
- `your_access` — translated facet: what the calling user can do with this resource (`restricted view`, `view`, `edit`, `delete`, `manage`). Omitted when undeterminable.

**Output columns** (for `--columns`, `csv`, `tsv`, `lines`): `label`, `iri`, `resource_type`, `ark_url`, `creation_date`, `last_modified`,
`attached_project`, `owner`, `visibility`, `your_access`.

**Filter disclosure:** as with `resource list`, every invocation appends a disclosure note because instance-side results may be silently filtered:
- Anonymous: "results may be filtered; login to see private resources"
- Authenticated: "results limited to your permissions"

**Auth:** optional — public resources are returned without a token.
The `visibility` and `your_access` facets depend on the caller's identity: anonymous callers see what the server grants them; authenticated callers see their effective permissions.

**See also:** `dsp docs concepts` for the `visibility`/`your_access` vocabulary.

Example:
```bash
dsp vre resource describe --resource 'http://rdfh.ch/0803/--6Esp4SVnGG1DBzFvYErw' --server prod
dsp vre resource describe --resource 'http://rdfh.ch/0803/--6Esp4SVnGG1DBzFvYErw' -p 0803 --server prod
dsp vre resource describe --resource 'http://rdfh.ch/0803/--6Esp4SVnGG1DBzFvYErw' --server prod -j
```

`dsp vre data-model structure` answers the question "how do the resource-types in a data-model relate to one another?"
It emits a flat, edge-centric list of all relations in the data-model: `link` relations (a link field pointing from one resource-type to another, labelled with the field name;
cross-model targets are tagged `[to <dm>]`) and `inherits` relations (superclass edges).
This is the complement to `data-model describe` (which lists resource-types) and `resource-type describe` (which lists fields):
`structure` gives the relational topology in one view, without drilling into each resource-type separately.

**Full signature:**
```bash
dsp vre data-model structure \
  -p <shortcode|shortname|iri> \
  --data-model <name-or-iri> \
  [--include-builtins] \
  [--format <f> | -j | -l] \
  --server <s>
```

`--include-builtins` reveals system superclasses (e.g. `knora-api:Resource`) and built-in link fields that are hidden by default.
Five output formats: `prose` (edge list with `→` arrows), `json` (array of edge objects with `source`, `target`, `kind`, `field`, and `target_data_model` keys —
`field` and `target_data_model` are `null` when not applicable), `lines` (omits `target_data_model`), `csv`, `tsv`.
Authentication is optional — public project schemas are returned without a token.

**v1 limitation:** link fields that are *defined in a sibling data-model and only reused* in this one are omitted (no sibling-data-model fetch).
The common case — a field defined here pointing to a resource-type in a sibling data-model — is fully covered via the `[to <dm>]` cross-model tag.

Example:
```bash
dsp vre data-model structure -p 0801 --data-model beol --server prod
dsp vre data-model structure -p 0801 --data-model beol --server prod -j
dsp vre data-model structure -p 0801 --data-model beol --server prod --include-builtins
```

`dsp vre project dump` triggers a server-side bagit-zip packaging of the full project (data + assets by default), polls until complete, and streams the result to disk.
**Requires a system-administrator token** — project-admin scope is rejected with `403`.
The existing `DSP_TOKEN` browser-harvest auth path applies: obtain a system-admin JWT from the DSP web app and set `DSP_TOKEN=<jwt>`.
Use `--skip-assets` to reduce archive size when you only need the structured data.

**Idempotent by default (safe to re-run):** if a dump already exists on the server, the default behaviour adopts it —
downloading it immediately if complete, or polling it to completion if still in progress.
Re-running `dsp vre project dump` is therefore safe for agents: it fetches whatever dump is available without creating a duplicate.

**One dump slot, shared server-wide:** the DSP-API holds a single dump at a time across all projects.
If that slot is currently held by a *different* project, `dsp vre project dump` refuses by default rather than touching another project's dump.
Use `--replace --discard-other-project` to explicitly reclaim the slot (see below).

- `--replace` — discard a completed or failed existing dump and create a fresh one (force a new version). Returns a conflict error if a dump is currently in progress.
- `--discard-other-project` — only valid with `--replace`. When the single server-wide slot is held by a *different* project, `--replace` alone refuses;
  add this flag to also discard that project's dump and make room. (Distinct from `--force`, which only governs overwriting the local output file.)
- `--delete` — remove the project's existing dump without downloading. Returns a conflict error if a dump is in progress.
  `--delete` is mutually exclusive with `--output`, `--force`, `--skip-assets`, `--cleanup`, and `--replace`.
  If the slot is held by a *different* project, `--delete` is a no-op — it never removes another project's dump.

The existing dump's id is discovered from the 409 conflict response body (no list endpoint exists in the API); the action extracts it from `errors[0].details.id`.

## Output formats

- Default: **prose** with a footer disclosing the server and auth state.
- `-j` / `--json` — full structured output, wrapped in `{ "_meta": {...}, "data": [...] }`.
- `-l` / `--lines` — one entity per line, tab-separated, no header. For `cut`/`awk`.
- `--format csv` / `--format tsv` — formal tabular formats with headers.
- `--columns=a,b,c` — select/reorder output columns (csv/tsv/lines; valid names in each command's `--help`; not supported for json/prose).
- `--no-header` — suppress the header row (csv/tsv only; useful for `>> all.csv` row concatenation).
- `--header-only` — emit only the header row and exit (csv/tsv only; server fetch still happens).

## Server selection

`--server <value>` (short: `-s`) accepts a built-in shortcut or any URL. Shortcut matching is case-insensitive.

Built-in shortcuts: `prod`, `stage`, `dev`, `demo`, `rdu`, `ls-prod`, `ls-test`, `local`.

Or use `DSP_SERVER` env var as a default; or a `.env` file in the CWD.

There is no implicit default server — every command must explicitly target one.

## Authentication

```bash
dsp auth login     --server <s> --user <email|username|iri>  # prompts for password interactively;
                                                             # pipe password via stdin when not a TTY
dsp auth status    --server <s>                  # reports cached token state (no API call)
dsp auth logout    --server <s>                  # removes cached token; idempotent
dsp auth set-token --server <s>                  # reads a JWT from stdin, verifies it, caches it
dsp auth token     --server <s>                  # prints the resolved token to stdout (no API call); exit 3 if none/expired
```

**Caution — `dsp auth token`'s output is the secret.** Calling it directly (not
inside `$(…)`) dumps the raw bearer token into your own tool-output/transcript on
every invocation. Prefer `export DSP_TOKEN=$(dsp auth token -s <s>)` or piping
straight into the next command; see the fuller caution below.

`login`/`status`/`logout`/`set-token` accept `--format` / `-j` / `-l`; `dsp auth
token` is verbatim-only — it has no `--format` flag, it always prints the bare
token (or nothing, on error). Token is cached in `~/.config/dsp-cli/auth.toml` (mode `0600`, keyed by server URL), so you log in once and later commands reuse it until it expires.

For non-interactive login: `DSP_USER` supplies `--user`, and `DSP_PASSWORD` supplies the password (resolution order: `DSP_PASSWORD` → prompt → stdin).
**`DSP_PASSWORD` is for local/dev/test only — never a production password.** `DSP_SERVER` / `DSP_USER` / `DSP_PASSWORD` can live in a `.env` file in the CWD.

`DSP_TOKEN` (a pre-issued bearer token that overrides the cached token, so login is skipped entirely) is **fully wired** —
set it and `dsp auth status` will report that it is in effect, showing the token's expiry when readable from the JWT `exp` claim.
Preferred over `DSP_PASSWORD` for real environments (scoped + expiring).

`dsp auth set-token --server <s>` reads a pre-issued JWT from stdin, verifies it against the server (`GET /v2/authentication`), and caches it in `auth.toml` like `login`.
The cached user is the token's `sub` claim (a user IRI).
Use this as the persistent path when a token was harvested externally; `DSP_TOKEN` remains the ephemeral per-invocation alternative.

`dsp auth token --server <s>` is the read-out counterpart to `set-token`: it prints the resolved token (env or cache) verbatim to stdout, making no API call.
Use `export DSP_TOKEN=$(dsp auth token -s dev)` to lift a cached token back into the environment for another tool.
It exits `3` if no token is cached for the server or the cached/env token is locally detected as expired (an advisory, unverified `exp` check — not a live probe).

### For agents: browser-harvest auth (recommended)

DSP-API has no OAuth/device-code flow — only email+password → JWT.
So the cleanest way for an agent to authenticate a human against a real environment (including any SSO/2FA the browser presents) is:

1. Open the DSP app in a browser and have the user log in.
2. Read the JWT directly from web storage — run `localStorage.getItem("ACCESS_TOKEN")` in the browser console (or DevTools).
   The DSP web app stores the JWT in plain `localStorage` under the key `ACCESS_TOKEN`; it is NOT an HttpOnly cookie, and `document.cookie` is empty.
3. Pipe that token into `dsp auth set-token` to cache it persistently, or set `DSP_TOKEN` for a single invocation:

```bash
echo "$JWT" | dsp auth set-token --server dev
# or, for a single command without persisting:
DSP_TOKEN="$JWT" dsp vre project list --server dev
```

**`dsp auth set-token` is for dev/test only — never use a production token harvested through an AI agent.** A token passing through an agent's context window also passes through
the model provider's infrastructure and may appear in transcripts or logs. Treat any agent-harvested token as potentially logged.
The same caution extends to `dsp auth token`: if an agent invokes it directly (not inside `$(…)`), the raw token lands in the agent's own tool-output/transcript
on **every** call — prefer the `export DSP_TOKEN=$(dsp auth token -s dev)` form or piping it straight into the consuming command.

**Always pipe the token via a shell variable** (`echo "$JWT" | dsp auth set-token …`) — do NOT paste it at an interactive TTY (it echoes into scrollback)
and do NOT inline the literal token in a shell command string (it leaks into `ps` output and shell history).

The harvested JWT is the same credential `dsp auth login` would obtain, and expires the same way (~30 days).
dsp-cli itself never opens a browser; the browser dance is the agent's, dsp-cli just consumes the token.

Most read operations on **projects and data models** are public — no auth required.
Authentication is needed for private projects, instance data (resources), and write operations.

When authenticated, every command's output footer shows the authenticated user; otherwise it shows "anonymous".

## Domain vocabulary

dsp-cli uses **researcher-facing language** that differs from DSP-API:

| dsp-cli term       | DSP-API term                  |
|--------------------|-------------------------------|
| `data-model`       | ontology                      |
| `resource-type`    | resource class (`knora-api:ResourceClass`) |
| `field`            | property (`knora-api:Property`) |
| `value`            | value (knora-api:*Value instance) |
| `value-type`       | the kind of `Value` subclass  |

Run `dsp docs concepts` for the full vocabulary explanation.

## Further documentation

Inside the CLI itself (`dsp docs <topic>` prints embedded markdown; run `dsp docs` for the list):
- `dsp docs dsp-cli`      — what this tool is, who it's for, design principles
- `dsp docs dsp`          — what the DaSCH Service Platform is (VRE vs Repository)
- `dsp docs concepts`     — domain vocabulary in depth
- `dsp docs identifiers`  — how to name projects, data-models, resource-types
- `dsp docs connecting`   — servers, environments, auth (incl. browser-harvest)
- `dsp docs output`       — output formats, channels, the JSON envelope
- `dsp docs workflows`    — chaining commands into real tasks
- `dsp docs errors`       — exit codes and how to recover
- `dsp docs dsp-tools`    — when to use dsp-cli vs dsp-tools

Use `dsp docs -j` for a machine-readable JSON index of all topics
(`{"_meta":{},"data":[{"name":…,"summary":…},…]}`). Useful when an agent needs
to enumerate topics programmatically. `-j` conflicts with `<topic>` and
`--pager`; it is only the no-arg index form.

## Installation (if `dsp` is not present)

Try `cargo install dsp-cli` first. If that fails (not yet published to crates.io), fall back to installing from source:

```bash
cargo install --git https://github.com/dasch-swiss/dsp-incubator dsp-cli --force
```

Requires a Rust toolchain (`rustup`). The binary is installed to `$HOME/.cargo/bin/dsp`.