clssck/dataiku-sdk
Dataiku DSS SDK and agent-oriented CLI for programmatic access to DSS REST APIs.
Changelog
Unreleased
4.2.1
- Fix: an HTML page answering with
401/403isunexpected_response(exit 2), notpermission_denied. DSS answers those statuses with a JSON error document, so the page came from an intermediary, e.g. a corporate proxy that intercepts GETs for browser authentication (Zscaler) while POSTs pass. The error reads "HTML error page from an intermediary, not DSS" and the hint points at the network path instead of the API key and project permissions.doctor --capabilitiesreports such probes asunknowninstead ofno, and the target-absence guard ofapp create-instance/create-successor-instancesurfaces the intercepted probe instead oftarget_absence_unverifiable(still creating nothing). Verified live behind a simulated intercepting proxy; DSS's own401/403staypermission_denied.
4.2.0
- Fix: scenario
canonicalEditableFieldsnamedparams.triggersandparams.reporters; DSS (and dataikuapi) keep triggers and reporters at the top level (triggers,reporters), so an agent following the advertised path wrote fields DSS ignores. Verified live: an email reporter (messaging.type: mail-scenario) and a daily trigger set throughscenario updatepersist. - A scenario update that DSS did not persist as sent now carries
details.mismatchesin the CLI error: each mismatched field with the paths that differ (e.g.reporters.0.messaging.channelId), never the values, since reporter and step settings can hold credentials. scenario reporter-add --channel IDwarnsreporter_channel_unknown(with the visible channel ids) when no messaging channel has that id: DSS saves such a reporter, but it never sends.- A mistyped resource with no close match (
dss pipelines list) no longer suggests the same action under unrelated resources. - The skill names
dss commands run --contains TEXTfor finding commands by concept. - New
messaging-channelresource:list(--type,--family),get,create,settings-get,settings-set(merge, optional--expect-hash),permissions-get,permissions-set,delete,send(multipart mail with--attachment). Credentials (passwords, tokens, webhook URLs, SMTP session secrets) are redacted in output, plans, dry-runs, and errors. - New
project test-report(JUnit XML or--format html,--output PATH) andproject testing-statusfor the last test-scenario runs;project-deployer testing-statusandrun-test-scenarios. - New skill reference
notifications.md: attaching a mail channel to a scenario end to end, direct sends, and test reports. - Breaking: agent contract v7.
scenario run(without--wait) returns{triggerId, triggerRunId, cancelled, next}instead of{runId}: the id DSS returns from a run request is a trigger run id, not a scenario run id (get-run/logdo not accept it). Resolve it with the newscenario get-run-for-trigger SCENARIO TRIGGER_RUN_ID(statePENDING, RUNNING, FINISHED withrunIdandoutcome, or CANCELLED;--trigger-idfor non-manual fires);nextnames it. - Fix: a trigger fire DSS cancels because the scenario is already running now ends
scenario run-and-wait/run --waitat once with outcomeCANCELLED(exit 4,cancelled: true,triggerRunId, afailure.messageandnext), instead of waiting out the timeout and reportingTIMEOUT. scenario run,run-and-wait:--params JSON/--params-file PATHare the run parameters (the POST body; they appear in the run'strigger.params).scenario last-runs --only-finished(DSSonlyFinishedRuns: skips in-progress runs;--only-finished --limit 1is the last finished run). Newscenario runs-by-date --from DAY [--to DAY](compact likelast-runs; DSS treats--toas exclusive, default tomorrow). Newscenario run-report SCENARIO RUNID [--step-id ID] [--output PATH]: the JUnit XML of a test (markedAsTest) scenario run.- Scenario authoring:
scenario create --data/--data-file/--stdinmerges fields (triggers, reporters, steps,runAsUser) into the create body. Newscenario trigger-add|trigger-list|trigger-remove(schedules built from--frequency minutely|hourly|daily|weekly|monthlywith--every/--hour/--minute/--days/--day-of-month/--run-on/--start-date/--timezone, or any trigger via--data) andreporter-add|reporter-list|reporter-remove(mail reporter from--channel/--recipient/--subject/--message/--condition/--phase, other channel types via--data; credentials are redacted in output and plans). They read, change and write the whole list with the other elements untouched, verify it, and support--dry-run/--plan. Newscenario run-as-set --user LOGIN|--clearreports the effective run-as;scenario statusshowsrunAsUser. future list --scenarios-onlylists only scenario futures (withNotScenarios=false).
4.1.0
-
Breaking: agent contract v6.
scenario get-runandscenario last-runsprint compact results by default (--full/--fieldsreturn the DSS objects).get-runkeeps the run identity, outcome, timing, trigger, per-step built datasets and executed jobs with their error message, plusfailure{stepId, jobId, dataset, message} andnextargv (e.g.dss job log JOB --errors-only); the raw report's trigger auth context, permission flags, API-key metadata, and log tails are gone (a failed run went from ~5 KB of noise to ~1 KB). A failedlast-runsitem carriesnextpointing atscenario get-run.scenario run-and-wait/run --waitfailures includefailureandnext. -
commands run --fieldsreturns the known selectors when some are unknown and warnsunknown_fieldswith did-you-mean suggestions (flow.map→project.map); it fails only when none are known, now withdetails.suggestions. -
commands run --fields RESOURCE(a bare resource, on stdout) lists each action'susage,description, andsideEffectinstead of every full entry:--fields recipeis 6 KB instead of 49 KB. In an eval run the agent got a 49 KB, middle-elided result and spent four calls exporting the registry and filtering it withjq.RESOURCE.ACTIONand--output PATHstill return full entries. -
--fullis accepted on everygetread whose output is already the DSS object (recipe, scenario, folder, wiki, …), so "--full returns the DSS object" holds everywhere agents try it;code-env get --fullreturns the raw definition.connection get/info(secrets redacted),future get, andproject-library getdo not take it. -
dataset preview --max-rowsabove 500 returns the first 500 rows instead of failing; the preview hint points todss dataset download --limit N --output PATHfor more. -
When the failed recipe is known,
scenario get-runand a failedscenario run-and-waitadd ahintthat spells out the edit-and-rerun loop (recipe get-payload … --output FILE, edit,recipe set-payload … --file FILE,scenario run-and-wait). In evals, agents spent two or threecommands runlookups finding those commands. -
recipe createfor a join, grouping, or prepare recipe configured from flags returnsnext:dss job build-and-wait OUTPUT --build-mode RECURSIVE_BUILD --summary. In evals, agents spent up to four calls looking for how to build a dataset. -
recipe create --type grouping --aggregate …outputs only the group keys and the requested aggregates: DSS's implicit per-groupcountcolumn (globalCount) is turned off; addCOL:countfor a count. With--group-byalone the count stays, as the only aggregate. In 2 of 3 eval runs agents rewrote the payload (3–4 calls) to drop the unrequestedcountcolumn. -
A mistyped resource or action (
dss flow map,dss recipes list,dss scenario get-runs) fails with "Did you meandss project map?" in the hint anddetails.suggestions, so the agent fixes the call without acommands runlookup. -
DSS_PRETTY=1indents stdout JSON (results and errors; still one JSON value). Agent shells that cut long lines (omp at 768 bytes) truncated 5–7 one-line results per eval case, and the agent spent calls on artifact reads andjqto recover them. -
Contributors:
bun run eval:agentsruns headless coding agents (omp -p) against cases on a live DSS (scenario-fix, data-question, build-flow), verifies the outcome against DSS state, and reports success, tool calls, dss calls, failed dss calls (with argv and error code), and tokens per case in.agent-eval/<run>/— live feedback on how navigable the CLI is for agents. -
scenario get-runand failedscenario run-and-waitalso name the recipe that failed and the datasets it read (failure.recipe,failure.inputs, from one extrajob getonly on failure), andnextlistsrecipe cat,dataset schemafor those inputs, thenjob log --errors-only.scenario last-runsshows an in-progress run asoutcome: "RUNNING"instead ofend: 0with no outcome. The skill entrypoint tells agents to follownext/hintbefore exploring, to run reads directly (errors carry the usage line), and to fetchcommands run --fieldsentries only before a first write, batched in one call. -
Fix: a response that exceeds a client-side size limit ("Response Too Large": buffered bodies over 50 MiB, SQL results over the stream cap) is a non-retryable
validation_failedwith a hint to narrow the request, not a retryabletransienterror. -
Wait timeouts for ML training, scenario runs, futures, and
code runsay the wait timed out with the last known state, instead of "failed long-running result: RUNNING". They claim the operation was not cancelled only when the result carriescancelled: false;code runpoints to itscleanupstatus. -
Job wait timeouts add
resumeArgv(the resume command as an argv array, runnable without shell quoting on Windows);resumestays as the POSIX display form. -
job logkeeps its per-chunk stall timeout and also caps the whole read at 10x--request-timeout, with an error naming that limit, so a log that never stops trickling cannot hang a caller.
4.0.0
- Breaking: agent contract v5 (
agentContractVersion: 5), for the correctedoutputShapes and error classifications below. - Breaking: Bun 1.4.3 is now the minimum supported version (
engines.bun >=1.4.3); CI and release run 1.4.3. On an older Bun,dssexits 2 with a JSON error that tells you to runbun upgrade. - Breaking: dataset TSV cell/row limits (a single cell over 16 MiB, a row over 64 MiB) fail as
validation_failed(exit 1, not retryable) naming the column and pointing to--columns. They used to surface as a retryabletransient"0 Network Error" (exit 3) that no retry could fix. SDK: these are nowClientValidationError, notDataikuError. - Breaking:
code runreads the tail of the scenario log, and--max-log-bytes/--full-logkeep the last N bytes instead of the first; script output keeps its last quarter of that budget. Output over the budget no longer disappears:outputholds the tail, withoutputTruncated/outputOmittedBytesand acode_run_output_truncatedwarning. Printed lines containing CR, U+2028 or U+2029 are no longer dropped. - Breaking:
recipe updaterejectsenvSelectionplaced at the payload root or underrecipe(outsiderecipe.params) withvalidation_failed; it was silently ignored. A patch'srecipe.params.envSelectionnow replaces the stored object instead of deep-merging, so switchingEXPLICIT_ENV→INHERITno longer keeps a staleenvName.--dry-runpreviews the exact merged recipe the update sends. - Breaking: discovery
outputShapeis corrected forfolder.contents(array),plugin.usages,plugin.download, andproject-library.diff(object). - Fix:
dataset create-managed --record-cleanuprecords its ledger entry; it used to create the dataset and then failambiguous_outcome. Every action that advertises--record-cleanupnow derives a cleanup entry (alsostreaming-endpoint create-managed,ml-task create-for-dataset,saved-model create-external,project-folder create-child,data-collection create,plugin create-dev, andconnection/user/group create), enforced by a registry test. If recording still fails after a successful mutation, the error carriesdetails.mutationSucceeded: true,cleanupRecorded: false, and the created identifier and project, so a caller never has to retry the create. project exportinspects the written archive and warns (export_contains_credentials, stderr) when it contains credential-bearing structures —project_configAPI-key/secret files, secret-named project variables (object and list form), web-appapiKey-style fields — listing member paths and key names only, never values; the result addscredentialFindings.project inspect-archivegains the same structuralcredentialFindingsinventory and aresidue_scan_skippedwarning for scanned members over 1 MiB instead of skipping them silently. Archives are not redacted.- Fix:
job wait,job build-and-wait,job build --wait,monitor, andwatchtimeouts say the wait timed out and the job is still running in DSS, keep the last knownstate, and addcancelled: falseand aresumecommand (dss job wait ID [--project-key KEY]). Before, the error read "failed long-running result: RUNNING" and a deadline during a poll reported stateunknown. - Fix:
job logno longer fails after 30 s on a large log that is still arriving: the request timeout now applies per stalled read, not to the whole transfer. When only the tail fits the 10 MiB buffer,job logwarnslog_truncated(earlyLinesDropped: true);--errors-onlywith no matches warnsno_error_lineswith the scanned line count instead of printing a silent empty string, and keeps the job-level outcome line in logs without DSS record headers too. - Fix:
job summaryreturns the log summary plusdetailsErrorwhen the job-detail response exceeds the 50 MiB buffered limit, instead of failing outright. - Fix:
job listshows in-progress jobs asstate: "RUNNING", andjob list --state RUNNINGfinds them. DSS (verified on 15.0.1) lists a job that is computing dependencies or running withstableState: falseand nostate, so these jobs printed without a state and the filter matched nothing.--fullstill returns the DSS objects;job getreports the exact phase. - Fix:
plugin listkeepsisDevin its compact items, so development plugins (editable withcontents-*, Git actions) are distinguishable from installed ones without--full. project importreports the DSSstatusand sanitizeddetails.dssMessage/dssErrorTypebehind anambiguous_outcomefailure (process step or post-import re-read). DSS 15.0.1 answers an import into a taken project key with500 Project key KEY is already used; before, only "the project may or may not have been created" was shown. Anyambiguous_outcome/assertion_failed/long_running_failureerror that carries a DSS response as its cause now shows the same fields.- Fix:
dataset preview,dataset download, anddataset assert-countverify that a data stream which ended before the row cap was complete, as dataikuapi does: each read sends areadSessionIdand then asks DSSfinish-streaming; a server-side read failure now fails the command (and removes the partial download) instead of returning silently short data. Streams stopped at the row cap are not checked. - Fix:
job log --errors-only(and--log-filter errors) keeps DSS's job-level outcome line, e.g.Job is incompatible with build state: [...]when another running job already builds the target. It has no level word, so the filter used to drop the only reason DSS gives. - A client configured with
--insecureor--ca-certsends its requests through its ownBun.FetchSession, so its relaxed or custom TLS connections are never pooled with plainfetchor another client's;HTTP(S)_PROXY/NO_PROXYstill apply. - More Bun-native APIs: output files are written with
Bun.write(paths such asjob log --output,recipe get-payload --output,commands run --outputnow create missing parent directories), dataset TSV decoding uses streamingTextDecoder, hashing usesBun.CryptoHasher, and scripts useimport.meta.dir. - Examples use current Python env names (
PYTHON311forplugin code-env-create; DSS 15 rejects new Python 3.6–3.8 code envs). - Fix: downloads to a file (
project export,folder download,bundle download-exported, plugin/saved-model downloads) create missing parent directories, and stream through a nodeFileHandle: on Windows, Bun 1.4.3 could end the process with exit 0 in the middle ofBun.write(Bun.file(fd), response), leaving no file. User-supplied files (--file, cleanup ledgers) are read throughnode:fs, because Bun 1.4.3Bun.file()reads of a missing path crashed the CLI on Windows instead of reporting ENOENT. - Contributors: type checking runs on Bun's built-in
bun check(about 3x faster thantsc --noEmithere); the combined gate script is renamedbun run check→bun run verify, because a script namedcheckshadows the built-in.tscis still used to emitdist/.cross-envis removed (Bun's script runner sets inline env vars on every OS);@types/bun^1.4.3,dprint^0.63.0,@dprint/json0.25.2. - Contributors:
bun run lintis about 35% faster (1.95 s → 1.29 s) because thedss/*JS-plugin rules are scoped in.oxlintrc.jsonto the code they guard and no longer run on tests;no-restricted-importsnow bansnode:string_decoder,node:child_process, andfileURLToPathoutside tests and scripts. The SDK/CLI parity integration suite compares through the CLI's compact output shapes.
3.9.0
- Agent contract v4:
job get,dataset info,dataset get, andproject getprint compact results by default;--fullreturns the DSS object and--fieldsstill projects from it.job getkeeps state, outputs, progress, the error, and per-activity status, and never the log tail: a failed job is 240 tokens instead of 15,908, a finished one 173 instead of 1,170.dataset infokeeps type, connection, format, schema, recipes, buildability, data quality, and freshness (1,464 → 131).dataset getandproject getkeep the settings structure (so get → edit →updatestill works) without metrics/checks configuration, version stamps, checklists, and empty values;project getlists only the permissions you lack indeniedPermissionsinstead of ~20can*booleans (770 → 358, 551 → 149). Discovery output schemas describe the compact shapes;stdio.stdout.listsis nowcompactResults. job logprints the last 100 lines by default and emits alog_truncatedwarning with the total;--max-lines Nsets the tail,0prints everything,--output PATHis unchanged. A finished one-recipe job's log is 4,460 tokens instead of 9,950.- Fix: job logs no longer expose secrets. DSS writes the job ticket secret (
"jobTicketSecret":"...") into every job log;job log,job summary,job log-url, and--include-logsbuilds/waits (SDKjobs.log) now redact credential-like JSON values as[redacted]. - Fix:
job log --errors-onlyand--log-filter errorsno longer keep INFO records whose JSON payload merely contains a level word, such as the visual recipeSQL status {"statusWarnLevel":"ERROR",...}line logged by every successful grouping job. project mapstops repeating itself: nodenameis omitted when it equalsid, per-nodezoneNameand thenodeIdslists ofzonesandcomponentsare gone (membership is each node'szoneId/componentId), and emptywarningsand an untruncatedtruncationblock are omitted.topologyFingerprintis unchanged. A 7-node map is 513 tokens instead of 701.- Error envelopes drop
ok:false(same astype:"error") and the echoedresource/action; batch steps keep them at step level.
3.8.0
- Fix:
recipe create --type vstack(andjoin,geojoin,generate_features) sends the inputs as DSScreationSettings.virtualInputs, as dataikuapi does. DSS builds these recipes' inputs and payload only from virtual inputs, so a Stack recipe was created withinputs: {}, an empty payload, andoutputSchemaUpdateError: 500 Internal Error; it now has every input, a UNION payload, and a computed output schema. recipe create --rename/--fill-empty/--formula/--filter/--drop-columns/--keep-columnsruns prepare steps in the order the flags are given (the first use of a flag sets its position; SDKstepOrder); before, renames always ran first. A--formulaor--filterthat still names a column an earlier--renameremoved emitsrecipe_formula_uses_renamed_column, also on--plan.recipe create --name NreportsrequestedNameand arecipe_renamedwarning (reason: name_takenfor DSS'sN_1suffix, otherwisedss_chose_name) when DSS returns a different recipe name, instead of differing silently. The public API cannot rename a recipe afterwards.- Fix:
sql queryfailures that DSS answers with a database error (JDBC/SQL exception, permission denied, object not found) are reported as definite, non-retryable failures carrying the DSS message. Before, a 5xx with e.g.Schema ... does not exist or not authorizedcame back asambiguous_outcome("the mutation outcome is unknown") and was retried as transient. Connection resets, timeouts, generic 5xx answers, and JDBC errors reporting a lost or timed-out database connection (SQLRecoverableException,SQLTimeoutException,I/O error, communication errors) stay ambiguous, since a DML statement may have committed. - Fix: a value flag accepts a value that starts with
--when it is not flag-shaped, so--sql "-- comment\nselect ..."works; a missing value whose next token is a flag now hints--flag=VALUE(and--sql-file/--stdinfor--sql). - Fix:
job build-and-wait,job build --wait, andjob wait/monitor/watchfail (exit 4,long_running_failure,failure.code: nothing_to_build) when a job ran no activity because a target is a managed dataset that no recipe writes; DSS ends such a jobDONElike an up-to-date build. Up-to-date builds and source datasets stay successful. Abuilt_dataset_has_no_columnscheck that cannot read the schema now emitsbuilt_dataset_schema_uncheckedinstead of passing silently. - Fix:
dss doctorfailing checks include the error message and retry hint, so an untrusted corporate CA shows the TLS code (UNABLE_TO_VERIFY_LEAF_SIGNATURE, self-signed) and the--ca-cert/NODE_EXTRA_CA_CERTSguidance instead of a bareNetwork Error. Self-signed certificate failures are classified as non-retryable TLS trust failures everywhere. - New:
dss wiki attach ARTICLE FILEuploads a local file to a wiki article and returns itssmartId;dss wiki detach ARTICLE SMART_ID [--if-exists]removes exactly that attachment (DSS has no delete endpoint: the article is saved without it and re-read to verify). Both support--dry-run/--plan; SDKwiki.attach/wiki.detach. - New:
dataset createcreates SQL datasets over an existing table (--table T [--schema S] [--catalog C]) or a query (--query SQL/--query-file PATH) on any SQL connection type. DSS detects the schema (testAndDetectSettings/externalSQL) and it is stored; the result reportsschemaDetectedandcolumns. A failed detection keeps the dataset and emitsdataset_schema_not_detected. Flag combinations are validated before any request. - Fix:
flow-zone organizeno longer reports a moved zone that DSS left in place. DSS's public API applies a zonepositiononly when the zone is created and ignores it on update (name and color still save), so a plan that moves an existing zone now fails before any change withvalidation_failed, listing each zone's current and requested position. New--recreate-on-movecreates a replacement zone at the requested position, carries over items, shared items, tags, custom fields, and checklists, deletes the old zone, and reportsrecreated(replacedZoneId-> newzone); the zone id changes. SDK:flowZones.updateno longer acceptsposition;flowZones.recreatemoves a zone and fails withambiguous_outcomeand both zone ids if a step breaks partway. - Fix:
flow-zone organizehonors DSS's rule that a recipe and its outputs share a zone. A plan that splits them (which DSS overrides, so every rerun moved them back) is rejected withvalidation_failedand the conflictingdetails.conflicts. Listing a recipe or one of its outputs places the whole unit, reported per zone asimpliedItems, so--syncno longer sends an unlisted output back to Default and drags its recipe with it. - Fix:
flow-zone organizezone positions now land where the plan says. DSS stores a position sent on zone creation only while the project'szonesManualPositioningsetting is off (with it on, DSS auto-places the zone) and draws positions only while it is on. Organize therefore switches the setting off while it creates or recreates zones and restores it afterwards (manualPositioning,suspendManualPositioningin the result), checks each stored position (assertion_failedwithpositionsNotAppliedotherwise), and warns (zone_manual_positioning_disabled, orzone_manual_positioning_unverifiedif the settings cannot be read) when positions will not display; the hint is theproject settings-setcommand that enables it. flow-zone planaddsunassigned: Default-zone recipes and source objects still to place (recipe outputs follow their recipe).flow-zone organizepublishes its plan JSON Schema asschemas.inputincommands run/agent contract.project map --render mermaidcolors each zone subgraph with its DSS color.- Fix:
recipe create --output-connectionno longer leaves orphaned output datasets behind when DSS rejects the recipe (e.g.500 Root path of the dataset ... does not existfor an unbuilt input). The datasets the command created are deleted before the original error is rethrown, and the errordetailslistcreatedDatasetsDeletedandcreatedDatasetsNotDeleted(with the delete error) so a failed cleanup is visible. Because a failure can be ambiguous (DSS may have committed the recipe, possibly under another name), a created dataset that a recipe already writes in the flow graph, or every created dataset when the graph cannot be read, is kept and listed increatedDatasetsKeptwith the reason. Pre-existing datasets are never touched.
3.7.0
- Fix:
recipe create --output-connectioncreates missing outputs through DSS's managed-dataset endpoint (POST /datasets/managed, as the UI and dataikuapi do), so DSS picks the dataset type, storage path, and format from the connection. Before, the CLI guessed: an S3 connection with no existing dataset got aFilesystemdataset (builds failed withUnexpected connection type ... EC2), and once one S3 dataset existed the next output got SQL-table params with nopath(Placing a managed dataset at the root of a connection is not permitted; DSS then answeredrecipe create --type shakeranddataset refresh-schemawith an empty-body500). - Fix:
recipe createasks DSS to compute the output schema of visual and SQL query recipes (GET /recipes/{name}/schema-update) after creating and configuring them, and writes it to outputs the command created or whose schema is empty. Join and grouping outputs no longer keepcolumns: []and build to an empty dataset. The result reportsoutputSchemaUpdated; if DSS cannot compute the schema, the recipe is kept andoutputSchemaUpdateErrorplus arecipe_output_schema_not_computedwarning explain why. This replaces the sync-only input-schema copy:syncOutputSchemaPropagatedis nowoutputSchemaUpdated. - New:
dss recipe update-schema NAME(SDKrecipes.updateSchema,recipes.computeSchemaUpdates) writes the DSS-computed schema to every output whose schema differs, like the UI's "Update schema" and dataikuapicompute_schema_updates().apply();--dry-runlists them underpending. Code recipes are rejected up front because DSS cannot compute their schema. recipe set-payloadon a visual or SQL query recipe keeps DSS-derived output schemas in step with the new payload: outputs whose schema was empty or matched the DSS-computed one before the upload get the newly computed schema (outputSchemaUpdated), so a grouping created withrecipe createand then given keys and aggregations builds with those columns. Hand-edited output schemas are kept and reported in arecipe_output_schema_outdatedwarning.- New:
job build/job build-and-wait --auto-update-schemasets DSS'sautoUpdateSchemaBeforeEachRecipeRun. A successful dataset build that leaves the target with an empty schema (no columns, no rows) now emits abuilt_dataset_has_no_columnswarning instead of passing silently. The--planbuilder had read the unrelated--force-rebuildflag for this setting. - Fix: join and fuzzy-join configuration and the managed-folder output swap after
recipe createaddress the recipe by the name DSS returned, not the requested one. dataset create --type Inlineexplains why editable datasets are rejected (the public API cannot write their rows, and an empty one fails downstream builds) and what to use instead.- Fix:
job log --errors-onlyand--log-filter errorskeep the exception lines of a failed DSS record (java.lang.IllegalArgumentException: ... Unexpected connection type ...,Caused by:chains, Python traceback frames and the failing line) and drop JVMatframes. Before, anActivity unexpectedly failedheader came without its cause: class names such asClassCastExceptiondid not match the keyword filter. field_projection_missingwarnings for a nested--fieldspath now list the keys that exist under the deepest parent that resolved (missingrecipe.paramslistsrecipe.type,recipe.name, ...), so an absent key no longer reads as "nested paths are not supported".- New:
dss connection info NAME(SDKconnections.info) reads the non-admin usage view of a connection (GET /connections/{name}/info, dataikuapiDSSConnection.get_info());connection getreads the admin definition, and its403now hints atconnection info. Credential fields, including resolved AWSsessionTokens, are redacted. dss doctorreports the identity the API key acts as (identity:authSource,authIdentifier,groups,userProfilefrom/auth/info), to explain 403s on objects the user's UI profile can use. DSS versions without that route simply omit it.- The TLS verification hint names
dss auth login --ca-cert PATHfor subprocesses: a project.envapplies only whendssruns in that directory. - Fix: a missing required positional is a
missing_required_argusage error with the usage line for every command.dss knowledge-bank searchwithout an id used to crash asinternal_error. - Unknown-flag errors carry the command's usage line in
hint(and--jsonsays stdout is always JSON), instead of pointing to a ~850-tokencommands run --fieldslookup. - CLI DSS error envelopes are one line and carry the DSS message:
errorisSTATUS Text: DSS message(credentials redacted, bounded), where it used to repeat category, retryability, hint, and retry counters as prose and drop the DSS message.detailskeeps only content (elapsedMs/target,dssErrorType,bodyTruncated, andretrywhen a retry or timeout happened);dssCategory(same ascode),statusText(same asstatus), and thebodymetadata string are gone. A 403 names the project (DSS answers 403 for a project that does not exist) and a 404 names the resource and itslistcommand. SDKDataikuError.messageis one line too; category, retryability, hint, and retry stay structured fields. A 403 now costs ~100 tokens instead of ~180. - A refused connection, unknown host, bad URL, or untrusted certificate fails at once as
validation_failed(exit 2) instead of retrying for ~6 s and exitingtransient. Timeouts, resets, 429, and 5xx retry as before. - New:
dss commands run --contains TEXTreturns the top 5 actions for a concept ("propagate schema"→flow.propagate-schema,recipe.update-schema;whoami→doctor) with usage and description. - Agent contract v3: registry entries list command flags only; the global flags appear once under
agent contractcommands.globalFlags.structuredExamplesdrop theshellcopy ofexamples, and thepositionalsname list (a copy ofpositionalArguments) is gone.dataset.getis 697 tokens instead of 847, the full registry 275k instead of 347k. *.listcommands print compact items by default (identifiers, kind, and next-step fields such as recipeinputs/outputsor datasetconnection): a 6-dataset list is 118 tokens instead of 4,490, a project list 51 instead of 1,076.--fullreturns the DSS objects,--fieldsstill projects from them,--contains TEXTfilters on identifiers, and--limit Ncaps the count with alist_truncatedwarning. Discovery output schemas describe the compact items.- Bun 1.4.2 is now the minimum supported version (
engines.bun >=1.4.2); CI tests 1.4.2 only. On an older Bun,dssexits 2 with a JSON error that tells you to runbun upgrade. - Fix: when
dssruns under Bun itself (bunx --bun,bun --no-env-file), canary builds such as1.4.3-canary.12pass the minimum-version check again;Bun.semverrange matching rejected every prerelease. The Node and Bun launch paths now share one release-part comparison (bin/bun-version.js). - Faster startup (min of 21 runs, source checkout):
dss version100 → 49 ms,commands run138 → 47 ms,dataset create --plan111 → 62 ms,dataset list130 → 108 ms. Flag validation loads only the command registry: plan builders moved tosrc/cli/plans.tsand load only for--plan. Thecommands runsummary reads action names fromcommand-syntax.jsonwithout loading command modules.DataikuClientloads each resource module on first use.node:crypto,node:stream, andnode:zlibare gone from the common paths, andnode:tlsloads only for a custom CA bundle. Registry, summary, and agent-contract output are byte-identical. datasets.download/dss dataset downloadstream through Web Streams (TransformStream,CompressionStream("gzip")) intoBun.write: a 200k-row gzip export takes 345 ms instead of 571 ms (same bytes), and reaching the row limit now cancels the response instead of draining it.- Binary downloads (
writeResponseToFile) stream withBun.writeinto the exclusive owner-only temp file before the atomic rename. A temp file that cannot be created still cancels the response body. - New:
dss flow propagate-schema DATASET(SDKflow.propagateSchema) runs the UI's schema propagation through every downstream recipe, rebuilding as needed unless--no-auto-rebuild;--stop-at/--mark-ok RECIPESbound it and--waitwaits.dss flow generate-documentationexports the flow documentation (docx) from the default template,--template-file, or--folder/--path;--output PATHwaits and downloads it. - New:
recipe createbuilds grouping and prepare payloads from flags:--group-by,--aggregate COL:FN[+FN],--order-byfor grouping;--rename,--fill-empty,--formula,--filter,--drop-columns,--keep-columnsfor prepare (--type preparemaps toshaker). Builder flags on another recipe type are a usage error;--planlists the payload edits. - New:
dataset preview/download --columns COLS --partitions Pread a column or partition subset (POST /data/);dataset sync-hive-metastoreandupdate-from-hive;metrics dataset-run-checks;data-quality instance-status,partitions-status(defaults toNP), anddelete-history --partition. - New:
dss mlflowwraps the DSS MLflow extension (/api/2.0/mlflow/extension/*):list-models RUN_ID,set-inference-info,deploy-run RUN_ID SAVED_MODEL_ID(synchronous; raise--request-timeout),create-experiments-dataset, and the destructivegarbage-collectandclean-db. SDKclient.mlflowExtension;DataikuClient.get/postaccept extra requestheadersfor thex-dku-mlflow-project-keyheader. - New: Project Deployer
list-stages,get-infra,infra-settings,save-infra-settings,delete-infra,deployment-settings,governance-status,delete-project,project-settings,save-project-settings,delete-bundle;bundle get-exportedandbundle create-project(Automation node,--fileupload or--archive-path). - New: Visual ML diagnostics and documentation.
ml-taskandsaved-modelsharediagnostics --kind(subpopulation analyses, partial dependencies, timeseries residuals, per-timeseries metrics and forecasts),compute-diagnostics --kind ... [--features COLS] [--wait],generate-documentation [--output PATH],download-documentation,set-user-meta, and the license-gateddownload-scoring-jar/download-scoring-pmml; SDKmlTasks.model(a, t, m)andsavedModels.version(sm, v)return oneTrainedModel. Alsoml-task list,create-for-dataset(new analysis, time series forecasting with--time-variable/--timeseries-ids),reguess,reguess-forecasting, andanalysis update/list-ml-tasks.GET .../models-snippetsstays unwrapped: DSS requires a body on that GET, whichfetchcannot send. - New:
workspace remove-object,webapp trust [--for-everybody],future list [--all-users] [--with-scenarios],discussion update --topic,wiki update-settings,streaming-endpoint create-managed/schema/set-schema, andproject push-to-git-remote REMOTE. - Fix: a 403 hints that the project may not exist only when DSS's message is about the project; "You are not allowed to trust this webapp" keeps the generic permission hint.
- The DSS 15 coverage matrix covers 371 of 372 documented operations; Project Deployer
stagesandcreate infrarows now carry their documented paths. - Dev tooling: oxlint and
@oxlint/plugins1.86.0, dprint 0.60.1 with its npm-published TypeScript 0.96.1 and JSON 0.25.1 plugins (the JSON plugin orderspackage.jsonkeys canonically). The editor language server is TypeScript 7's nativetsc --lsp --stdio;typescript-language-serverand the TypeScript 5.9.3tsserveralias are gone, so TypeScript 7 is the only TypeScript in the repo.bun run lintreports no warnings. - Live tests cover the DSS 15 gap actions: column/partition dataset reads, dataset checks, flow schema propagation and documentation, the MLflow extension, Visual ML diagnostics, documentation, re-guessing and time series forecasting, the new Project Deployer settings, governance and delete actions, workspace object removal, discussion topic edits, future listing, wiki settings, and data-quality instance/partition status. Lab teardown deletes Project Deployer infras and published projects through
project-deployer delete-infra/delete-projectinstead of raw API calls.
3.6.1
- Fix: the Node-launched
dsschecks the Bun version (release part only, so canary builds pass) before spawning Bun, so an old Bun gets the JSON error instead of its own argument-parsing failure. batch --dry-runhas a regression test proving it applies the same meta-command flag checks as a direct run.- Remove the unused
DSS_LOAD_SOURCElauncher variable; load source comes only from where the CLI module actually lives.
3.6.0
- Fix: a non-2xx response whose body misses the request deadline keeps its real HTTP status instead of becoming a bare network timeout.
- Fix:
target_absence_unverifiable(a masked403on an explicit target key) exits 2 like other permission/environment failures; exit 1 is reserved for usage errors. - Fix: an environment variable set to
""counts as set everywhere, so.envcan no longer fill it (DATAIKU_URL=""clears a.envvalue). - Fix:
bin/dss.jsruns source in a checkout instead of a leftoverdist/, never trusts an inheritedDSS_LOAD_SOURCE/DSS_BUILD_REVISION, and checks the Bun version againstengines.bunbefore running, with a JSON error. - Release: the
versionlifecycle moves## Unreleasedentries under the new version heading, andbun run checkfails when the current version has no section; the history is split into 3.2.0–3.5.0 sections by release tag. - Packaging: stop building and shipping the unreachable
packages/types/dist/;prepublishOnlyreusesprepack; drop the duplicatebundledDependencies. - Internal: one meta-command validator for direct and batch runs; one argv positional scanner; no in-loop re-check of cleanup incarnation bindings; one
isRecord/asRecord; saved-model validators live inresources/base.ts;Content-Typeis sent only with a body;retryMaxAttemptsis documented as total attempts. - Docs: skill names
dss doctor, drops SDK test-fixture text, and states the one empty-variable rule; README token figures defer tobun run test:tokens; a test now machine-checks the API coverage matrix counts and every CLI/SDK mapping;.gitignorecoversinstall-skillproject targets.
3.5.0
- CI tests both the minimum supported Bun (1.4.0) and the latest (1.4.2) on all three operating systems; the release workflow runs 1.4.2;
@types/bun^1.4.2. - Lint:
dss/no-uncoded-errorsrejects built-inError/TypeError/RangeError/SyntaxErrorthrows andreject(new Error(...))anywhere insrc/;no-raw-json-parse-in-resourcesrequires resourceJSON.parseto sit in thetryblock of a try/catch;no-usage-literalsrejects hand-written usage text;no-direct-process-envconfines environment reads toenv.ts,runtime.ts, andconfig.ts(the few other reads carry a justified disable comment).node:cryptocreateHashis restricted tosha256Hexinsrc/.bun run lintnow covers all oftests/andscripts/. - Every error the SDK and CLI raise now carries a stable code; nothing reaches agents as an uncoded
internal_errorby accident. Caller and state problems arevalidation_failed(exit 1); a missing project key, URL, or API key from the SDK client ismissing_required_flag(exit 1, matched by type instead of by message text); a bad CA bundle path isinvalid_flag_value; malformed 2xx DSS responses (missing body, id, job id, recipe name, archive member) are one canonicalDataikuErrorclassifiedunexpected_response(exit 2) viaunexpectedResponseError, and non-JSON bodies use the existingnonJsonResponseBodyform; Project Git future failures and timeouts arelong_running_failure(exit 4); genuine invariants (missing bundled skill, missing command syntax, stalled local writes) are explicitinternal_error(exit 2). - Fix: 113 more hand-written usage strings in
requireArgscalls andUsage:messages are rendered from the command syntax; many had drifted from the real syntax. - Security:
.envfiles now supply onlyDATAIKU_*,NODE_TLS_REJECT_UNAUTHORIZED, andNODE_EXTRA_CA_CERTS; other keys are ignored, so a project.envcan no longer redirectDSS_CONFIG_DIR(and with it saved credentials). - Fix:
cleanup --dry-run --applyis now a usage error instead of running the destructive replay;auth login --dry-runis rejected instead of logging in and saving credentials; meta commands (doctor,auth,install-skill,agent,version,cleanup,fixtures,batch) now reject flags they do not support. - Fix:
--expect-hashaccepts uppercase hex in both the SDK and CLIcode-env set-definitionpaths (including--dry-run); commands without a plan mode (e.g.doctor,fixtures) reject--planinstead of running live;auth loginadvertises its--planpreview. - Fix: SQL query failures surface as DSS
validation_failederrors (exit 2, true 2xx status) and non-JSON SQL result streams asunexpected_response, instead ofinternal_error; non-JSON bodies are summarized by one shared helper. - Fix:
batch --dry-runstep errors report their own step's resource/action instead of a concurrently validated sibling's. - Fix:
--plannow matches the request actually sent forscenario create(default params),scenario active-set(merged light status, listed underrequests),flow-zone create(default color, no strayprojectKey),dataset createandrecipe create(both built by the same body builders as the real request),folder create(fullparams),saved-model evaluate-version(query flags),plugin install-from-git/update-from-git/create-dev(null git fields),plugin rename/move(leading-slash paths),bundle export(no body), andwiki create(content is a follow-up update, listed underrequests). A test now runs every documented write example with--planand for real against a mock server and requires identical method, endpoint, and body, skipping plans markedexact: falseand deliberately redacted payloads. - Security:
plugin create-dev --planno longer echoes credentials embedded in--repository; the URL is validated likeinstall-from-git. - Command syntax is now structured data:
src/cli/command-syntax.jsonholds a syntax tree per command (words, positionals, flags with value/enum/note, optional groups, required choices). Everyusageline is rendered from it, and the contract fields (flags, required flags and choices, value hints, positionals, stdin/data inputs, dry-run, local-file output, aliases, project scope, idempotency flags, cleanup commands) are derived by walking it; the regex parsing of usage prose is gone, as are 281 hand-copied usage strings in handler error messages (now rendered) and 26 abbreviatedUsage:messages that had drifted (e.g.scenario active-set <id> <true|false>). The registry is byte-identical except:recipe clonenow advertises its optionalsourcepositional (the old parser only recognized uppercase positionals in choices), andwiki update/insight createrender their required choice with uniform|separators. - Fix:
batch --dry-runacceptsnotebook unload-jupyter --all; the CLI's required-positional count had treated<name> <sessionId>as required even though--allreplaces them, contradicting the registry. - Plans that depend on live DSS state (
dataset clone,folder createwithout--connection,variable set,app create-instancewith a generated key,saved-model import-mlflow-version-from-folder) now say so withexact: falseand areason, likerecipe runandapi-service add-prediction-endpoint, instead of placeholder values. - Remove the unused
src/utils/pagination.ts, the strayProduct_Aggregated.csv.gzandVALIDATION-2026-09-14.md; share one SHA-256 helper and case-insensitive hash pattern, one set of poll defaults, and one schema export surface (export *), which also restores the previously droppedCodeEnvLogSummaryArrayandSqlNotebookHistoryexports. - CI runs on pull requests and pushes to
main; SECURITY.md covers the current3.xline; docs no longer claim--dry-runnever contacts DSS, list the removed--jsonflag, or deny thedss pluginauthoring commands. CLI test harness defaults toDATAIKU_DISABLE_ENV=1so the checkout.envcannot leak into tests. - Direct skill agents to always invoke the installed
dsscommand instead of callingbin/dss.jsthrough Bun; clarify source/built.envlookup and environment-only login, reducing skill and authentication guidance without removing safety requirements.
3.4.0
- Flush dataset CSV exports in bounded batches (64 KiB) at row boundaries, before truncation limits, and at EOF: byte-identical output while a 200k-row (8.96 MB) export drops from 16.6 s to 0.5 s.
- Honor
DataikuGetOptions.noRetryin the clientgetpath and Git transport, and give every futures, jobs, ML-training, and Project Git wait loop a spent-budget single observation: the first request always happens (capped by the per-request timeout), no later request starts after the budget expires, and the structured timeout reports the last observed state without clamping the first request. - Serve CLI discovery output schemas from the committed
src/generated/action-output-schemas.json:buildregenerates it ahead oftsc, whilecheckandprepack/prepublishOnlyverify freshness (after and before compilation respectively); full-registry and scoped contract bytes are unchanged, source checkouts work withoutdist, and scoped discovery latency drops by about half. - Enforce the project map metadata budget through the client's total request timeout (1500 ms), distinguishing deadline expiry from earlier per-request failures;
FlowZones.listacceptsDataikuGetOptions. - Correct skill release examples to snapshot permissions before mutations and reserve cleanup for rollback; remove the blanket credential-free planning claim and document schema file input and unfiltered log export.
- Honor
Retry-Afterseconds and HTTP dates within existing retry eligibility, the 30-second automatic wait cap, and total request deadlines. - Materialize discovery entries per action and schemas on access; defer runtime-only SDK imports while preserving full registry output.
- Extract the first visible HTML error line without allocating an array for every line, retaining carriage returns, decoding, and sanitization.
- Serialize releases around one versioned, integrity-checked tarball tested on every platform; verify npm metadata and canonical download availability before pushing the candidate commit/tag atomically. Preserve candidates for safe failed-job recovery without automatic republishing.
3.3.0
- Use platform-aware basenames for local MLflow archive uploads, keeping Windows parent directories out of multipart filenames.
- Build scoped discovery metadata only for requested resources, generate action indexes without payload schemas, and lazily materialize bootstrap sections; preserve registry bytes and global missing-field recovery hints.
- Bound SDK HTTP error bodies using the configured response limit, preserve UTF-8 boundaries and retry/deadline rules, and expose trusted truncation state through error wrappers and CLI diagnostics.
- Route skill discovery directly to full entries for writes and resource-only action indexes; accelerate optional native token measurements while retaining pinned JS parity and validation checks.
- Validate real Application Designer download-folder and form-variable references; report deleted download folders instead of silently skipping them.
- Self-provision owned Application Designer templates in the live suite, exercise variable/scenario/download and version workflows, and retire only proven unused creation reservations without cleanup requests or project-key reuse.
- Let
app create-instancegenerate a cryptographically random project key whentargetProjectKeyis omitted, preserving the display name without requiring global project visibility. Keep strict checks for explicit keys, future/cleanup identity guards, and allocation-free plans; expose fresh-key creation in masked-403 recovery guidance. - Let
app successor-preflightandapp create-successor-instanceomit--toand generate the successor target key during apply: preflight, plan, and dry-run stay targetless and allocation-free (targetProjectKeyGeneratedDuringApply,targetPreflight:"not-applicable-generated-key"), source/template/optional-ACL gates still run, the key is generated once before the single POST, cleanup binds the creation future pluscreationTag, and an explicit--tokeeps the strict masked-403 absence guard with no POST. - Preserve bounded, credential-redacted DSS messages and error types in ambiguous mutation failures without enabling retries or weakening unknown-outcome handling.
- Require app-release sharing checks: snapshot and compare intended users, groups, and roles; restore approved missing access without dropping newer grants, then verify with the intended identities.
- Preserve guarded app-deletion receipts and host ownership markers across cleanup failures; remove empty private host directories without widening their permissions.
- Use owned Filesystem fixtures with two-principal inherited ACLs, DSS-selected managed-folder storage, and native-only code-environment rebuilds in live verification.
- Keep unavailable dashboard rendering and meaning deletion explicitly blocked, but optional in current-capability live runs.
- Exercise App catalog reads against owned templates and attribute successful group reads to the read-only directory case instead of blocked account creation.
- Make the app-release rollback example apply cleanup explicitly; distinguish mutation with
--applyfrom the default preview. - Enforce project-owned accumulator-copy, widen-then-assert, and chained-assertion lint rules alongside the native accumulating-spread check. Remove double assertions through typed merge results, direct schema assignments, shared raw-body/Git transport methods, and iterable response streams.
- Add 113 CLI actions across eight new resource families and expanded scenario, metadata, dataset, saved-model, and connection APIs, with SDK exports and mutation preview contracts.
- Add LLMs, knowledge banks, project folders, data collections, users, groups, macros, and plugin administration; include MLflow imports and scoring exports.
- Bound ML training and macro status waits across requests, retries, and response bodies; preserve per-request timeout caps and distinguish request expiry from overall wait expiry. Use adaptive future and Project Git polling unless an interval is explicit.
- Keep early CLI usage errors lightweight with resource-local command loading while preserving structured errors.
- Reject malformed directory and scenario-history responses and missing run identifiers; consolidate SDK identifier validation and recursive secret sanitization.
- Use
nextconsistently in metadata previews. Normalize commands toproject-folder settings-get/settings-set,data-collection settings-set, andscenario payload-get/payload-set/active-set; remove the old names. - Remeasure and verify native cross-model discovery-token baselines after API expansion and command renames.
- Publish the DSS 15 API-to-SDK-to-CLI coverage matrix, including remaining gaps and documented endpoint discrepancies.
- Expand the self-provisioning live runner with an
--profile allselector that widens run-case availability to every profile inside one persistent lab (distinct from the destructivealllifecycle verb), persistent--state-dirdemo labs, retained trained-ML state across iterations, and new expanded case families (bundles, Project Git, scenario statistics/payloads, application manifests, webapp backend state, infrastructure reads, disposable folders/notebooks, disposable global lifecycles). - Add isolated-disposable global case families (users, groups, meanings, workspaces, data collections, API-deployer infra/services/deployments, plugins, project folders) guarded by exact lab-manifest reservations and ownership markers (
ctx.markerFor; code-envs bind on the serverdesc.creationTagincarnation snapshot), with per-command identity re-verification, never-delete-blind conflict handling, and no modification of pre-existing accounts or configuration. - Record explicit per-action unavailability for licensed or disabled instance features, external deployment/auth backends, plugin-store access, and cost-bearing LLM/macro surfaces; every registered action stays enumerated as demonstrated, blocked with a recorded prerequisite, or uncovered, with no silent omissions.
- Serve
plugin git-brancheswith GET: DSS 15 rejects POST on that route with 405rawMethodPOSTnotsupporteddespite the public documentation listing POST. - Clarify
code-env set-packagesclearing semantics: the package list is replaced wholesale, so an explicitly empty--packagesvalue (or an empty--file) clears the requested specs, while a call with no package source flag is a usage error. - Exercise plugin-managed code environments explicitly in the live harness: derived environments are deleted before the parent plugin (no server-side cascade) and plugin updates link the
settings.codeEnvNameassociation created after plugin creation; MLflow import fixtures use canonicalcode/data/envpackaging inside owned runtime environments. - Require the DSS 15
containerExecConfigNameparameter explicitly on MLflow imports and evaluations: sendNONEfor archive imports, folder imports, and evaluation bodies (folder imports no longer inherit), with plan parity and regression coverage.
3.2.0
- Optimize all seven skill references, cutting their combined OpenAI text-token count by 15.2% while preserving runnable examples and safety conditions; add per-reference budgets.
- Reduce installed-skill tokens by about 12% across model encodings and shorten discovery prose, retaining safety guidance, schema contracts, and reference links; tighten the skill budget to prevent regrowth.
- Add opt-in cross-model discovery token budgets using an external OMP native module, preserving the mandatory pinned OpenAI gate and adding no production dependency.
- Preserve request IDs and trusted target/timing metadata when enriching SQL failures.
- Treat SQLite missing-column and missing-table errors as nonretryable validation failures, including when SQL start retries are explicitly enabled; preserve ambiguous mutation outcomes.
- Decode bounded HTTP text incrementally to reduce large-response allocations while retaining byte limits, read deadlines, and UTF-8 truncation behavior.
- Load CLI command dependencies lazily and build only the selected resource registry during validation, preserving full discovery contracts.
- Publish SQL JSON exports atomically after query completion, retaining existing permission bits and using the process umask for new files; preserve existing destinations on failure and avoid iterable-string file writes.
- Add a separate, self-provisioning
test:liverunner with persistent setup/run/clean, upfront case validation, optional capability profiles, guarded ownership and local outputs, failure-preserving cleanup journals, deterministic fixtures, explicit registry coverage reports, and regular type/lint gates. - Normalize explicit boolean flag values and aliases before dispatch; share plan/dry-run resolution across direct, batch, and local commands.
- Bound stalled streaming body reads without imposing a total-duration limit on healthy archive transfers; use backpressure-aware file streaming and publish archive/folder outputs only after completion, preserving existing files on failure.
- Report unreadable JSON/text input files as structured usage errors rather than internal failures.
- Report the actual home target for global skill installation.
- Split the Dataiku skill into a short entrypoint and seven on-demand references; install and hash the complete bundle, detect incomplete reference trees, and preserve unrelated destination files.