@aiwg/cli 2026.9.0 → 2026.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +41 -0
  2. package/agentic/code/providers/model-capabilities.v1.json +11 -0
  3. package/agentic/code/providers/model-catalog.v1.json +8 -0
  4. package/agentic/code/providers/pi/aiwg-bridge.ts +26 -0
  5. package/bin/aiwg.mjs +15 -3
  6. package/dist/src/api/index.d.ts +3 -0
  7. package/dist/src/api/index.js +3 -0
  8. package/dist/src/auth/credential-store.js +6 -0
  9. package/dist/src/channel/manager.mjs +2 -2
  10. package/dist/src/cli/handlers/dataset.js +186 -0
  11. package/dist/src/cli/handlers/help.js +2 -1
  12. package/dist/src/cli/handlers/index.js +5 -1
  13. package/dist/src/cli/handlers/init.js +1 -0
  14. package/dist/src/cli/handlers/output-mode.js +18 -1
  15. package/dist/src/cli/handlers/run.js +11 -3
  16. package/dist/src/cli/handlers/schema.js +221 -0
  17. package/dist/src/cli/handlers/sessions.js +30 -12
  18. package/dist/src/cli/handlers/steward.js +11 -1
  19. package/dist/src/cli/handlers/use.js +6 -2
  20. package/dist/src/cli/hooks/builtin/activity-log-hook.js +6 -0
  21. package/dist/src/cli/router.js +1 -1
  22. package/dist/src/cli/scope-resolver.js +22 -0
  23. package/dist/src/dataset/adapter-sdk.d.ts +41 -0
  24. package/dist/src/dataset/adapter-sdk.js +147 -0
  25. package/dist/src/dataset/adapter-types.d.ts +179 -0
  26. package/dist/src/dataset/adapter-types.js +2 -0
  27. package/dist/src/dataset/adapters.d.ts +104 -0
  28. package/dist/src/dataset/adapters.js +518 -0
  29. package/dist/src/dataset/conformance-types.d.ts +84 -0
  30. package/dist/src/dataset/conformance-types.js +3 -0
  31. package/dist/src/dataset/conformance.d.ts +13 -0
  32. package/dist/src/dataset/conformance.js +90 -0
  33. package/dist/src/dataset/contracts.d.ts +17 -0
  34. package/dist/src/dataset/contracts.js +236 -0
  35. package/dist/src/dataset/file-orchestration-repository.d.ts +19 -0
  36. package/dist/src/dataset/file-orchestration-repository.js +68 -0
  37. package/dist/src/dataset/fortemi-execution-bridge.d.ts +33 -0
  38. package/dist/src/dataset/fortemi-execution-bridge.js +35 -0
  39. package/dist/src/dataset/index.d.ts +21 -0
  40. package/dist/src/dataset/index.js +21 -0
  41. package/dist/src/dataset/ledger-types.d.ts +141 -0
  42. package/dist/src/dataset/ledger-types.js +2 -0
  43. package/dist/src/dataset/ledger.d.ts +27 -0
  44. package/dist/src/dataset/ledger.js +100 -0
  45. package/dist/src/dataset/local-execution-backend.d.ts +10 -0
  46. package/dist/src/dataset/local-execution-backend.js +32 -0
  47. package/dist/src/dataset/orchestration-repository.d.ts +29 -0
  48. package/dist/src/dataset/orchestration-repository.js +34 -0
  49. package/dist/src/dataset/orchestration-service.d.ts +56 -0
  50. package/dist/src/dataset/orchestration-service.js +466 -0
  51. package/dist/src/dataset/orchestration-types.d.ts +83 -0
  52. package/dist/src/dataset/orchestration-types.js +2 -0
  53. package/dist/src/dataset/presentation.d.ts +3 -0
  54. package/dist/src/dataset/presentation.js +8 -0
  55. package/dist/src/dataset/projections.d.ts +42 -0
  56. package/dist/src/dataset/projections.js +192 -0
  57. package/dist/src/dataset/schema-governance.d.ts +71 -0
  58. package/dist/src/dataset/schema-governance.js +135 -0
  59. package/dist/src/dataset/standards-types.d.ts +66 -0
  60. package/dist/src/dataset/standards-types.js +10 -0
  61. package/dist/src/dataset/standards.d.ts +13 -0
  62. package/dist/src/dataset/standards.js +291 -0
  63. package/dist/src/dataset/types.d.ts +258 -0
  64. package/dist/src/dataset/types.js +2 -0
  65. package/dist/src/extensions/commands/definitions.js +27 -1
  66. package/dist/src/installation/manager.mjs +5 -1
  67. package/dist/src/models/model-capabilities.v1.json +11 -0
  68. package/dist/src/models/model-catalog.v1.json +8 -0
  69. package/dist/src/models/model-discovery.js +32 -0
  70. package/dist/src/models/provider-policy.js +3 -2
  71. package/dist/src/output-modes/index.js +4 -0
  72. package/dist/src/output-modes/registry.js +68 -24
  73. package/dist/src/output-modes/runtime.js +10 -8
  74. package/dist/src/plugin/skill-command-translator.js +1 -0
  75. package/dist/src/providers/capability-matrix.yaml +41 -0
  76. package/dist/src/providers/provider-definitions.js +72 -0
  77. package/dist/src/providers/provider-inventory.js +1 -0
  78. package/dist/src/schema/catalog.js +234 -0
  79. package/dist/src/schema/compatibility.js +42 -0
  80. package/dist/src/schema/diagnostics.js +36 -0
  81. package/dist/src/schema/index.js +8 -0
  82. package/dist/src/schema/policy.js +58 -0
  83. package/dist/src/schema/resolver.js +76 -0
  84. package/dist/src/schema/types.js +2 -0
  85. package/dist/src/schema/validator.js +82 -0
  86. package/dist/src/sessions/adapters/pi.js +141 -0
  87. package/dist/src/sessions/contracts.js +1 -1
  88. package/dist/src/sessions/index.js +1 -0
  89. package/dist/src/sessions/workspace-discovery.js +10 -0
  90. package/dist/src/storage/backends/fortemi.js +6 -0
  91. package/dist/src/storage/config.js +18 -4
  92. package/dist/src/storage/fortemi-qualification.js +106 -0
  93. package/dist/src/storage/index.js +1 -0
  94. package/dist/src/storage/types.js +1 -1
  95. package/package.json +3 -1
  96. package/schemas/dataset/conformance-manifest.v1.schema.json +35 -0
  97. package/schemas/dataset/conformance-receipt.v1.schema.json +22 -0
  98. package/schemas/dataset/dataset-contracts.v1.schema.json +117 -0
  99. package/schemas/dataset/dataset-deprecations.v1.schema.json +37 -0
  100. package/schemas/dataset/dataset-schema-governance.v1.schema.json +92 -0
  101. package/schemas/dataset/dataset-standards-exchange.v1.schema.json +59 -0
  102. package/schemas/dataset/profiles/openlineage-1.0.0.schema.json +15 -0
  103. package/schemas/dataset/profiles/prov-json-20130430.schema.json +12 -0
  104. package/schemas/dataset/run-ledger.v1.schema.json +39 -0
  105. package/schemas/dataset/source-adapter.v1.schema.json +112 -0
  106. package/tools/agents/deploy-agents.mjs +9 -3
  107. package/tools/agents/providers/pi.mjs +176 -0
@@ -0,0 +1,291 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import Ajv2020 from 'ajv/dist/2020.js';
6
+ import addFormats from 'ajv-formats';
7
+ import { createLedgerEvent } from './ledger.js';
8
+ import { RUN_LEDGER_VERSION } from './ledger-types.js';
9
+ import { STANDARDS_EXCHANGE_VERSION, StandardsProfileError, } from './standards-types.js';
10
+ const AIWG_EXTENSION_ROOT = 'https://aiwg.io/ns/dataset-standards/';
11
+ const PRODUCER = { id: 'aiwg:standards-adapter', version: '1.0.0' };
12
+ const IMPORTED_AT = '1970-01-01T00:00:00.000Z';
13
+ function packageRoot(start) {
14
+ let current = resolve(start);
15
+ for (;;) {
16
+ try {
17
+ const manifest = JSON.parse(readFileSync(join(current, 'package.json'), 'utf8'));
18
+ if (manifest.name === 'aiwg' || manifest.name === '@aiwg/cli')
19
+ return current;
20
+ }
21
+ catch { /* source and compiled modules have different depths */ }
22
+ const parent = dirname(current);
23
+ if (parent === current)
24
+ throw new Error('dataset standards: could not locate the aiwg package root');
25
+ current = parent;
26
+ }
27
+ }
28
+ const root = packageRoot(dirname(fileURLToPath(import.meta.url)));
29
+ const ajv = new Ajv2020({ strict: true, allErrors: true });
30
+ addFormats(ajv);
31
+ function compileSchema(name) { return ajv.compile(JSON.parse(readFileSync(join(root, 'schemas/dataset/profiles', name), 'utf8'))); }
32
+ const validateProvDocument = compileSchema('prov-json-20130430.schema.json');
33
+ const validateOpenLineageDocument = compileSchema('openlineage-1.0.0.schema.json');
34
+ function stable(value) {
35
+ if (Array.isArray(value))
36
+ return `[${value.map(stable).join(',')}]`;
37
+ if (value && typeof value === 'object')
38
+ return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${stable(item)}`).join(',')}}`;
39
+ return JSON.stringify(value);
40
+ }
41
+ function digest(value) { return { algorithm: 'sha256', value: createHash('sha256').update(stable(value)).digest('hex') }; }
42
+ function loss(profile, direction, source, items) {
43
+ const counts = { mapped: 0, omitted: 0, synthesized: 0, unsupported: 0, 'extension-carried': 0 };
44
+ for (const item of items)
45
+ counts[item.category]++;
46
+ return { schemaVersion: STANDARDS_EXCHANGE_VERSION, profileId: profile.id, profileVersion: profile.version, direction, sourceDigest: digest(source), items, counts };
47
+ }
48
+ function exchange(profile, direction, source, value, items) {
49
+ return { schemaVersion: STANDARDS_EXCHANGE_VERSION, profile: { id: profile.id, version: profile.version }, value, loss: loss(profile, direction, source, items) };
50
+ }
51
+ function isObject(value) { return Boolean(value) && typeof value === 'object' && !Array.isArray(value); }
52
+ function invalid(code, detail) { throw new StandardsProfileError(code, detail); }
53
+ function validateDocument(validate, value, direction) {
54
+ if (!validate(value))
55
+ invalid(direction === 'input' ? 'DATASET_STANDARD_INVALID_INPUT' : 'DATASET_STANDARD_INVALID_OUTPUT', ajv.errorsText(validate.errors, { separator: '; ' }));
56
+ }
57
+ function event(record, sequence) { return createLedgerEvent({ eventId: `urn:aiwg:standards:event:${sequence}:${encodeURIComponent(record.id)}`, sequence, recordedAt: IMPORTED_AT, producer: PRODUCER, record }); }
58
+ function assertion(id, subjectId, predicate, objectId) {
59
+ return { recordType: 'assertion', id, subjectId, predicate, objectId, basis: 'imported', evidenceIds: [], privacy: 'internal' };
60
+ }
61
+ function entries(value, path) {
62
+ if (value === undefined)
63
+ return [];
64
+ if (!isObject(value))
65
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path} must be an object`);
66
+ return Object.entries(value).map(([id, item]) => {
67
+ if (!isObject(item))
68
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path}/${id} must be an object`);
69
+ return [id, item];
70
+ });
71
+ }
72
+ function ensureLedger(snapshot) {
73
+ if (!isObject(snapshot) || snapshot.schemaVersion !== RUN_LEDGER_VERSION || !Array.isArray(snapshot.events))
74
+ invalid('DATASET_STANDARD_INVALID_INPUT', 'canonical input must be a run-ledger/v1 snapshot');
75
+ }
76
+ function extensionItems(document, known, descriptor) {
77
+ const items = [];
78
+ for (const key of Object.keys(document))
79
+ if (!known.has(key)) {
80
+ if (key.startsWith(AIWG_EXTENSION_ROOT) && !key.startsWith(descriptor.extensionNamespace))
81
+ throw new StandardsProfileError('DATASET_STANDARD_EXTENSION_COLLISION', `${key} collides with the reserved AIWG namespace`);
82
+ items.push({ category: descriptor.unknownExtensionPolicy === 'preserve' ? 'extension-carried' : 'unsupported', sourcePath: `/${key}`, reason: 'unknown top-level extension', ...(descriptor.unknownExtensionPolicy === 'preserve' ? { extensionNamespace: descriptor.extensionNamespace } : {}) });
83
+ }
84
+ return items;
85
+ }
86
+ export const PROV_PROFILE = Object.freeze({
87
+ id: 'w3c-prov-json/20130430', standard: 'w3c-prov-json', version: '2013-04-30', direction: 'round-trip',
88
+ inputSchema: { id: 'https://aiwg.io/schemas/dataset/profiles/prov-json-20130430.schema.json', version: '1.0.0' },
89
+ outputSchema: { id: 'https://aiwg.io/schemas/dataset/profiles/prov-json-20130430.schema.json', version: '1.0.0' },
90
+ mappingImplementation: 'src/dataset/standards.ts#provAdapter',
91
+ supportedFeatures: ['entity', 'activity', 'agent', 'wasDerivedFrom', 'wasGeneratedBy', 'used', 'wasAttributedTo', 'wasAssociatedWith', 'correction'],
92
+ roundTripFields: ['entity', 'activity', 'agent', 'wasDerivedFrom', 'wasGeneratedBy', 'used', 'wasAttributedTo', 'wasAssociatedWith'],
93
+ extensionNamespace: `${AIWG_EXTENSION_ROOT}prov-json/20130430/`, unknownExtensionPolicy: 'report', maturity: 'stable',
94
+ useCases: ['exchange canonical dataset and run lineage with PROV-JSON consumers'], coverageBoundary: 'PROV-JSON core entity/activity/agent and eight listed relation/history mappings; qualified relations and bundles are unsupported',
95
+ });
96
+ function importProv(document) {
97
+ validateDocument(validateProvDocument, document, 'input');
98
+ if (!isObject(document))
99
+ invalid('DATASET_STANDARD_INVALID_INPUT', 'PROV-JSON document must be an object');
100
+ const items = extensionItems(document, new Set(['prefix', 'entity', 'activity', 'agent', 'wasDerivedFrom', 'wasGeneratedBy', 'used', 'wasAttributedTo', 'wasAssociatedWith', 'alternateOf']), PROV_PROFILE);
101
+ const events = [];
102
+ let sequence = 1;
103
+ const entityEntries = entries(document.entity, '/entity');
104
+ const activityEntries = entries(document.activity, '/activity');
105
+ const agentEntries = entries(document.agent, '/agent');
106
+ const identities = [...entityEntries.map(([id]) => id), ...activityEntries.map(([id]) => id), ...agentEntries.map(([id]) => id)];
107
+ if (new Set(identities).size !== identities.length)
108
+ throw new StandardsProfileError('DATASET_STANDARD_IDENTITY_CONFLICT', 'an identifier cannot be both an entity, activity, or agent');
109
+ for (const [id, attrs] of entityEntries)
110
+ events.push(event({ recordType: 'entity', id, entityType: String(attrs['prov:type'] ?? 'entity'), privacy: 'internal' }, sequence++));
111
+ for (const [id, attrs] of activityEntries)
112
+ events.push(event({ recordType: 'activity', id, activityType: String(attrs['prov:type'] ?? 'activity'), ...(typeof attrs['prov:startTime'] === 'string' ? { startedAt: attrs['prov:startTime'] } : {}), ...(typeof attrs['prov:endTime'] === 'string' ? { endedAt: attrs['prov:endTime'] } : {}) }, sequence++));
113
+ for (const [id, attrs] of agentEntries)
114
+ events.push(event({ recordType: 'agent', id, principalKind: attrs['prov:type'] === 'prov:Person' ? 'person' : attrs['prov:type'] === 'prov:Organization' ? 'organization' : 'software' }, sequence++));
115
+ const relations = [
116
+ ['wasDerivedFrom', 'prov:generatedEntity', 'prov:usedEntity'], ['wasGeneratedBy', 'prov:entity', 'prov:activity'], ['used', 'prov:activity', 'prov:entity'],
117
+ ['wasAttributedTo', 'prov:entity', 'prov:agent'], ['wasAssociatedWith', 'prov:activity', 'prov:agent'], ['alternateOf', 'prov:alternate1', 'prov:alternate2'],
118
+ ];
119
+ for (const [relation, subjectKey, objectKey] of relations)
120
+ for (const [id, attrs] of entries(document[relation], `/${relation}`)) {
121
+ const subject = attrs[subjectKey], object = attrs[objectKey];
122
+ if (typeof subject !== 'string' || typeof object !== 'string')
123
+ invalid('DATASET_STANDARD_INVALID_INPUT', `/${relation}/${id} requires ${subjectKey} and ${objectKey}`);
124
+ const predicate = relation === 'alternateOf' ? 'correction' : relation;
125
+ if (predicate === 'correction')
126
+ events.push(event({ recordType: 'correction', id, correctsEventId: subject, replacementEventId: object, reason: 'imported PROV alternateOf relation', responsibleAgentId: PRODUCER.id }, sequence++));
127
+ else
128
+ events.push(event(assertion(id, subject, predicate, object), sequence++));
129
+ items.push({ category: 'mapped', sourcePath: `/${relation}/${id}`, targetPath: `/events/${events.length - 1}`, reason: `${relation} mapped to canonical ledger` });
130
+ }
131
+ for (const section of ['entity', 'activity', 'agent'])
132
+ for (const [id] of entries(document[section], `/${section}`))
133
+ items.push({ category: 'mapped', sourcePath: `/${section}/${id}`, targetPath: `/events/${events.findIndex(item => item.record.id === id)}`, reason: `${section} mapped to canonical ledger` });
134
+ items.push({ category: 'synthesized', targetPath: '/events/*/recordedAt', reason: 'PROV-JSON has no document observation timestamp; deterministic import epoch used' });
135
+ return exchange(PROV_PROFILE, 'import', document, { schemaVersion: RUN_LEDGER_VERSION, events }, items);
136
+ }
137
+ function exportProv(snapshot) {
138
+ ensureLedger(snapshot);
139
+ const document = { prefix: { aiwg: 'https://aiwg.io/ns/' }, entity: {}, activity: {}, agent: {}, wasDerivedFrom: {}, wasGeneratedBy: {}, used: {}, wasAttributedTo: {}, wasAssociatedWith: {}, alternateOf: {} };
140
+ const items = [];
141
+ for (const item of snapshot.events) {
142
+ const record = item.record;
143
+ if (record.recordType === 'entity')
144
+ document.entity[record.id] = { 'prov:type': record.entityType };
145
+ else if (record.recordType === 'activity')
146
+ document.activity[record.id] = { 'prov:type': record.activityType, ...(record.startedAt ? { 'prov:startTime': record.startedAt } : {}), ...(record.endedAt ? { 'prov:endTime': record.endedAt } : {}) };
147
+ else if (record.recordType === 'agent')
148
+ document.agent[record.id] = { 'prov:type': record.principalKind === 'person' ? 'prov:Person' : record.principalKind === 'organization' ? 'prov:Organization' : 'prov:SoftwareAgent' };
149
+ else if (record.recordType === 'assertion' && ['wasDerivedFrom', 'wasGeneratedBy', 'used', 'wasAttributedTo', 'wasAssociatedWith'].includes(record.predicate)) {
150
+ const keys = { wasDerivedFrom: ['prov:generatedEntity', 'prov:usedEntity'], wasGeneratedBy: ['prov:entity', 'prov:activity'], used: ['prov:activity', 'prov:entity'], wasAttributedTo: ['prov:entity', 'prov:agent'], wasAssociatedWith: ['prov:activity', 'prov:agent'] };
151
+ const [a, b] = keys[record.predicate];
152
+ document[record.predicate][record.id] = { [a]: record.subjectId, [b]: record.objectId };
153
+ }
154
+ else if (record.recordType === 'correction' && record.replacementEventId)
155
+ document.alternateOf[record.id] = { 'prov:alternate1': record.correctsEventId, 'prov:alternate2': record.replacementEventId };
156
+ else {
157
+ items.push({ category: 'unsupported', sourcePath: `/events/${item.sequence - 1}`, reason: `${record.recordType}${record.recordType === 'assertion' ? `:${record.predicate}` : ''} is outside the declared PROV profile` });
158
+ continue;
159
+ }
160
+ items.push({ category: 'mapped', sourcePath: `/events/${item.sequence - 1}`, reason: `${record.recordType} mapped to PROV-JSON` });
161
+ if ('privacy' in record)
162
+ items.push({ category: 'omitted', sourcePath: `/events/${item.sequence - 1}/record/privacy`, reason: 'privacy classification is policy metadata and is not downgraded into PROV' });
163
+ }
164
+ validateDocument(validateProvDocument, document, 'output');
165
+ return exchange(PROV_PROFILE, 'export', snapshot, document, items);
166
+ }
167
+ export const OPENLINEAGE_PROFILE = Object.freeze({
168
+ id: 'openlineage/1.0.0', standard: 'openlineage', version: '1.0.0', direction: 'round-trip',
169
+ inputSchema: { id: 'https://aiwg.io/schemas/dataset/profiles/openlineage-1.0.0.schema.json', version: '1.0.0' }, outputSchema: { id: 'https://aiwg.io/schemas/dataset/profiles/openlineage-1.0.0.schema.json', version: '1.0.0' },
170
+ mappingImplementation: 'src/dataset/standards.ts#openLineageAdapter', supportedFeatures: ['job', 'run', 'inputs', 'outputs', 'eventTime', 'eventType', 'failure-state', 'dataset.facets.columnLineage'],
171
+ roundTripFields: ['job.namespace', 'job.name', 'run.runId', 'eventTime', 'eventType', 'inputs.namespace', 'inputs.name', 'outputs.namespace', 'outputs.name'],
172
+ extensionNamespace: `${AIWG_EXTENSION_ROOT}openlineage/1.0.0/`, unknownExtensionPolicy: 'report', maturity: 'stable',
173
+ useCases: ['exchange job and dataset execution lineage with OpenLineage producers and consumers'], coverageBoundary: 'single RunEvent with job/run/dataset identities, lifecycle timing/failure, and columnLineage facet; arbitrary facets are reported unsupported',
174
+ });
175
+ function olId(value, path) { if (!isObject(value) || typeof value.namespace !== 'string' || typeof value.name !== 'string')
176
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path} requires namespace and name`); return `${value.namespace}/${value.name}`; }
177
+ function importOpenLineage(document) {
178
+ validateDocument(validateOpenLineageDocument, document, 'input');
179
+ if (!isObject(document) || typeof document.eventTime !== 'string' || typeof document.eventType !== 'string' || !isObject(document.run) || typeof document.run.runId !== 'string')
180
+ invalid('DATASET_STANDARD_INVALID_INPUT', 'OpenLineage RunEvent requires eventTime, eventType, and run.runId');
181
+ const jobId = olId(document.job, '/job');
182
+ const items = extensionItems(document, new Set(['eventTime', 'eventType', 'run', 'job', 'inputs', 'outputs', 'producer', 'schemaURL']), OPENLINEAGE_PROFILE);
183
+ const events = [];
184
+ let sequence = 1;
185
+ events.push(createLedgerEvent({ eventId: `urn:aiwg:openlineage:${document.run.runId}:activity`, runId: document.run.runId, sequence: sequence++, recordedAt: document.eventTime, producer: PRODUCER, record: { recordType: 'activity', id: jobId, activityType: `openlineage:${document.eventType}`, runId: document.run.runId, ...(document.eventType === 'START' ? { startedAt: document.eventTime } : { endedAt: document.eventTime }) } }));
186
+ const mapDatasets = (datasets, predicate, path) => {
187
+ if (datasets === undefined)
188
+ return;
189
+ if (!Array.isArray(datasets))
190
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path} must be an array`);
191
+ for (const [index, dataset] of datasets.entries()) {
192
+ const id = olId(dataset, `${path}/${index}`);
193
+ events.push(event({ recordType: 'entity', id, entityType: 'dataset', privacy: 'internal' }, sequence++));
194
+ events.push(event(assertion(`openlineage:${predicate}:${sequence}`, predicate === 'used' ? jobId : id, predicate, predicate === 'used' ? id : jobId), sequence++));
195
+ items.push({ category: 'mapped', sourcePath: `${path}/${index}`, targetPath: `/events/${events.length - 2}`, reason: `dataset and ${predicate} relation mapped` });
196
+ if (isObject(dataset) && isObject(dataset.facets)) {
197
+ const facets = dataset.facets;
198
+ for (const facet of Object.keys(facets))
199
+ if (facet !== 'columnLineage')
200
+ items.push({ category: 'unsupported', sourcePath: `${path}/${index}/facets/${facet}`, reason: 'facet is outside the declared OpenLineage profile' });
201
+ if (isObject(facets.columnLineage) && isObject(facets.columnLineage.fields)) {
202
+ for (const [field, lineage] of Object.entries(facets.columnLineage.fields)) {
203
+ if (!isObject(lineage) || !Array.isArray(lineage.inputFields))
204
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path}/${index}/facets/columnLineage/fields/${field} requires inputFields`);
205
+ const outputFieldId = `${id}#field=${encodeURIComponent(field)}`;
206
+ events.push(event({ recordType: 'entity', id: outputFieldId, entityType: 'dataset-field', privacy: 'internal' }, sequence++));
207
+ for (const [inputIndex, input] of lineage.inputFields.entries()) {
208
+ if (!isObject(input) || typeof input.namespace !== 'string' || typeof input.name !== 'string' || typeof input.field !== 'string')
209
+ invalid('DATASET_STANDARD_INVALID_INPUT', `${path}/${index}/facets/columnLineage/fields/${field}/inputFields/${inputIndex} requires namespace, name, and field`);
210
+ const inputFieldId = `${input.namespace}/${input.name}#field=${encodeURIComponent(input.field)}`;
211
+ events.push(event({ recordType: 'entity', id: inputFieldId, entityType: 'dataset-field', privacy: 'internal' }, sequence++));
212
+ const relation = assertion(`openlineage:column:${sequence}`, outputFieldId, 'wasDerivedFrom', inputFieldId);
213
+ relation.field = field;
214
+ events.push(event(relation, sequence++));
215
+ items.push({ category: 'mapped', sourcePath: `${path}/${index}/facets/columnLineage/fields/${field}/inputFields/${inputIndex}`, targetPath: `/events/${events.length - 1}`, reason: 'column lineage mapped to a field-qualified canonical derivation' });
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+ };
222
+ mapDatasets(document.inputs, 'used', '/inputs');
223
+ mapDatasets(document.outputs, 'wasGeneratedBy', '/outputs');
224
+ items.push({ category: 'mapped', sourcePath: '/job', targetPath: '/events/0', reason: 'job/run lifecycle mapped to canonical activity' });
225
+ if (isObject(document.run.facets))
226
+ for (const facet of Object.keys(document.run.facets))
227
+ items.push({ category: 'unsupported', sourcePath: `/run/facets/${facet}`, reason: 'run facet is reported but not promoted into canonical observed evidence' });
228
+ return exchange(OPENLINEAGE_PROFILE, 'import', document, { schemaVersion: RUN_LEDGER_VERSION, events }, items);
229
+ }
230
+ function splitOlId(id) { const at = id.lastIndexOf('/'); return at > 0 ? { namespace: id.slice(0, at), name: id.slice(at + 1) } : { namespace: 'aiwg', name: id }; }
231
+ function exportOpenLineage(snapshot) {
232
+ ensureLedger(snapshot);
233
+ const activity = snapshot.events.find(item => item.record.recordType === 'activity')?.record;
234
+ if (!activity || activity.recordType !== 'activity' || !activity.runId)
235
+ invalid('DATASET_STANDARD_INVALID_OUTPUT', 'OpenLineage export requires an activity with runId');
236
+ const associations = snapshot.events.filter((item) => item.record.recordType === 'assertion');
237
+ const entityIds = new Set(snapshot.events.filter(item => item.record.recordType === 'entity').map(item => item.record.id));
238
+ const inputs = associations.filter(item => item.record.predicate === 'used' && item.record.subjectId === activity.id && entityIds.has(item.record.objectId)).map(item => splitOlId(item.record.objectId));
239
+ const outputs = associations.filter(item => item.record.predicate === 'wasGeneratedBy' && item.record.objectId === activity.id && entityIds.has(item.record.subjectId)).map(item => splitOlId(item.record.subjectId));
240
+ for (const relation of associations.filter(item => item.record.predicate === 'wasDerivedFrom' && item.record.field && item.record.subjectId.includes('#field=') && item.record.objectId.includes('#field='))) {
241
+ const [outputDataset, outputField] = relation.record.subjectId.split('#field=');
242
+ const [inputDataset, inputField] = relation.record.objectId.split('#field=');
243
+ const output = outputs.find(item => `${item.namespace}/${item.name}` === outputDataset);
244
+ if (!output)
245
+ continue;
246
+ const withFacets = output;
247
+ const facets = withFacets.facets ??= {};
248
+ const columnLineage = (facets.columnLineage ??= { fields: {} });
249
+ const decodedOutput = decodeURIComponent(outputField);
250
+ const entry = columnLineage.fields[decodedOutput] ??= { inputFields: [] };
251
+ entry.inputFields.push({ ...splitOlId(inputDataset), field: decodeURIComponent(inputField) });
252
+ }
253
+ const eventType = activity.activityType.replace(/^openlineage:/, '');
254
+ const allowed = new Set(['START', 'RUNNING', 'COMPLETE', 'ABORT', 'FAIL', 'OTHER']);
255
+ if (!allowed.has(eventType))
256
+ throw new StandardsProfileError('DATASET_STANDARD_UNSUPPORTED_CAPABILITY', `activity type ${activity.activityType} cannot be represented as an OpenLineage eventType`);
257
+ const document = { eventTime: activity.startedAt ?? activity.endedAt ?? snapshot.events[0]?.recordedAt, eventType, run: { runId: activity.runId }, job: splitOlId(activity.id), inputs, outputs, producer: 'https://aiwg.io' };
258
+ if (!document.eventTime)
259
+ invalid('DATASET_STANDARD_INVALID_OUTPUT', 'OpenLineage export requires an event timestamp');
260
+ validateDocument(validateOpenLineageDocument, document, 'output');
261
+ const items = [{ category: 'mapped', sourcePath: `/events/${snapshot.events.findIndex(item => item.record === activity)}`, targetPath: '/job', reason: 'activity/run mapped to OpenLineage job event' }];
262
+ for (const item of snapshot.events)
263
+ if (item.record.recordType !== 'activity' && item.record.recordType !== 'entity' && item.record.recordType !== 'assertion')
264
+ items.push({ category: 'unsupported', sourcePath: `/events/${item.sequence - 1}`, reason: `${item.record.recordType} is outside the declared OpenLineage profile` });
265
+ return exchange(OPENLINEAGE_PROFILE, 'export', snapshot, document, items);
266
+ }
267
+ export const DESCRIPTOR_ONLY_PROFILES = Object.freeze([
268
+ ['dcat', '3.0', 'catalog discovery'], ['croissant', '1.0', 'machine-learning dataset metadata'], ['data-package', '2.0', 'tabular data packaging'], ['ro-crate', '1.1', 'research object packaging'],
269
+ ].map(([standard, version, useCase]) => Object.freeze({ id: `${standard}/${version}`, standard: standard, version, direction: 'round-trip', inputSchema: { id: `https://aiwg.io/schemas/dataset/profiles/${standard}-${version}.schema.json`, version: '0.0.0' }, outputSchema: { id: `https://aiwg.io/schemas/dataset/profiles/${standard}-${version}.schema.json`, version: '0.0.0' }, mappingImplementation: 'unimplemented', supportedFeatures: [], roundTripFields: [], extensionNamespace: `${AIWG_EXTENSION_ROOT}${standard}/${version}/`, unknownExtensionPolicy: 'report', maturity: 'descriptor-only', useCases: [useCase], coverageBoundary: 'Descriptor only: no import, export, validation, or conformance capability is claimed.' })));
270
+ export const provAdapter = { descriptor: PROV_PROFILE, importDocument: importProv, exportDocument: exportProv };
271
+ export const openLineageAdapter = { descriptor: OPENLINEAGE_PROFILE, importDocument: importOpenLineage, exportDocument: exportOpenLineage };
272
+ const adapters = Object.freeze([provAdapter, openLineageAdapter]);
273
+ export const standardsProfiles = Object.freeze([...adapters.map(adapter => adapter.descriptor), ...DESCRIPTOR_ONLY_PROFILES]);
274
+ export function listStandardsProfiles() { return standardsProfiles; }
275
+ export function resolveStandardsProfile(standard, version, capability) {
276
+ const known = standardsProfiles.filter(profile => profile.standard === standard);
277
+ if (known.length === 0)
278
+ throw new StandardsProfileError('DATASET_STANDARD_PROFILE_NOT_FOUND', `unknown standard ${standard}`);
279
+ const profile = known.find(item => item.version === version);
280
+ if (!profile)
281
+ throw new StandardsProfileError('DATASET_STANDARD_UNSUPPORTED_VERSION', `${standard} version ${version} is not registered; exact version selection is required`);
282
+ const adapter = adapters.find(item => item.descriptor.id === profile.id);
283
+ if (!adapter || profile.maturity === 'descriptor-only')
284
+ throw new StandardsProfileError('DATASET_STANDARD_UNSUPPORTED_CAPABILITY', `${profile.id} is descriptor-only`);
285
+ if (capability && profile.direction !== 'round-trip' && profile.direction !== capability)
286
+ throw new StandardsProfileError('DATASET_STANDARD_UNSUPPORTED_CAPABILITY', `${profile.id} does not support ${capability}`);
287
+ return adapter;
288
+ }
289
+ export function importStandard(standard, version, document) { return resolveStandardsProfile(standard, version, 'import').importDocument(document); }
290
+ export function exportStandard(standard, version, snapshot) { return resolveStandardsProfile(standard, version, 'export').exportDocument(snapshot); }
291
+ //# sourceMappingURL=standards.js.map
@@ -0,0 +1,258 @@
1
+ export declare const DATASET_CONTRACT_VERSION: "aiwg.dataset/v1";
2
+ export type DatasetContractVersion = typeof DATASET_CONTRACT_VERSION;
3
+ export type PrivacyClassification = 'public' | 'internal' | 'confidential' | 'restricted';
4
+ export type ArtifactClass = 'canonical' | 'derived' | 'regenerable-index' | 'cache' | 'distribution' | 'portable-export';
5
+ export type LocalityPolicy = 'local-only' | 'approved-regions' | 'unrestricted';
6
+ export type NetworkPolicy = 'offline' | 'allowlisted' | 'online';
7
+ export type CapabilityRequirement = 'required' | 'optional';
8
+ export type DegradationAction = 'fail' | 'disable' | 'fallback';
9
+ export type LineageBasis = 'declared' | 'observed' | 'imported' | 'inferred';
10
+ export type RunOutcome = 'preview' | 'attempted' | 'committed' | 'rejected' | 'cancelled' | 'failed';
11
+ export interface ContractBase {
12
+ contractVersion: DatasetContractVersion;
13
+ id: string;
14
+ }
15
+ export interface Digest {
16
+ algorithm: 'sha256';
17
+ value: string;
18
+ }
19
+ export interface SchemaBinding {
20
+ id: string;
21
+ version: string;
22
+ digest?: Digest;
23
+ }
24
+ export interface PolicyBinding {
25
+ privacy: PrivacyClassification;
26
+ rights?: string;
27
+ license?: string;
28
+ retention?: {
29
+ policy: string;
30
+ expiresAt?: string;
31
+ };
32
+ intendedUse: string[];
33
+ locality: LocalityPolicy;
34
+ network: NetworkPolicy;
35
+ authorizationRefs: string[];
36
+ }
37
+ export interface DatasetSource extends ContractBase {
38
+ kind: 'DatasetSource';
39
+ sourceType: string;
40
+ locator: string;
41
+ policy: PolicyBinding;
42
+ schema?: SchemaBinding;
43
+ adapter: {
44
+ id: string;
45
+ version: string;
46
+ configDigest: Digest;
47
+ };
48
+ }
49
+ export interface Dataset extends ContractBase {
50
+ kind: 'Dataset';
51
+ artifactClass: 'canonical';
52
+ logicalId: string;
53
+ title: string;
54
+ description?: string;
55
+ owner: string;
56
+ policy: PolicyBinding;
57
+ }
58
+ export interface DatasetRevision extends ContractBase {
59
+ kind: 'DatasetRevision';
60
+ artifactClass: 'canonical';
61
+ datasetId: string;
62
+ revisionId: string;
63
+ manifestDigest: Digest;
64
+ contentDigest?: Digest;
65
+ sourceIds: string[];
66
+ createdAt: string;
67
+ schema?: SchemaBinding;
68
+ }
69
+ export interface Distribution extends ContractBase {
70
+ kind: 'Distribution';
71
+ datasetRevisionId: string;
72
+ artifactClass: 'distribution' | 'portable-export';
73
+ mediaType: string;
74
+ locator: string;
75
+ digest: Digest;
76
+ schema?: SchemaBinding;
77
+ }
78
+ export interface CapabilitySpec {
79
+ name: string;
80
+ requirement: CapabilityRequirement;
81
+ acceptedVersions?: string[];
82
+ degradation: {
83
+ action: DegradationAction;
84
+ fallbackCapability?: string;
85
+ reason?: string;
86
+ };
87
+ }
88
+ export interface CapabilityProfile extends ContractBase {
89
+ kind: 'CapabilityProfile';
90
+ capabilities: CapabilitySpec[];
91
+ }
92
+ export interface ProcessingStep {
93
+ id: string;
94
+ operation: string;
95
+ implementation: {
96
+ id: string;
97
+ version: string;
98
+ digest?: Digest;
99
+ };
100
+ inputSchema?: SchemaBinding;
101
+ outputSchema?: SchemaBinding;
102
+ configDigest: Digest;
103
+ }
104
+ export interface ProcessingPlan extends ContractBase {
105
+ kind: 'ProcessingPlan';
106
+ readonly datasetRevisionId: string;
107
+ readonly capabilityProfileId: string;
108
+ readonly steps: readonly ProcessingStep[];
109
+ readonly artifactClasses: readonly ArtifactClass[];
110
+ readonly createdBy: string;
111
+ readonly source: {
112
+ id: string;
113
+ revisionId: string;
114
+ identity: string;
115
+ };
116
+ readonly adapter: {
117
+ id: string;
118
+ version: string;
119
+ configDigest: Digest;
120
+ };
121
+ readonly schemas: readonly SchemaBinding[];
122
+ readonly capabilities: readonly CapabilitySpec[];
123
+ readonly capabilityDecision: CapabilityNegotiationReceipt;
124
+ readonly policy: PolicyBinding;
125
+ readonly execution: {
126
+ locality: 'local' | 'remote';
127
+ backend: string;
128
+ fallback?: string;
129
+ };
130
+ readonly estimates: {
131
+ reads: number;
132
+ writes: number;
133
+ bytes?: number;
134
+ cost?: number;
135
+ currency?: string;
136
+ };
137
+ readonly approvals: readonly {
138
+ id: string;
139
+ required: boolean;
140
+ reason: string;
141
+ threshold?: number;
142
+ }[];
143
+ readonly reconciliation?: {
144
+ tombstones: number;
145
+ previewDigest: Digest;
146
+ approvalThreshold: number;
147
+ };
148
+ readonly planDigest: Digest;
149
+ }
150
+ export interface ProcessingRun extends ContractBase {
151
+ kind: 'ProcessingRun';
152
+ runId: string;
153
+ planId: string;
154
+ planDigest: Digest;
155
+ attempt: number;
156
+ outcome: RunOutcome;
157
+ startedAt: string;
158
+ endedAt?: string;
159
+ executor: {
160
+ id: string;
161
+ version: string;
162
+ };
163
+ diagnosticCodes?: string[];
164
+ }
165
+ export interface DerivedArtifact extends ContractBase {
166
+ kind: 'DerivedArtifact';
167
+ artifactClass: Exclude<ArtifactClass, 'canonical'>;
168
+ sourceRevisionId: string;
169
+ runId: string;
170
+ locator: string;
171
+ digest: Digest;
172
+ schema?: SchemaBinding;
173
+ regenerable: boolean;
174
+ }
175
+ export interface EvidenceLocator {
176
+ locator: string;
177
+ method: string;
178
+ confidence: number;
179
+ privacy: PrivacyClassification;
180
+ }
181
+ export interface ProvenanceAssertion extends ContractBase {
182
+ kind: 'ProvenanceAssertion';
183
+ basis: LineageBasis;
184
+ subjectId: string;
185
+ predicate: string;
186
+ objectId: string;
187
+ sourceRevisionId?: string;
188
+ runId?: string;
189
+ evidence: EvidenceLocator[];
190
+ assertedBy: string;
191
+ assertedAt: string;
192
+ }
193
+ export interface Relationship extends ContractBase {
194
+ kind: 'Relationship';
195
+ relationshipType: string;
196
+ direction: 'outbound' | 'inbound';
197
+ sourceId: string;
198
+ targetId: string;
199
+ basis: LineageBasis;
200
+ sourceRevisionId?: string;
201
+ runId?: string;
202
+ evidence: EvidenceLocator[];
203
+ }
204
+ export interface Checkpoint extends ContractBase {
205
+ kind: 'Checkpoint';
206
+ sourceId: string;
207
+ sourceSchema: SchemaBinding;
208
+ adapter: {
209
+ id: string;
210
+ version: string;
211
+ };
212
+ planDigest: Digest;
213
+ opaqueCursor: string;
214
+ priorCommittedReceiptId?: string;
215
+ createdAt: string;
216
+ }
217
+ export interface RunReceipt extends ContractBase {
218
+ kind: 'RunReceipt';
219
+ runId: string;
220
+ planId: string;
221
+ planDigest: Digest;
222
+ outcome: RunOutcome;
223
+ committed: boolean;
224
+ attemptedRecords: number;
225
+ committedRecords: number;
226
+ rejectedRecords: number;
227
+ checkpointBeforeId?: string;
228
+ checkpointAfterId?: string;
229
+ priorCommittedReceiptId?: string;
230
+ receiptDigest: Digest;
231
+ createdAt: string;
232
+ diagnosticCodes?: string[];
233
+ }
234
+ export type DatasetContract = DatasetSource | Dataset | DatasetRevision | Distribution | CapabilityProfile | ProcessingPlan | ProcessingRun | DerivedArtifact | ProvenanceAssertion | Relationship | Checkpoint | RunReceipt;
235
+ export interface CapabilityNegotiationReceipt {
236
+ contractVersion: DatasetContractVersion;
237
+ satisfied: string[];
238
+ degraded: Array<{
239
+ capability: string;
240
+ action: Exclude<DegradationAction, 'fail'>;
241
+ fallbackCapability?: string;
242
+ }>;
243
+ }
244
+ export interface AvailableDatasetCapability {
245
+ name: string;
246
+ version: string;
247
+ }
248
+ export interface DatasetDiagnostic {
249
+ code: string;
250
+ message: string;
251
+ path?: string;
252
+ }
253
+ export interface DatasetValidationResult<T extends DatasetContract = DatasetContract> {
254
+ valid: boolean;
255
+ value?: T;
256
+ diagnostics: DatasetDiagnostic[];
257
+ }
258
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export const DATASET_CONTRACT_VERSION = 'aiwg.dataset/v1';
2
+ //# sourceMappingURL=types.js.map
@@ -1086,7 +1086,7 @@ export const outputModeCommand = {
1086
1086
  description: 'List, inspect, enable, disable, clear, and report composable output modes',
1087
1087
  version: '1.0.0',
1088
1088
  capabilities: ['cli', 'voice', 'output-mode', 'controlled-language', 'presentation'],
1089
- keywords: ['output-mode', 'voice', 'style', 'asd-ste', 'presentation'],
1089
+ keywords: ['output-mode', 'output-mask', 'voice', 'style', 'syntax', 'wittgenstein', 'asd-ste', 'engineering-language', 'controlled-language', 'presentation'],
1090
1090
  category: 'project',
1091
1091
  platforms: { claude: 'full', generic: 'full' },
1092
1092
  deployment: { pathTemplate: '.{platform}/commands/{id}.md', core: true },
@@ -1097,6 +1097,30 @@ export const outputModeCommand = {
1097
1097
  allowedTools: ['Read', 'Write'],
1098
1098
  },
1099
1099
  };
1100
+ export const schemaCommand = {
1101
+ id: 'schema',
1102
+ type: 'command',
1103
+ name: 'Schema Control Plane',
1104
+ description: 'Discover, validate, compare, and verify governed schema artifacts',
1105
+ version: '1.0.0',
1106
+ capabilities: ['cli', 'schema', 'catalog', 'validation', 'compatibility', 'projections'],
1107
+ keywords: ['schema', 'catalog', 'validate', 'lint', 'references', 'compatibility', 'projection', 'policy'],
1108
+ category: 'utility',
1109
+ platforms: { claude: 'full', generic: 'full' },
1110
+ deployment: { pathTemplate: '.{platform}/commands/{id}.md', core: true },
1111
+ metadata: {
1112
+ type: 'command',
1113
+ template: 'utility',
1114
+ argumentHint: '<list|show|graph|policy|validate|lint|check-refs|diff|compatibility|generate|verify-projections> [options]',
1115
+ allowedTools: ['Read', 'Write'],
1116
+ },
1117
+ };
1118
+ export const datasetCommand = {
1119
+ id: 'dataset', type: 'command', name: 'Dataset Intelligence', description: 'Register, preview, plan, ingest, verify, query, and trace governed datasets', version: '1.0.0',
1120
+ capabilities: ['cli', 'dataset', 'ingest', 'index', 'traceability', 'provenance'], keywords: ['dataset', 'source', 'preview', 'plan', 'ingest', 'verify', 'query', 'lineage', 'export'], category: 'index',
1121
+ platforms: { claude: 'full', generic: 'full' }, deployment: { pathTemplate: '.{platform}/commands/{id}.md', core: true },
1122
+ metadata: { type: 'command', template: 'utility', argumentHint: '<source|check|preview|plan|ingest|status|show|verify|query|lineage|export|cancel|retry> [options]', allowedTools: ['Read', 'Write'] },
1123
+ };
1100
1124
  // Session Catalog Command (#1903)
1101
1125
  export const sessionsCommand = {
1102
1126
  id: 'sessions',
@@ -3777,6 +3801,8 @@ export const commandDefinitions = [
3777
3801
  sessionCommand,
3778
3802
  sessionsCommand,
3779
3803
  outputModeCommand,
3804
+ schemaCommand,
3805
+ datasetCommand,
3780
3806
  ];
3781
3807
  // ============================================
3782
3808
  // Helper Functions
@@ -151,7 +151,7 @@ export function loadInstallationIdentity(options = {}) {
151
151
  throw wrapped;
152
152
  }
153
153
  }
154
- if (options.createIfMissing === false) return null;
154
+ if (options.createIfMissing === false || process.env.AIWG_CLI_DRY_RUN === '1') return null;
155
155
  if (!options.actualRoot) return null;
156
156
 
157
157
  const legacy = options.legacyConfig ?? readLegacy(options) ?? {};
@@ -232,6 +232,10 @@ export function formatInstallationDiagnostic(status) {
232
232
 
233
233
  export function assertCanonicalInstallation(options = {}) {
234
234
  const status = inspectInstallation(options);
235
+ // A strict dry-run may inspect an installation that has not yet recorded
236
+ // identity, but must not create installation.json merely to authorize a
237
+ // read-only preview. Callers must opt into this narrow exception.
238
+ if (options.allowUnrecorded === true && status.state === 'unrecorded') return status;
235
239
  if (status.state !== 'aligned') {
236
240
  const error = new Error(formatInstallationDiagnostic(status));
237
241
  error.code = 'AIWG_INSTALLATION_DRIFT';
@@ -76,6 +76,17 @@
76
76
  "verification": "Inspect active profile and run metadata",
77
77
  "sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions", "verifiedAt": "2026-07-20"
78
78
  },
79
+ "pi": {
80
+ "agent": "native", "skill": "inherited", "globalChild": "native",
81
+ "identifierSyntax": "provider/model identifier accepted by Pi --model",
82
+ "effortValues": ["minimal", "low", "medium", "high", "xhigh"],
83
+ "inheritance": "Omitted model and thinking level inherit the invoking Pi session",
84
+ "invalidPinFallback": "Pi resolves against its configured catalog and exits on invalid explicit selection",
85
+ "configTarget": "Pi headless launch arguments",
86
+ "artifactFormat": "Runtime --model and --thinking flags",
87
+ "verification": "Inspect strict JSONL state and the selected provider/model",
88
+ "sourceUrl": "https://github.com/earendil-works/pi/tree/main/packages/coding-agent#cli-reference", "verifiedAt": "2026-09-04"
89
+ },
79
90
  "windsurf": {
80
91
  "agent": "unsupported", "skill": "unsupported", "globalChild": "inherited",
81
92
  "identifierSyntax": "UI-selected provider model",